10 #include "../stdafx.h" 11 #include "../openttd.h" 12 #include "../gfx_func.h" 13 #include "../os/windows/win32.h" 15 #include "../blitter/factory.hpp" 16 #include "../network/network.h" 17 #include "../core/math_func.hpp" 18 #include "../core/random_func.hpp" 19 #include "../texteff.hpp" 20 #include "../thread.h" 21 #include "../progress.h" 22 #include "../window_gui.h" 23 #include "../window_func.h" 24 #include "../framerate_type.h" 29 #include <condition_variable> 32 #include "../safeguards.h" 35 #ifndef MAPVK_VK_TO_CHAR 36 #define MAPVK_VK_TO_CHAR (2) 40 #define PM_QS_INPUT 0x20000 43 typedef BOOL (WINAPI *PFNTRACKMOUSEEVENT)(LPTRACKMOUSEEVENT lpEventTrack);
44 static PFNTRACKMOUSEEVENT _pTrackMouseEvent =
nullptr;
61 bool _force_full_redraw;
62 bool _window_maximize;
78 static void MakePalette()
80 LOGPALETTE *pal = (LOGPALETTE*)alloca(
sizeof(LOGPALETTE) + (256 - 1) *
sizeof(PALETTEENTRY));
82 pal->palVersion = 0x300;
83 pal->palNumEntries = 256;
85 for (uint i = 0; i != 256; i++) {
89 pal->palPalEntry[i].peFlags = 0;
92 _wnd.gdi_palette = CreatePalette(pal);
93 if (_wnd.gdi_palette ==
nullptr)
usererror(
"CreatePalette failed!\n");
100 static void UpdatePalette(HDC dc, uint start, uint count)
105 for (i = 0; i != count; i++) {
106 rgb[i].rgbRed = _local_palette.
palette[start + i].r;
107 rgb[i].rgbGreen = _local_palette.
palette[start + i].g;
108 rgb[i].rgbBlue = _local_palette.
palette[start + i].b;
109 rgb[i].rgbReserved = 0;
112 SetDIBColorTable(dc, start, count, rgb);
115 bool VideoDriver_Win32::ClaimMousePointer()
117 MyShowCursor(
false,
true);
127 #define AS(x, z) {x, 0, z} 128 #define AM(x, y, z, w) {x, y - x, z} 132 AM(VK_PRIOR, VK_DOWN, WKC_PAGEUP, WKC_DOWN),
134 AM(
'A',
'Z',
'A',
'Z'),
135 AM(
'0',
'9',
'0',
'9'),
137 AS(VK_ESCAPE, WKC_ESC),
138 AS(VK_PAUSE, WKC_PAUSE),
139 AS(VK_BACK, WKC_BACKSPACE),
140 AM(VK_INSERT, VK_DELETE, WKC_INSERT, WKC_DELETE),
142 AS(VK_SPACE, WKC_SPACE),
143 AS(VK_RETURN, WKC_RETURN),
147 AM(VK_F1, VK_F12, WKC_F1, WKC_F12),
150 AM(VK_NUMPAD0, VK_NUMPAD9,
'0',
'9'),
151 AS(VK_DIVIDE, WKC_NUM_DIV),
152 AS(VK_MULTIPLY, WKC_NUM_MUL),
153 AS(VK_SUBTRACT, WKC_NUM_MINUS),
154 AS(VK_ADD, WKC_NUM_PLUS),
155 AS(VK_DECIMAL, WKC_NUM_DECIMAL),
171 static uint MapWindowsKey(uint sym)
176 for (map = _vk_mapping; map !=
endof(_vk_mapping); ++map) {
177 if ((uint)(sym - map->vk_from) <= map->vk_count) {
178 key = sym - map->vk_from + map->map_to;
183 if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT;
184 if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL;
185 if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT;
189 static bool AllocateDibSection(
int w,
int h,
bool force =
false);
191 static void ClientSizeChanged(
int w,
int h)
194 if (AllocateDibSection(w, h)) {
209 int RedrawScreenDebug()
214 HPALETTE old_palette;
218 dc = GetDC(_wnd.main_wnd);
219 dc2 = CreateCompatibleDC(dc);
221 old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect);
222 old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
223 BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
224 SelectPalette(dc, old_palette, TRUE);
225 SelectObject(dc2, old_bmp);
227 ReleaseDC(_wnd.main_wnd, dc);
234 #if !defined(WM_MOUSELEAVE) 235 #define WM_MOUSELEAVE 0x02A3 237 #define TID_POLLMOUSE 1 238 #define MOUSE_POLL_DELAY 75 240 static void CALLBACK TrackMouseTimerProc(HWND hwnd, UINT msg, UINT_PTR event, DWORD time)
248 GetClientRect(hwnd, &rc);
249 MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)(LPRECT)&rc, 2);
252 if (!PtInRect(&rc, pt) || (WindowFromPoint(pt) != hwnd)) {
253 KillTimer(hwnd, event);
254 PostMessage(hwnd, WM_MOUSELEAVE, 0, 0L);
265 _fullscreen = full_screen;
268 if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) {
269 DestroyWindow(_wnd.main_wnd);
276 memset(&settings, 0,
sizeof(settings));
282 (_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0);
284 settings.dmPelsWidth = _wnd.width_org;
285 settings.dmPelsHeight = _wnd.height_org;
286 settings.dmDisplayFrequency = _display_hz;
289 if (settings.dmBitsPerPel == 8 &&
290 (_support8bpp !=
S8BPP_HARDWARE || ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)) {
291 settings.dmBitsPerPel = 32;
295 if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
297 GetWindowRect(GetDesktopWindow(), &r);
300 if ((
int)settings.dmPelsWidth != r.right - r.left || (
int)settings.dmPelsHeight != r.bottom - r.top) {
305 if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
309 }
else if (_wnd.fullscreen) {
311 ChangeDisplaySettings(
nullptr, 0);
313 _wnd.width = _bck_resolution.width;
314 _wnd.height = _bck_resolution.height;
319 DWORD style, showstyle;
322 showstyle = SW_SHOWNORMAL;
323 _wnd.fullscreen = full_screen;
324 if (_wnd.fullscreen) {
326 SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
328 style = WS_OVERLAPPEDWINDOW;
330 if (_window_maximize) showstyle = SW_SHOWMAXIMIZED;
331 SetRect(&r, 0, 0, _wnd.width, _wnd.height);
334 AdjustWindowRect(&r, style, FALSE);
335 w = r.right - r.left;
336 h = r.bottom - r.top;
338 if (_wnd.main_wnd !=
nullptr) {
339 if (!_window_maximize) SetWindowPos(_wnd.main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
341 int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
342 int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
344 char window_title[64];
345 seprintf(window_title,
lastof(window_title),
"OpenTTD %s", _openttd_revision);
347 _wnd.main_wnd = CreateWindow(_T(
"OTTD"), MB_TO_WIDE(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(
nullptr), 0);
348 if (_wnd.main_wnd ==
nullptr)
usererror(
"CreateWindow failed");
349 ShowWindow(_wnd.main_wnd, showstyle);
364 HDC dc2 = CreateCompatibleDC(dc);
365 HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect);
366 HPALETTE old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
389 BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
390 SelectPalette(dc, old_palette, TRUE);
391 SelectObject(dc2, old_bmp);
395 static void PaintWindowThread()
407 ClientToScreen(_wnd.main_wnd, &pt);
408 OffsetRect(&_wnd.update_rect, pt.x, pt.y);
412 HRGN rgn = CreateRectRgnIndirect(&_wnd.update_rect);
413 HDC dc = GetDCEx(_wnd.main_wnd, rgn, DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_INTERSECTRGN);
418 SetRectEmpty(&_wnd.update_rect);
419 ReleaseDC(_wnd.main_wnd, dc);
431 #if !defined(UNICODE) 432 static char prev_char = 0;
434 char input[2] = {(char)charcode, 0};
437 if (prev_char != 0) {
439 input[0] = prev_char;
440 input[1] = (char)charcode;
442 }
else if (IsDBCSLeadByte(charcode)) {
444 prev_char = charcode;
450 int len = MultiByteToWideChar(CP_ACP, 0, input, input_len, w, 2);
461 DEBUG(driver, 1,
"Invalid DBCS character sequence encountered, dropping input");
466 static WChar prev_char = 0;
470 if (prev_char != 0)
DEBUG(driver, 1,
"Got two UTF-16 lead surrogates, dropping the first one");
471 prev_char = charcode;
476 if (prev_char != 0) {
480 DEBUG(driver, 1,
"Got an UTF-16 lead surrogate without a trail surrogate, dropping the lead surrogate");
494 return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI);
500 HIMC hIMC = ImmGetContext(hwnd);
503 cf.dwStyle = CFS_POINT;
508 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
509 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
511 cf.ptCurrentPos.x = 0;
512 cf.ptCurrentPos.y = 0;
514 ImmSetCompositionWindow(hIMC, &cf);
516 ImmReleaseContext(hwnd, hIMC);
522 HIMC hIMC = ImmGetContext(hwnd);
526 cf.dwStyle = CFS_EXCLUDE;
530 cf.ptCurrentPos.x = _focused_window->
left + pt.x;
531 cf.ptCurrentPos.y = _focused_window->
top + pt.y;
533 cf.rcArea.left = _focused_window->
left;
534 cf.rcArea.top = _focused_window->
top;
535 cf.rcArea.right = _focused_window->
left + _focused_window->
width;
536 cf.rcArea.bottom = _focused_window->
top + _focused_window->
height;
544 cf.ptCurrentPos.x = 0;
545 cf.ptCurrentPos.y = 0;
546 SetRectEmpty(&cf.rcArea);
548 ImmSetCandidateWindow(hIMC, &cf);
550 ImmReleaseContext(hwnd, hIMC);
556 HIMC hIMC = ImmGetContext(hwnd);
559 if (lParam & GCS_RESULTSTR) {
561 LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR,
nullptr, 0);
562 TCHAR *str = (TCHAR *)_alloca(len +
sizeof(TCHAR));
563 len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str, len);
564 str[len /
sizeof(TCHAR)] =
'\0';
574 lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR);
579 LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR,
nullptr, 0);
580 TCHAR *str = (TCHAR *)_alloca(len +
sizeof(TCHAR));
581 len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str, len);
582 str[len /
sizeof(TCHAR)] =
'\0';
585 static char utf8_buf[1024];
589 LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS,
nullptr, 0);
590 const char *caret = utf8_buf;
591 for (
const TCHAR *c = str; *c !=
'\0' && *caret !=
'\0' && caret_bytes > 0; c++, caret_bytes--) {
596 if (IsDBCSLeadByte(*c)) {
609 lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART);
612 ImmReleaseContext(hwnd, hIMC);
614 return lParam != 0 ? DefWindowProc(hwnd, WM_IME_COMPOSITION, wParam, lParam) : 0;
620 HIMC hIMC = ImmGetContext(hwnd);
621 if (hIMC != NULL) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
622 ImmReleaseContext(hwnd, hIMC);
627 static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
629 static uint32 keycode = 0;
630 static bool console =
false;
631 static bool in_sizemove =
false;
635 SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, TrackMouseTimerProc);
640 case WM_ENTERSIZEMOVE:
644 case WM_EXITSIZEMOVE:
652 GetUpdateRect(hwnd, &r, FALSE);
653 UnionRect(&_wnd.update_rect, &_wnd.update_rect, &r);
656 ValidateRect(hwnd,
nullptr);
661 BeginPaint(hwnd, &ps);
667 case WM_PALETTECHANGED:
668 if ((HWND)wParam == hwnd)
return 0;
671 case WM_QUERYNEWPALETTE: {
672 HDC hDC = GetWindowDC(hwnd);
673 HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE);
674 UINT nChanged = RealizePalette(hDC);
676 SelectPalette(hDC, hOldPalette, TRUE);
677 ReleaseDC(hwnd, hDC);
678 if (nChanged != 0) InvalidateRect(hwnd,
nullptr, FALSE);
683 HandleExitGameRequest();
724 int x = (int16)LOWORD(lParam);
725 int y = (int16)HIWORD(lParam);
732 if (_pTrackMouseEvent !=
nullptr) {
734 tme.cbSize =
sizeof(tme);
735 tme.dwFlags = TME_LEAVE;
736 tme.hwndTrack = hwnd;
738 _pTrackMouseEvent(&tme);
740 SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, TrackMouseTimerProc);
748 while (PeekMessage(&m, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE | PM_NOYIELD | PM_QS_INPUT)) {
749 x = (int16)LOWORD(m.lParam);
750 y = (int16)HIWORD(m.lParam);
756 pt.x = _cursor.
pos.x;
757 pt.y = _cursor.
pos.y;
758 ClientToScreen(hwnd, &pt);
759 SetCursorPos(pt.x, pt.y);
766 case WM_INPUTLANGCHANGE:
770 case WM_IME_SETCONTEXT:
775 case WM_IME_STARTCOMPOSITION:
780 case WM_IME_COMPOSITION:
783 case WM_IME_ENDCOMPOSITION:
793 #if !defined(UNICODE) 795 if (
GB(wParam, 8, 8) != 0) {
804 console =
GB(lParam, 16, 8) == 41;
808 uint scancode =
GB(lParam, 16, 8);
809 uint charcode = wParam;
813 if (console && scancode == 41) {
820 uint cur_keycode = keycode;
828 uint scancode =
GB(lParam, 16, 8);
829 keycode = scancode == 41 ? (uint)WKC_BACKQUOTE : MapWindowsKey(wParam);
833 if (PeekMessage(&msg,
nullptr, 0, 0, PM_NOREMOVE)) {
834 if ((msg.message == WM_CHAR || msg.message == WM_DEADCHAR) &&
GB(lParam, 16, 8) ==
GB(msg.lParam, 16, 8)) {
839 uint charcode = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR);
848 if (
HasBit(charcode, 31) && !console) {
849 if (scancode == 41) {
858 uint cur_keycode = keycode;
868 ToggleFullScreen(!_wnd.fullscreen);
885 if (wParam != SIZE_MINIMIZED) {
888 _window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
889 if (_window_maximize || _fullscreen) _bck_resolution =
_cur_resolution;
890 ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
895 RECT *r = (RECT*)lParam;
899 SetRect(&r2, 0, 0, 0, 0);
900 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
902 w = r->right - r->left - (r2.right - r2.left);
903 h = r->bottom - r->top - (r2.bottom - r2.top);
906 SetRect(&r2, 0, 0, w, h);
908 AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
909 w = r2.right - r2.left;
910 h = r2.bottom - r2.top;
914 r->bottom = r->top + h;
917 case WMSZ_BOTTOMLEFT:
918 r->bottom = r->top + h;
919 r->left = r->right - w;
922 case WMSZ_BOTTOMRIGHT:
923 r->bottom = r->top + h;
924 r->right = r->left + w;
928 r->left = r->right - w;
932 r->right = r->left + w;
936 r->top = r->bottom - h;
940 r->top = r->bottom - h;
941 r->left = r->right - w;
945 r->top = r->bottom - h;
946 r->right = r->left + w;
953 #if !defined(WM_MOUSEWHEEL) 954 # define WM_MOUSEWHEEL 0x020A 956 #if !defined(GET_WHEEL_DELTA_WPARAM) 957 # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam)) 960 case WM_MOUSEWHEEL: {
961 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
965 }
else if (delta > 0) {
973 _wnd.has_focus =
true;
978 _wnd.has_focus =
false;
983 if (_exit_game)
break;
985 bool active = (LOWORD(wParam) != WA_INACTIVE);
986 bool minimized = (HIWORD(wParam) != 0);
987 if (_wnd.fullscreen) {
988 if (active && minimized) {
990 ShowWindow(hwnd, SW_RESTORE);
992 }
else if (!active && !minimized) {
994 ShowWindow(hwnd, SW_MINIMIZE);
995 ChangeDisplaySettings(
nullptr, 0);
1002 return DefWindowProc(hwnd, msg, wParam, lParam);
1005 static void RegisterWndClass()
1007 static bool registered =
false;
1010 HINSTANCE hinst = GetModuleHandle(
nullptr);
1017 LoadIcon(hinst, MAKEINTRESOURCE(100)),
1018 LoadCursor(
nullptr, IDC_ARROW),
1025 if (!RegisterClass(&wnd))
usererror(
"RegisterClass failed");
1028 _pTrackMouseEvent = (PFNTRACKMOUSEEVENT)GetProcAddress(GetModuleHandle(_T(
"User32")),
"TrackMouseEvent");
1032 static bool AllocateDibSection(
int w,
int h,
bool force)
1041 if (bpp == 0)
usererror(
"Can't use a blitter that blits 0 bpp for normal visuals");
1043 if (!force && w == _screen.width && h == _screen.height)
return false;
1045 bi = (BITMAPINFO*)alloca(
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * 256);
1046 memset(bi, 0,
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * 256);
1047 bi->bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
1049 bi->bmiHeader.biWidth = _wnd.width = w;
1050 bi->bmiHeader.biHeight = -(_wnd.height = h);
1052 bi->bmiHeader.biPlanes = 1;
1054 bi->bmiHeader.biCompression = BI_RGB;
1056 if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
1059 _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits,
nullptr, 0);
1060 if (_wnd.dib_sect ==
nullptr)
usererror(
"CreateDIBSection failed");
1064 _screen.pitch = (bpp == 8) ?
Align(w, 4) : w;
1066 _screen.dst_ptr = _wnd.buffer_bits;
1071 static const Dimension default_resolutions[] = {
1085 static void FindResolutions()
1098 for (i = 0; EnumDisplaySettingsA(
nullptr, i, &dm) != 0; i++) {
1099 if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480)
continue;
1101 _resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight);
1106 _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions));
1116 memset(&_wnd, 0,
sizeof(_wnd));
1142 DeleteObject(_wnd.gdi_palette);
1143 DeleteObject(_wnd.dib_sect);
1144 DestroyWindow(_wnd.main_wnd);
1146 if (_wnd.fullscreen) ChangeDisplaySettings(
nullptr, 0);
1152 RECT r = { left, top, left + width, top + height };
1154 InvalidateRect(_wnd.main_wnd, &r, FALSE);
1157 static void CheckPaletteAnim()
1162 InvalidateRect(_wnd.main_wnd,
nullptr, FALSE);
1168 uint32 cur_ticks = GetTickCount();
1169 uint32 last_cur_ticks = cur_ticks;
1172 std::thread draw_thread;
1173 std::unique_lock<std::recursive_mutex> draw_lock;
1186 draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
1194 draw_lock.release();
1197 _draw_mutex =
nullptr;
1200 DEBUG(driver, 1,
"Threaded drawing enabled");
1207 _wnd.running =
true;
1211 uint32 prev_cur_ticks = cur_ticks;
1213 while (PeekMessage(&mesg,
nullptr, 0, 0, PM_REMOVE)) {
1214 InteractiveRandom();
1217 DispatchMessage(&mesg);
1219 if (_exit_game)
break;
1222 if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 &&
1225 if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0 && GetAsyncKeyState(VK_MENU) >= 0 &&
1229 }
else if (_fast_forward & 2) {
1233 cur_ticks = GetTickCount();
1234 if (cur_ticks >= next_tick || (_fast_forward && !
_pause_mode) || cur_ticks < prev_cur_ticks) {
1236 last_cur_ticks = cur_ticks;
1241 _ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0;
1245 if (_wnd.has_focus) {
1247 (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
1248 (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
1249 (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
1250 (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
1289 if (draw_lock.owns_lock()) draw_lock.unlock();
1290 draw_lock.release();
1302 std::unique_lock<std::recursive_mutex>
lock;
1303 if (
_draw_mutex !=
nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
1305 if (_window_maximize) ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL);
1307 _wnd.width = _wnd.width_org = w;
1308 _wnd.height = _wnd.height_org = h;
1315 std::unique_lock<std::recursive_mutex>
lock;
1316 if (
_draw_mutex !=
nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
1323 return AllocateDibSection(_screen.width, _screen.height,
true) && this->
MakeWindow(_fullscreen);
1338 std::unique_lock<std::recursive_mutex>
lock;
1339 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.