12 #include "../stdafx.h" 13 #include "../openttd.h" 14 #include "../gfx_func.h" 15 #include "../os/windows/win32.h" 17 #include "../blitter/factory.hpp" 18 #include "../network/network.h" 19 #include "../core/math_func.hpp" 20 #include "../core/random_func.hpp" 21 #include "../texteff.hpp" 22 #include "../thread.h" 23 #include "../progress.h" 24 #include "../window_gui.h" 25 #include "../window_func.h" 26 #include "../framerate_type.h" 31 #include <condition_variable> 34 #include "../safeguards.h" 37 #ifndef MAPVK_VK_TO_CHAR 38 #define MAPVK_VK_TO_CHAR (2) 42 #define PM_QS_INPUT 0x20000 45 typedef BOOL (WINAPI *PFNTRACKMOUSEEVENT)(LPTRACKMOUSEEVENT lpEventTrack);
46 static PFNTRACKMOUSEEVENT _pTrackMouseEvent =
nullptr;
63 bool _force_full_redraw;
64 bool _window_maximize;
80 static void MakePalette()
82 LOGPALETTE *pal = (LOGPALETTE*)alloca(
sizeof(LOGPALETTE) + (256 - 1) *
sizeof(PALETTEENTRY));
84 pal->palVersion = 0x300;
85 pal->palNumEntries = 256;
87 for (uint i = 0; i != 256; i++) {
91 pal->palPalEntry[i].peFlags = 0;
94 _wnd.gdi_palette = CreatePalette(pal);
95 if (_wnd.gdi_palette ==
nullptr)
usererror(
"CreatePalette failed!\n");
102 static void UpdatePalette(HDC dc, uint start, uint count)
107 for (i = 0; i != count; i++) {
108 rgb[i].rgbRed = _local_palette.
palette[start + i].r;
109 rgb[i].rgbGreen = _local_palette.
palette[start + i].g;
110 rgb[i].rgbBlue = _local_palette.
palette[start + i].b;
111 rgb[i].rgbReserved = 0;
114 SetDIBColorTable(dc, start, count, rgb);
117 bool VideoDriver_Win32::ClaimMousePointer()
119 MyShowCursor(
false,
true);
129 #define AS(x, z) {x, 0, z} 130 #define AM(x, y, z, w) {x, y - x, z} 134 AM(VK_PRIOR, VK_DOWN, WKC_PAGEUP, WKC_DOWN),
136 AM(
'A',
'Z',
'A',
'Z'),
137 AM(
'0',
'9',
'0',
'9'),
139 AS(VK_ESCAPE, WKC_ESC),
140 AS(VK_PAUSE, WKC_PAUSE),
141 AS(VK_BACK, WKC_BACKSPACE),
142 AM(VK_INSERT, VK_DELETE, WKC_INSERT, WKC_DELETE),
144 AS(VK_SPACE, WKC_SPACE),
145 AS(VK_RETURN, WKC_RETURN),
149 AM(VK_F1, VK_F12, WKC_F1, WKC_F12),
152 AM(VK_NUMPAD0, VK_NUMPAD9,
'0',
'9'),
153 AS(VK_DIVIDE, WKC_NUM_DIV),
154 AS(VK_MULTIPLY, WKC_NUM_MUL),
155 AS(VK_SUBTRACT, WKC_NUM_MINUS),
156 AS(VK_ADD, WKC_NUM_PLUS),
157 AS(VK_DECIMAL, WKC_NUM_DECIMAL),
173 static uint MapWindowsKey(uint sym)
178 for (map = _vk_mapping; map !=
endof(_vk_mapping); ++map) {
179 if ((uint)(sym - map->vk_from) <= map->vk_count) {
180 key = sym - map->vk_from + map->map_to;
185 if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT;
186 if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
187 if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT;
191 static bool AllocateDibSection(
int w,
int h,
bool force =
false);
193 static void ClientSizeChanged(
int w,
int h)
196 if (AllocateDibSection(w, h)) {
211 int RedrawScreenDebug()
216 HPALETTE old_palette;
220 dc = GetDC(_wnd.main_wnd);
221 dc2 = CreateCompatibleDC(dc);
223 old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect);
224 old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
225 BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
226 SelectPalette(dc, old_palette, TRUE);
227 SelectObject(dc2, old_bmp);
229 ReleaseDC(_wnd.main_wnd, dc);
236 #if !defined(WM_MOUSELEAVE) 237 #define WM_MOUSELEAVE 0x02A3 239 #define TID_POLLMOUSE 1 240 #define MOUSE_POLL_DELAY 75 242 static void CALLBACK TrackMouseTimerProc(HWND hwnd, UINT msg, UINT_PTR event, DWORD time)
250 GetClientRect(hwnd, &rc);
251 MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)(LPRECT)&rc, 2);
254 if (!PtInRect(&rc, pt) || (WindowFromPoint(pt) != hwnd)) {
255 KillTimer(hwnd, event);
256 PostMessage(hwnd, WM_MOUSELEAVE, 0, 0L);
267 _fullscreen = full_screen;
270 if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) {
271 DestroyWindow(_wnd.main_wnd);
278 memset(&settings, 0,
sizeof(settings));
284 (_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0);
286 settings.dmPelsWidth = _wnd.width_org;
287 settings.dmPelsHeight = _wnd.height_org;
288 settings.dmDisplayFrequency = _display_hz;
291 if (settings.dmBitsPerPel == 8 &&
292 (_support8bpp !=
S8BPP_HARDWARE || ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)) {
293 settings.dmBitsPerPel = 32;
297 if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
299 GetWindowRect(GetDesktopWindow(), &r);
302 if ((
int)settings.dmPelsWidth != r.right - r.left || (
int)settings.dmPelsHeight != r.bottom - r.top) {
307 if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
311 }
else if (_wnd.fullscreen) {
313 ChangeDisplaySettings(
nullptr, 0);
315 _wnd.width = _bck_resolution.width;
316 _wnd.height = _bck_resolution.height;
321 DWORD style, showstyle;
324 showstyle = SW_SHOWNORMAL;
325 _wnd.fullscreen = full_screen;
326 if (_wnd.fullscreen) {
328 SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
330 style = WS_OVERLAPPEDWINDOW;
332 if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
333 SetRect(&r, 0, 0, _wnd.width, _wnd.height);
336 AdjustWindowRect(&r, style, FALSE);
337 w = r.right - r.left;
338 h = r.bottom - r.top;
340 if (_wnd.main_wnd !=
nullptr) {
341 if (!_window_maximize) SetWindowPos(_wnd.main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
343 int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
344 int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
346 char window_title[64];
347 seprintf(window_title,
lastof(window_title),
"OpenTTD %s", _openttd_revision);
349 _wnd.main_wnd = CreateWindow(_T(
"OTTD"), MB_TO_WIDE(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(
nullptr), 0);
350 if (_wnd.main_wnd ==
nullptr)
usererror(
"CreateWindow failed");
351 ShowWindow(_wnd.main_wnd, showstyle);
366 HDC dc2 = CreateCompatibleDC(dc);
367 HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect);
368 HPALETTE old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
391 BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
392 SelectPalette(dc, old_palette, TRUE);
393 SelectObject(dc2, old_bmp);
397 static void PaintWindowThread()
409 ClientToScreen(_wnd.main_wnd, &pt);
410 OffsetRect(&_wnd.update_rect, pt.x, pt.y);
414 HRGN rgn = CreateRectRgnIndirect(&_wnd.update_rect);
415 HDC dc = GetDCEx(_wnd.main_wnd, rgn, DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_INTERSECTRGN);
420 SetRectEmpty(&_wnd.update_rect);
421 ReleaseDC(_wnd.main_wnd, dc);
433 #if !defined(UNICODE) 434 static char prev_char = 0;
436 char input[2] = {(char)charcode, 0};
439 if (prev_char != 0) {
441 input[0] = prev_char;
442 input[1] = (char)charcode;
444 }
else if (IsDBCSLeadByte(charcode)) {
446 prev_char = charcode;
452 int len = MultiByteToWideChar(CP_ACP, 0, input, input_len, w, 2);
463 DEBUG(driver, 1,
"Invalid DBCS character sequence encountered, dropping input");
468 static WChar prev_char = 0;
472 if (prev_char != 0)
DEBUG(driver, 1,
"Got two UTF-16 lead surrogates, dropping the first one");
473 prev_char = charcode;
478 if (prev_char != 0) {
482 DEBUG(driver, 1,
"Got an UTF-16 lead surrogate without a trail surrogate, dropping the lead surrogate");
496 return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI);
502 HIMC hIMC = ImmGetContext(hwnd);
505 cf.dwStyle = CFS_POINT;
510 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
511 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
513 cf.ptCurrentPos.x = 0;
514 cf.ptCurrentPos.y = 0;
516 ImmSetCompositionWindow(hIMC, &cf);
518 ImmReleaseContext(hwnd, hIMC);
524 HIMC hIMC = ImmGetContext(hwnd);
528 cf.dwStyle = CFS_EXCLUDE;
532 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
533 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
535 cf.rcArea.left = _focused_window->
left;
536 cf.rcArea.top = _focused_window->
top;
537 cf.rcArea.right = _focused_window->
left + _focused_window->
width;
538 cf.rcArea.bottom = _focused_window->
top + _focused_window->
height;
546 cf.ptCurrentPos.x = 0;
547 cf.ptCurrentPos.y = 0;
548 SetRectEmpty(&cf.rcArea);
550 ImmSetCandidateWindow(hIMC, &cf);
552 ImmReleaseContext(hwnd, hIMC);
558 HIMC hIMC = ImmGetContext(hwnd);
561 if (lParam & GCS_RESULTSTR) {
563 LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR,
nullptr, 0);
564 TCHAR *str = (TCHAR *)_alloca(len +
sizeof(TCHAR));
565 len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str, len);
566 str[len /
sizeof(TCHAR)] =
'\0';
576 lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR);
581 LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR,
nullptr, 0);
582 TCHAR *str = (TCHAR *)_alloca(len +
sizeof(TCHAR));
583 len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str, len);
584 str[len /
sizeof(TCHAR)] =
'\0';
587 static char utf8_buf[1024];
591 LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS,
nullptr, 0);
592 const char *caret = utf8_buf;
593 for (
const TCHAR *c = str; *c !=
'\0' && *caret !=
'\0' && caret_bytes > 0; c++, caret_bytes--) {
598 if (IsDBCSLeadByte(*c)) {
611 lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART);
614 ImmReleaseContext(hwnd, hIMC);
616 return lParam != 0 ? DefWindowProc(hwnd, WM_IME_COMPOSITION, wParam, lParam) : 0;
622 HIMC hIMC = ImmGetContext(hwnd);
623 if (hIMC != NULL) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
624 ImmReleaseContext(hwnd, hIMC);
629 static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
631 static uint32 keycode = 0;
632 static bool console =
false;
633 static bool in_sizemove =
false;
637 SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, TrackMouseTimerProc);
642 case WM_ENTERSIZEMOVE:
646 case WM_EXITSIZEMOVE:
654 GetUpdateRect(hwnd, &r, FALSE);
655 UnionRect(&_wnd.update_rect, &_wnd.update_rect, &r);
658 ValidateRect(hwnd,
nullptr);
663 BeginPaint(hwnd, &ps);
669 case WM_PALETTECHANGED:
670 if ((HWND)wParam == hwnd)
return 0;
673 case WM_QUERYNEWPALETTE: {
674 HDC hDC = GetWindowDC(hwnd);
675 HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE);
676 UINT nChanged = RealizePalette(hDC);
678 SelectPalette(hDC, hOldPalette, TRUE);
679 ReleaseDC(hwnd, hDC);
680 if (nChanged != 0) InvalidateRect(hwnd,
nullptr, FALSE);
685 HandleExitGameRequest();
726 int x = (int16)LOWORD(lParam);
727 int y = (int16)HIWORD(lParam);
734 if (_pTrackMouseEvent !=
nullptr) {
736 tme.cbSize =
sizeof(tme);
737 tme.dwFlags = TME_LEAVE;
738 tme.hwndTrack = hwnd;
740 _pTrackMouseEvent(&tme);
742 SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, TrackMouseTimerProc);
750 while (PeekMessage(&m, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE | PM_NOYIELD | PM_QS_INPUT)) {
751 x = (int16)LOWORD(m.lParam);
752 y = (int16)HIWORD(m.lParam);
758 pt.x = _cursor.
pos.x;
759 pt.y = _cursor.
pos.y;
760 ClientToScreen(hwnd, &pt);
761 SetCursorPos(pt.x, pt.y);
768 case WM_INPUTLANGCHANGE:
772 case WM_IME_SETCONTEXT:
777 case WM_IME_STARTCOMPOSITION:
782 case WM_IME_COMPOSITION:
785 case WM_IME_ENDCOMPOSITION:
795 #if !defined(UNICODE) 797 if (
GB(wParam, 8, 8) != 0) {
806 console =
GB(lParam, 16, 8) == 41;
810 uint scancode =
GB(lParam, 16, 8);
811 uint charcode = wParam;
815 if (console && scancode == 41) {
822 uint cur_keycode = keycode;
830 uint scancode =
GB(lParam, 16, 8);
831 keycode = scancode == 41 ? (uint)WKC_BACKQUOTE : MapWindowsKey(wParam);
835 if (PeekMessage(&msg,
nullptr, 0, 0, PM_NOREMOVE)) {
836 if ((msg.message == WM_CHAR || msg.message == WM_DEADCHAR) &&
GB(lParam, 16, 8) ==
GB(msg.lParam, 16, 8)) {
841 uint charcode = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR);
850 if (
HasBit(charcode, 31) && !console) {
851 if (scancode == 41) {
860 uint cur_keycode = keycode;
870 ToggleFullScreen(!_wnd.fullscreen);
887 if (wParam != SIZE_MINIMIZED) {
890 _window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
891 if (_window_maximize || _fullscreen) _bck_resolution =
_cur_resolution;
892 ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
897 RECT *r = (RECT*)lParam;
901 SetRect(&r2, 0, 0, 0, 0);
902 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
904 w = r->right - r->left - (r2.right - r2.left);
905 h = r->bottom - r->top - (r2.bottom - r2.top);
908 SetRect(&r2, 0, 0, w, h);
910 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
911 w = r2.right - r2.left;
912 h = r2.bottom - r2.top;
916 r->bottom = r->top + h;
919 case WMSZ_BOTTOMLEFT:
920 r->bottom = r->top + h;
921 r->left = r->right - w;
924 case WMSZ_BOTTOMRIGHT:
925 r->bottom = r->top + h;
926 r->right = r->left + w;
930 r->left = r->right - w;
934 r->right = r->left + w;
938 r->top = r->bottom - h;
942 r->top = r->bottom - h;
943 r->left = r->right - w;
947 r->top = r->bottom - h;
948 r->right = r->left + w;
955 #if !defined(WM_MOUSEWHEEL) 956 # define WM_MOUSEWHEEL 0x020A 958 #if !defined(GET_WHEEL_DELTA_WPARAM) 959 # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam)) 962 case WM_MOUSEWHEEL: {
963 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
967 }
else if (delta > 0) {
975 _wnd.has_focus =
true;
980 _wnd.has_focus =
false;
985 if (_exit_game)
break;
987 bool active = (LOWORD(wParam) != WA_INACTIVE);
988 bool minimized = (HIWORD(wParam) != 0);
989 if (_wnd.fullscreen) {
990 if (active && minimized) {
992 ShowWindow(hwnd, SW_RESTORE);
994 }
else if (!active && !minimized) {
996 ShowWindow(hwnd, SW_MINIMIZE);
997 ChangeDisplaySettings(
nullptr, 0);
1004 return DefWindowProc(hwnd, msg, wParam, lParam);
1007 static void RegisterWndClass()
1009 static bool registered =
false;
1012 HINSTANCE hinst = GetModuleHandle(
nullptr);
1019 LoadIcon(hinst, MAKEINTRESOURCE(100)),
1020 LoadCursor(
nullptr, IDC_ARROW),
1027 if (!RegisterClass(&wnd))
usererror(
"RegisterClass failed");
1030 _pTrackMouseEvent = (PFNTRACKMOUSEEVENT)GetProcAddress(GetModuleHandle(_T(
"User32")),
"TrackMouseEvent");
1034 static bool AllocateDibSection(
int w,
int h,
bool force)
1043 if (bpp == 0)
usererror(
"Can't use a blitter that blits 0 bpp for normal visuals");
1045 if (!force && w == _screen.width && h == _screen.height)
return false;
1047 bi = (BITMAPINFO*)alloca(
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * 256);
1048 memset(bi, 0,
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * 256);
1049 bi->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
1051 bi->bmiHeader.biWidth = _wnd.width = w;
1052 bi->bmiHeader.biHeight = -(_wnd.height = h);
1054 bi->bmiHeader.biPlanes = 1;
1056 bi->bmiHeader.biCompression = BI_RGB;
1058 if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
1061 _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits,
nullptr, 0);
1062 if (_wnd.dib_sect ==
nullptr)
usererror(
"CreateDIBSection failed");
1066 _screen.pitch = (bpp == 8) ?
Align(w, 4) : w;
1068 _screen.dst_ptr = _wnd.buffer_bits;
1073 static const Dimension default_resolutions[] = {
1087 static void FindResolutions()
1100 for (i = 0; EnumDisplaySettingsA(
nullptr, i, &dm) != 0; i++) {
1101 if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480)
continue;
1103 _resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight);
1108 _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
1118 memset(&_wnd, 0,
sizeof(_wnd));
1144 DeleteObject(_wnd.gdi_palette);
1145 DeleteObject(_wnd.dib_sect);
1146 DestroyWindow(_wnd.main_wnd);
1148 if (_wnd.fullscreen) ChangeDisplaySettings(
nullptr, 0);
1154 RECT r = { left, top, left + width, top + height };
1156 InvalidateRect(_wnd.main_wnd, &r, FALSE);
1159 static void CheckPaletteAnim()
1164 InvalidateRect(_wnd.main_wnd,
nullptr, FALSE);
1170 uint32 cur_ticks = GetTickCount();
1171 uint32 last_cur_ticks = cur_ticks;
1174 std::thread draw_thread;
1175 std::unique_lock<std::recursive_mutex> draw_lock;
1188 draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
1196 draw_lock.release();
1199 _draw_mutex =
nullptr;
1202 DEBUG(driver, 1,
"Threaded drawing enabled");
1209 _wnd.running =
true;
1213 uint32 prev_cur_ticks = cur_ticks;
1215 while (PeekMessage(&mesg,
nullptr, 0, 0, PM_REMOVE)) {
1216 InteractiveRandom();
1219 DispatchMessage(&mesg);
1221 if (_exit_game)
break;
1224 if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 &&
1227 if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0 && GetAsyncKeyState(VK_MENU) >= 0 &&
1231 }
else if (_fast_forward & 2) {
1235 cur_ticks = GetTickCount();
1236 if (cur_ticks >= next_tick || (_fast_forward && !
_pause_mode) || cur_ticks < prev_cur_ticks) {
1238 last_cur_ticks = cur_ticks;
1243 _ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0;
1247 if (_wnd.has_focus) {
1249 (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
1250 (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
1251 (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
1252 (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
1291 if (draw_lock.owns_lock()) draw_lock.unlock();
1292 draw_lock.release();
1304 std::unique_lock<std::recursive_mutex>
lock;
1305 if (
_draw_mutex !=
nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
1307 if (_window_maximize) ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL);
1309 _wnd.width = _wnd.width_org = w;
1310 _wnd.height = _wnd.height_org = h;
1317 std::unique_lock<std::recursive_mutex>
lock;
1318 if (
_draw_mutex !=
nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
1325 return AllocateDibSection(_screen.width, _screen.height,
true) && this->
MakeWindow(_fullscreen);
1340 std::unique_lock<std::recursive_mutex>
lock;
1341 if (
_draw_mutex !=
nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
static LRESULT HandleCharMsg(uint keycode, WChar charcode)
Forward key presses to the window system.
const char * GetDriverParam(const char *const *parm, const char *name)
Get a string parameter the list of parameters.
static bool _draw_threaded
Whether the drawing is/may be done in a separate thread.
bool _networking
are we in networking mode?
uint32 _realtime_tick
The real time in the game.
const NWidgetCore * nested_focus
Currently focused nested widget, or nullptr if no nested widget has focus.
Point pos
logical mouse position
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD's encoding from that of the local environment.
Information about the currently used palette.
int left
x position of left edge of the window
void MainLoop() override
Perform the actual drawing.
The factory for Windows' video driver.
void EditBoxLostFocus() override
An edit box lost the input focus.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
void Stop() override
Stop this driver.
bool _right_button_down
Is right mouse button pressed?
Colour palette[256]
Current palette. Entry 0 has to be always fully transparent!
fluid_settings_t * settings
FluidSynth settings handle.
static std::recursive_mutex * _draw_mutex
Mutex to keep the access to the shared memory controlled.
int top
y position of top edge of the window
Dimension _cur_resolution
The current resolution.
static volatile bool _draw_continue
Should we keep continue drawing?
#define lastof(x)
Get the last element of an fixed size array.
How all blitters should look like.
char * convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
Convert to OpenTTD's encoding from that of the environment in UNICODE.
static T max(const T a, const T b)
Returns the maximum of two values.
virtual void PostResize()
Post resize event.
void AcquireBlitterLock() override
Acquire any lock(s) required to be held when changing blitters.
Palette animation should be done by video backend (8bpp only!)
bool _left_button_clicked
Is left mouse button clicked?
void ReleaseBlitterLock() override
Release any lock(s) required to be held when changing blitters.
std::vector< Dimension > _resolutions
List of resolutions.
bool _ctrl_pressed
Is Ctrl pressed?
bool StartNewThread(std::thread *thr, const char *name, TFn &&_Fx, TArgs &&... _Ax)
Start a new thread.
const char * Start(const char *const *param) override
Start this driver.
bool _right_button_clicked
Is right mouse button clicked?
static T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
The blitter takes care of the palette animation.
virtual void PaletteAnimate(const Palette &palette)=0
Called when the 8bpp palette is changed; you should redraw all pixels on the screen that are equal to...
bool _left_button_down
Is left mouse button pressed?
std::mutex lock
synchronization for playback status fields
void GetKeyboardLayout()
Retrieve keyboard layout from language string or (if set) config file.
static bool DrawIMECompositionString()
Should we draw the composition string ourself, i.e is this a normal IME?
void CDECL usererror(const char *s,...)
Error handling for fatal user errors.
int wheel
mouse wheel movement
bool UpdateCursorPosition(int x, int y, bool queued_warp)
Update cursor position on mouse movement.
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
void HandleKeypress(uint keycode, WChar key)
Handle keyboard input.
byte _dirkeys
1 = left, 2 = up, 4 = right, 8 = down
bool fix_at
mouse is moving, but cursor is not (used for scrolling)
bool ToggleFullscreen(bool fullscreen) override
Change the full screen setting.
void HandleMouseEvents()
Handle a mouse event from the video driver.
#define lengthof(x)
Return the length of an fixed size array.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
int first_dirty
The first dirty element.
PauseMode _pause_mode
The current pause mode.
bool ChangeResolution(int w, int h) override
Change the resolution of the window.
static WChar Utf16DecodeSurrogate(uint lead, uint trail)
Convert an UTF-16 surrogate pair to the corresponding Unicode character.
Palette _cur_palette
Current palette.
bool _shift_pressed
Is Shift pressed?
#define DEBUG(name, level,...)
Output a line of debugging information.
virtual Blitter::PaletteAnimation UsePaletteAnimation()=0
Check if the blitter uses palette animation at all.
static void PaintWindow(HDC dc)
Do palette animation and blit to the window.
The video driver for windows.
static bool Utf16IsTrailSurrogate(uint c)
Is the given character a lead surrogate code point?
void HandleCtrlChanged()
State of CONTROL key has changed.
bool EditBoxInGlobalFocus()
Check if an edit box is in global focus.
Base of the Windows video driver.
Speed of painting drawn video buffer.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam)
Handle WM_IME_COMPOSITION messages.
static void SetCandidatePos(HWND hwnd)
Set the position of the candidate window.
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
void MakeDirty(int left, int top, int width, int height) override
Mark a particular area dirty.
void NetworkDrawChatMessage()
Draw the chat message-box.
static Palette _local_palette
Local copy of the palette for use in the drawing thread.
#define endof(x)
Get the end element of an fixed size array.
bool in_window
mouse inside this window, determines drawing logic
bool MakeWindow(bool full_screen)
Instantiate a new window.
Coordinates of a point in 2D.
virtual uint8 GetScreenDepth()=0
Get the screen depth this blitter works for.
#define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview)
AirportSpec definition for airports with at least one depot.
static bool Utf16IsLeadSurrogate(uint c)
Is the given character a lead surrogate code point?
void GameSizeChanged()
Size of the application screen changed.
int width
width of the window (number of pixels to the right in x direction)
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
void HandleTextInput(const char *str, bool marked=false, const char *caret=nullptr, const char *insert_location=nullptr, const char *replacement_end=nullptr)
Handle text input.
static std::condition_variable_any * _draw_signal
Signal to draw the next frame.
WindowClass window_class
Window class.
bool AfterBlitterChange() override
Callback invoked after the blitter was changed.
int count_dirty
The number of dirty elements.
static void CancelIMEComposition(HWND hwnd)
Clear the current composition string.
virtual Point GetCaretPosition() const
Get the current caret position if an edit box has the focus.
uint32 WChar
Type for wide characters, i.e.
static void SetCompositionPos(HWND hwnd)
Set position of the composition window to the caret position.
Dimensions (a width and height) of a rectangle in 2D.
Full 8bpp support by OS and hardware.
static bool HasModalProgress()
Check if we are currently in a modal progress state.
int height
Height of the window (number of pixels down in y direction)
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
void UpdateWindows()
Update the continuously changing contents of the windows, such as the viewports.