diff --git a/gfx.c b/gfx.c index 8c7a94febf..3dab6b132b 100644 --- a/gfx.c +++ b/gfx.c @@ -1654,6 +1654,9 @@ void DrawMouseCursor(void) int w; int h; + /* Redraw mouse cursor but only when it's inside the window */ + if (!_cursor.in_window) return; + // Don't draw the mouse cursor if it's already drawn if (_cursor.visible) { if (!_cursor.dirty) return; diff --git a/gfx.h b/gfx.h index 66eb5eee1a..4e605a24e6 100644 --- a/gfx.h +++ b/gfx.h @@ -21,17 +21,18 @@ struct DrawPixelInfo { typedef struct CursorVars { - Point pos, size, offs, delta; - Point draw_pos, draw_size; - CursorID sprite; + Point pos, size, offs, delta; ///< position, size, offset from top-left, and movement + Point draw_pos, draw_size; ///< position and size bounding-box for drawing + CursorID sprite; ///< current image of cursor - int wheel; // mouse wheel movement - const CursorID *animate_list, *animate_cur; - uint animate_timeout; + int wheel; ///< mouse wheel movement + const CursorID *animate_list, *animate_cur; ///< in case of animated cursor, list of frames + uint animate_timeout; ///< current frame in list of animated cursor - bool visible; - bool dirty; - bool fix_at; + bool visible; ///< cursor is visible + bool dirty; ///< the rect occupied by the mouse is dirty (redraw) + bool fix_at; ///< mouse is moving, but cursor is not (used for scrolling) + bool in_window; ///< mouse inside this window, determines drawing logic } CursorVars; diff --git a/openttd.c b/openttd.c index bc928779fe..15b20e1405 100644 --- a/openttd.c +++ b/openttd.c @@ -450,6 +450,7 @@ int ttd_main(int argc, char* argv[]) // initialize the ingame console IConsoleInit(); + _cursor.in_window = true; InitializeGUI(); IConsoleCmdExec("exec scripts/autoexec.scr 0"); diff --git a/video/sdl_v.c b/video/sdl_v.c index 3b27c7ad61..d190237fb2 100644 --- a/video/sdl_v.c +++ b/video/sdl_v.c @@ -345,6 +345,15 @@ static int PollEvent(void) } break; + case SDL_ACTIVEEVENT: + if (ev.active.gain == 1) // mouse entered the window, enable cursor + _cursor.in_window = true; + else if (ev.active.gain == 0) { + UndrawMouseCursor(); // mouse left the window, undraw cursor + _cursor.in_window = false; + } + break; + case SDL_QUIT: // do not ask to quit on the main screen if (_game_mode != GM_MENU) { diff --git a/video/win32_v.c b/video/win32_v.c index 3ecda25287..aff4f2526c 100644 --- a/video/win32_v.c +++ b/video/win32_v.c @@ -184,9 +184,40 @@ int RedrawScreenDebug(void) } #endif +/* Windows 95 will not have a WM_MOUSELEAVE message, so define it if + * needed. There is no such event as WM_MOUSEENTER, we just made this up :) */ +#define WM_MOUSEENTER WM_USER + 1 +#if !defined(WM_MOUSELEAVE) +#define WM_MOUSELEAVE 0x02A3 +#endif +#define TID_POLLMOUSE 1 +#define MOUSE_POLL_DELAY 75 + +static void CALLBACK TrackMouseTimerProc(HWND hwnd, UINT msg, UINT event, DWORD time) +{ + RECT rc; + POINT pt; + + /* Get the rectangle of our window and translate it to screen coordinates. + * Compare this with the current screen coordinates of the mouse and if it + * falls outside of the area or our window we have left the window. */ + GetClientRect(hwnd, &rc); + MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)&rc, 2); + GetCursorPos(&pt); + + if (!PtInRect(&rc, pt) || (WindowFromPoint(pt) != hwnd)) { + KillTimer(hwnd, event); + PostMessage(hwnd, WM_MOUSELEAVE, 0, 0L); + } +} + static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { + case WM_CREATE: + SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc); + break; + case WM_PAINT: { PAINTSTRUCT ps; HDC dc,dc2; @@ -259,11 +290,33 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP _right_button_down = false; return 0; + case WM_MOUSEENTER: + printf("enter\n"); + _cursor.in_window = true; + DrawMouseCursor(); + break; + + case WM_MOUSELEAVE: + printf("enter\n"); + UndrawMouseCursor(); + _cursor.in_window = false; + break; + case WM_MOUSEMOVE: { int x = (int16)LOWORD(lParam); int y = (int16)HIWORD(lParam); POINT pt; + /* If the mouse was not in the window and it has moved it means it has + * come into the window, so send a WM_MOUSEENTER message. Also start + * tracking the mouse for exiting the window */ + if (!_cursor.in_window) { + _cursor.in_window = true; + SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc); + + if (hwnd != GetCapture()) PostMessage(hwnd, WM_MOUSEENTER, 0, 0L); + } + if (_wnd.double_size) { x /= 2; y /= 2;