forked from 0ad/0ad
wsdl: fix incorrect handling of mouse leaving the window. split complicated if logic into separate function.
wposix: use Liberror_set_errno various other improvements spotted while looking through code. This was SVN commit r3281.
This commit is contained in:
parent
d8149fe9a1
commit
6d137a5c41
@ -308,8 +308,8 @@ static LibError ia32_walk_stack(STACKFRAME64* sf)
|
||||
|
||||
// called for each stack frame found by walk_stack, passing information
|
||||
// about the frame and <user_arg>.
|
||||
// return <= 0 to stop immediately and have walk_stack return that;
|
||||
// otherwise, > 0 to continue.
|
||||
// return INFO_CB_CONTINUE to continue, anything else to stop immediately
|
||||
// and return that value to walk_stack's caller.
|
||||
//
|
||||
// rationale: we can't just pass function's address to the callback -
|
||||
// dump_frame_cb needs the frame pointer for reg-relative variables.
|
||||
@ -353,10 +353,11 @@ static LibError walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip
|
||||
ia32_get_current_context(&context);
|
||||
#else
|
||||
// try to import RtlCaptureContext (available on WinXP and later)
|
||||
HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");
|
||||
// .. note: kernel32 is always loaded into every process, so we
|
||||
// don't need LoadLibrary/FreeLibrary.
|
||||
HMODULE hKernel32Dll = GetModuleHandle("kernel32.dll");
|
||||
VOID (*pRtlCaptureContext)(PCONTEXT*);
|
||||
*(void**)&pRtlCaptureContext = GetProcAddress(hKernel32Dll, "RtlCaptureContext");
|
||||
FreeLibrary(hKernel32Dll); // doesn't actually free the lib
|
||||
if(pRtlCaptureContext)
|
||||
pRtlCaptureContext(&context);
|
||||
// not available: raise+handle an exception; grab the reported context.
|
||||
|
@ -88,30 +88,31 @@ static Watches watches;
|
||||
struct Watch
|
||||
{
|
||||
intptr_t reqnum;
|
||||
|
||||
// (refcounted, since dir_add_watch reuses existing Watches)
|
||||
int refs;
|
||||
// refcounted, since dir_add_watch reuses existing Watches.
|
||||
|
||||
std::string dir_name;
|
||||
HANDLE hDir;
|
||||
|
||||
// storage for RDC lpBytesReturned to avoid BoundsChecker warning
|
||||
// (dox are unclear on whether the pointer must be valid).
|
||||
DWORD dummy_nbytes;
|
||||
// storage for RDC lpBytesReturned, to avoid BoundsChecker warning
|
||||
// (dox are unclear on whether the pointer must be valid).
|
||||
|
||||
// fields aren't used.
|
||||
// overlapped I/O completation notification is via IOCP.
|
||||
OVERLAPPED ovl;
|
||||
// fields aren't used.
|
||||
// overlapped I/O completation notification is via IOCP.
|
||||
|
||||
// if too small, the current FILE_NOTIFY_INFORMATION is lost!
|
||||
// this is enough for ~7 packets (worst case) - should be enough,
|
||||
// since the app polls once a frame. we don't want to waste too much
|
||||
// memory. size chosen such that sizeof(Watch) = 4KiB.
|
||||
// issue code uses sizeof(change_buf) to determine size.
|
||||
//
|
||||
// note: we can't share one central buffer: the individual watches
|
||||
// are independent, and may be triggered 'simultaneously' before
|
||||
// the next app poll, so they'd overwrite one another.
|
||||
char change_buf[4096-58];
|
||||
// if too small, the current FILE_NOTIFY_INFORMATION is lost!
|
||||
// this is enough for ~7 packets (worst case) - should be enough,
|
||||
// since the app polls once a frame. we don't want to waste too much
|
||||
// memory. size chosen such that sizeof(Watch) = 4KiB.
|
||||
// issue code uses sizeof(change_buf) to determine size.
|
||||
//
|
||||
// note: we can't share one central buffer: the individual watches
|
||||
// are independent, and may be triggered 'simultaneously' before
|
||||
// the next app poll, so they'd overwrite one another.
|
||||
|
||||
|
||||
Watch(intptr_t _reqnum, const std::string& _dir_name, HANDLE _hDir)
|
||||
|
@ -330,7 +330,7 @@ static inline void pre_libc_init()
|
||||
int entry()
|
||||
{
|
||||
int ret = -1;
|
||||
// __try
|
||||
__try
|
||||
{
|
||||
pre_libc_init();
|
||||
#ifdef USE_WINMAIN
|
||||
@ -339,7 +339,7 @@ int entry()
|
||||
ret = mainCRTStartup(); // calls _cinit and then our main
|
||||
#endif
|
||||
}
|
||||
// __except(wdbg_exception_filter(GetExceptionInformation()))
|
||||
__except(wdbg_exception_filter(GetExceptionInformation()))
|
||||
{
|
||||
}
|
||||
return ret;
|
||||
|
@ -418,23 +418,15 @@ fail:
|
||||
d->hFind = FindFirstFileA(search_path, &d->fd);
|
||||
if(d->hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
switch(GetLastError())
|
||||
{
|
||||
// not an error - the directory is just empty.
|
||||
case ERROR_NO_MORE_FILES:
|
||||
if(GetLastError() == ERROR_NO_MORE_FILES)
|
||||
goto success;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
// translate Win32 error to errno.
|
||||
LibError err = LibError_from_win32(0);
|
||||
LibError_set_errno(err);
|
||||
|
||||
// release the WDIR allocated above.
|
||||
// unfortunately there's no way around this; we need to allocate
|
||||
// d before FindFirstFile because it uses d->fd. copying from a
|
||||
// temporary isn't nice either (this free doesn't happen often)
|
||||
@ -501,7 +493,7 @@ int readdir_stat_np(DIR* d_, struct stat* s)
|
||||
{
|
||||
WDIR* d = (WDIR*)d_;
|
||||
|
||||
memset(s, 0, sizeof(struct stat));
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->st_size = (off_t)u64_from_u32(d->fd.nFileSizeHigh, d->fd.nFileSizeLow);
|
||||
s->st_mode = (d->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
|
||||
s->st_mtime = filetime_to_time_t(&d->fd.ftLastWriteTime);
|
||||
|
@ -72,7 +72,6 @@ HWND hWnd = (HWND)INVALID_HANDLE_VALUE;
|
||||
static HDC hDC = (HDC)INVALID_HANDLE_VALUE; // needed by gamma code
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// gamma
|
||||
|
||||
@ -156,6 +155,25 @@ static HGLRC hGLRC = (HGLRC)INVALID_HANDLE_VALUE;
|
||||
|
||||
static int depth_bits = 24; // depth buffer size; set via SDL_GL_SetAttribute
|
||||
|
||||
// check if resolution needs to be changed
|
||||
static bool video_need_change(int w, int h, int cur_w, int cur_h, bool fullscreen)
|
||||
{
|
||||
// invalid: keep current settings
|
||||
if(w <= 0 || h <= 0)
|
||||
return false;
|
||||
|
||||
// higher resolution mode needed
|
||||
if(w > cur_w || h > cur_h)
|
||||
return true;
|
||||
|
||||
// fullscreen requested and not exact same mode set
|
||||
if(fullscreen && (w != cur_w || h != cur_h))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline void video_enter_game_mode()
|
||||
{
|
||||
ShowWindow(hWnd, SW_RESTORE);
|
||||
@ -199,22 +217,13 @@ int SDL_SetVideoMode(int w, int h, int bpp, unsigned long flags)
|
||||
dm.dmBitsPerPel = bpp;
|
||||
dm.dmFields = DM_BITSPERPEL;
|
||||
|
||||
// check if resolution needs to be changed
|
||||
// .. invalid: keep current settings
|
||||
if(w <= 0 || h <= 0 || bpp <= 0)
|
||||
goto keep;
|
||||
// .. higher resolution mode needed
|
||||
if(w > cur_w || h > cur_h)
|
||||
goto change;
|
||||
// .. fullscreen requested and not exact same mode set
|
||||
if(fullscreen && (w != cur_w || h != cur_h))
|
||||
if(video_need_change(w,h, cur_w,cur_h, fullscreen))
|
||||
{
|
||||
change:
|
||||
dm.dmPelsWidth = (DWORD)w;
|
||||
dm.dmPelsHeight = (DWORD)h;
|
||||
dm.dmFields |= DM_PELSWIDTH|DM_PELSHEIGHT;
|
||||
}
|
||||
keep:
|
||||
|
||||
|
||||
// the (possibly changed) mode will be (re)set at next WM_ACTIVATE
|
||||
|
||||
@ -445,17 +454,7 @@ static bool dequeue_event(SDL_Event* ev)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void queue_active_event(uint gain, uint changed_app_state)
|
||||
{
|
||||
// SDL says this event is not generated when the window is created,
|
||||
// but skipping the first event may confuse things.
|
||||
|
||||
SDL_Event ev;
|
||||
ev.type = SDL_ACTIVEEVENT;
|
||||
ev.active.state = (u8)changed_app_state;
|
||||
ev.active.gain = (u8)gain;
|
||||
queue_event(ev);
|
||||
}
|
||||
|
||||
static void queue_quit_event()
|
||||
{
|
||||
@ -464,6 +463,97 @@ static void queue_quit_event()
|
||||
queue_event(ev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// app activation
|
||||
|
||||
enum SdlActivationType { LOSE = 0, GAIN = 1 };
|
||||
|
||||
static inline void queue_active_event(SdlActivationType type, uint changed_app_state)
|
||||
{
|
||||
// SDL says this event is not generated when the window is created,
|
||||
// but skipping the first event may confuse things.
|
||||
|
||||
SDL_Event ev;
|
||||
ev.type = SDL_ACTIVEEVENT;
|
||||
ev.active.state = (u8)changed_app_state;
|
||||
ev.active.gain = (type == GAIN)? 1 : 0;
|
||||
queue_event(ev);
|
||||
}
|
||||
|
||||
|
||||
// SDL_APP* bitflags indicating whether we are active.
|
||||
// note: responsibility for yielding lies with SDL apps -
|
||||
// they control the main loop.
|
||||
static uint app_state;
|
||||
|
||||
static void active_change_state(SdlActivationType type, uint changed_app_state)
|
||||
{
|
||||
uint old_app_state = app_state;
|
||||
|
||||
if(type == GAIN)
|
||||
app_state |= changed_app_state;
|
||||
else
|
||||
app_state &= ~changed_app_state;
|
||||
|
||||
// generate an event - but only if the given state flags actually changed.
|
||||
if((old_app_state & changed_app_state) != (app_state & changed_app_state))
|
||||
queue_active_event(type, changed_app_state);
|
||||
}
|
||||
|
||||
static void reset_all_keys();
|
||||
|
||||
static LRESULT OnActivate(HWND hWnd, UINT state, HWND UNUSED(hWndActDeact), BOOL fMinimized)
|
||||
{
|
||||
SdlActivationType type;
|
||||
uint changed_app_state;
|
||||
|
||||
// went active and not minimized
|
||||
if(state != WA_INACTIVE && !fMinimized)
|
||||
{
|
||||
type = GAIN;
|
||||
changed_app_state = SDL_APPINPUTFOCUS|SDL_APPACTIVE;
|
||||
|
||||
|
||||
// grab keyboard focus (we previously had DefWindowProc do this).
|
||||
SetFocus(hWnd);
|
||||
|
||||
gamma_swap(GAMMA_LATCH_NEW_RAMP);
|
||||
if(fullscreen)
|
||||
video_enter_game_mode();
|
||||
}
|
||||
// deactivated (Alt+Tab out) or minimized
|
||||
else
|
||||
{
|
||||
type = LOSE;
|
||||
changed_app_state = SDL_APPINPUTFOCUS;
|
||||
if(fMinimized)
|
||||
changed_app_state |= SDL_APPACTIVE;
|
||||
|
||||
|
||||
reset_all_keys();
|
||||
|
||||
gamma_swap(GAMMA_RESTORE_ORIGINAL);
|
||||
if(fullscreen)
|
||||
video_leave_game_mode();
|
||||
}
|
||||
|
||||
active_change_state(type, changed_app_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Uint8 SDL_GetAppState()
|
||||
{
|
||||
return app_state;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// keyboard
|
||||
|
||||
// note: keysym.unicode is only returned for SDL_KEYDOWN, and is otherwise 0.
|
||||
static void queue_key_event(uint type, uint sdlk, WCHAR unicode_char)
|
||||
{
|
||||
@ -474,20 +564,6 @@ static void queue_key_event(uint type, uint sdlk, WCHAR unicode_char)
|
||||
queue_event(ev);
|
||||
}
|
||||
|
||||
static void queue_button_event(uint button, uint state, uint x, uint y)
|
||||
{
|
||||
SDL_Event ev;
|
||||
ev.type = (state == SDL_PRESSED)? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
|
||||
ev.button.button = (u8)button;
|
||||
ev.button.state = (u8)state;
|
||||
ev.button.x = x;
|
||||
ev.button.y = y;
|
||||
queue_event(ev);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// keyboard
|
||||
|
||||
static Uint8 keys[SDLK_LAST];
|
||||
|
||||
@ -661,7 +737,72 @@ int SDL_EnableUNICODE(int UNUSED(enable))
|
||||
//----------------------------------------------------------------------------
|
||||
// mouse
|
||||
|
||||
static void queue_mouse_event(uint x, uint y)
|
||||
{
|
||||
SDL_Event ev;
|
||||
ev.type = SDL_MOUSEMOTION;
|
||||
debug_assert(x <= USHRT_MAX && y <= USHRT_MAX);
|
||||
ev.motion.x = x;
|
||||
ev.motion.y = y;
|
||||
queue_event(ev);
|
||||
}
|
||||
|
||||
static void queue_button_event(uint button, uint state, uint x, uint y)
|
||||
{
|
||||
SDL_Event ev;
|
||||
ev.type = (state == SDL_PRESSED)? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
|
||||
ev.button.button = (u8)button;
|
||||
ev.button.state = (u8)state;
|
||||
debug_assert(x <= USHRT_MAX && y <= USHRT_MAX);
|
||||
ev.button.x = x;
|
||||
ev.button.y = y;
|
||||
queue_event(ev);
|
||||
}
|
||||
|
||||
|
||||
static uint mouse_x, mouse_y;
|
||||
|
||||
// generate a mouse move message and update our notion of the mouse position.
|
||||
// x, y are screen pixel coordinates.
|
||||
// notes:
|
||||
// - does not actually move the OS cursor;
|
||||
// - called from mouse_update and SDL_WarpMouse.
|
||||
// - coords should never be negative - this would indicate a logic error.
|
||||
static void mouse_moved(int x, int y)
|
||||
{
|
||||
debug_assert(x >= 0 && y >= 0);
|
||||
mouse_x = (uint)x;
|
||||
mouse_y = (uint)y;
|
||||
queue_mouse_event(mouse_x, mouse_y);
|
||||
}
|
||||
|
||||
|
||||
static void mouse_update()
|
||||
{
|
||||
// don't use DirectInput, because we want to respect the user's mouse
|
||||
// sensitivity settings. Windows messages are laggy, so poll instead.
|
||||
|
||||
POINT pt;
|
||||
WARN_IF_FALSE(GetCursorPos(&pt));
|
||||
WARN_IF_FALSE(ScreenToClient(hWnd, &pt));
|
||||
|
||||
// nothing to do if it hasn't changed since last time
|
||||
if(mouse_x == (uint)pt.x && mouse_y == (uint)pt.y)
|
||||
return;
|
||||
|
||||
// moved within window
|
||||
RECT client_rect;
|
||||
GetClientRect(hWnd, &client_rect);
|
||||
if(PtInRect(&client_rect, pt) && WindowFromPoint(pt) == hWnd)
|
||||
{
|
||||
active_change_state(GAIN, SDL_APPMOUSEFOCUS);
|
||||
mouse_moved((int)pt.x, (int)pt.y);
|
||||
}
|
||||
// moved outside of window
|
||||
else
|
||||
queue_active_event(LOSE, SDL_APPMOUSEFOCUS);
|
||||
}
|
||||
|
||||
static uint mouse_buttons;
|
||||
|
||||
// (we define a new function signature since the windowsx.h message crackers
|
||||
@ -751,9 +892,8 @@ Uint8 SDL_GetMouseState(int* x, int* y)
|
||||
|
||||
inline void SDL_WarpMouse(int x, int y)
|
||||
{
|
||||
mouse_x = (uint)x;
|
||||
mouse_y = (uint)y;
|
||||
WARN_IF_FALSE(SetCursorPos(x, y));
|
||||
mouse_moved(x, y);
|
||||
}
|
||||
|
||||
|
||||
@ -774,62 +914,6 @@ int SDL_ShowCursor(int toggle)
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// app activation
|
||||
|
||||
// SDL_APP* bitflags indicating whether we are active.
|
||||
// note: responsibility for yielding lies with SDL apps -
|
||||
// they control the main loop.
|
||||
static uint app_state;
|
||||
|
||||
static LRESULT OnActivate(HWND hWnd, UINT state, HWND UNUSED(hWndActDeact), BOOL fMinimized)
|
||||
{
|
||||
uint changed_app_state;
|
||||
uint gain;
|
||||
if(state != WA_INACTIVE && !fMinimized)
|
||||
{
|
||||
gain = 1;
|
||||
changed_app_state = SDL_APPINPUTFOCUS|SDL_APPACTIVE;
|
||||
app_state |= changed_app_state;
|
||||
}
|
||||
// deactivated (Alt+Tab out) or minimized
|
||||
else
|
||||
{
|
||||
gain = 0;
|
||||
changed_app_state = SDL_APPINPUTFOCUS;
|
||||
if(fMinimized)
|
||||
changed_app_state |= SDL_APPACTIVE;
|
||||
app_state &= ~changed_app_state;
|
||||
}
|
||||
|
||||
if(gain)
|
||||
{
|
||||
// grab keyboard focus (we previously had DefWindowProc do this).
|
||||
SetFocus(hWnd);
|
||||
|
||||
gamma_swap(GAMMA_LATCH_NEW_RAMP);
|
||||
if(fullscreen)
|
||||
video_enter_game_mode();
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_all_keys();
|
||||
|
||||
gamma_swap(GAMMA_RESTORE_ORIGINAL);
|
||||
if(fullscreen)
|
||||
video_leave_game_mode();
|
||||
}
|
||||
|
||||
queue_active_event(gain, changed_app_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Uint8 SDL_GetAppState()
|
||||
{
|
||||
return app_state;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -890,6 +974,7 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||
|
||||
HANDLE_MSG(hWnd, WM_MOUSEWHEEL, OnMouseWheel);
|
||||
|
||||
// (can't use message crackers: they do not provide for passing uMsg)
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN:
|
||||
@ -916,6 +1001,8 @@ void SDL_PumpEvents(void)
|
||||
// instead, they should check active state and call SDL_Delay etc.
|
||||
// if our window is minimized.
|
||||
|
||||
mouse_update(); // polled
|
||||
|
||||
MSG msg;
|
||||
while(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
@ -924,6 +1011,7 @@ void SDL_PumpEvents(void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
int SDL_PollEvent(SDL_Event* ev)
|
||||
{
|
||||
SDL_PumpEvents();
|
||||
@ -931,22 +1019,6 @@ int SDL_PollEvent(SDL_Event* ev)
|
||||
if(dequeue_event(ev))
|
||||
return 1;
|
||||
|
||||
// mouse motion
|
||||
//
|
||||
// don't use DirectInput, because we want to respect the user's mouse
|
||||
// sensitivity settings. Windows messages are laggy, so poll instead.
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
ScreenToClient(hWnd, &p);
|
||||
if(mouse_x != (uint)p.x || mouse_y != (uint)p.y)
|
||||
{
|
||||
// don't use queue_event; we fill the SDL_Event directly here
|
||||
ev->type = SDL_MOUSEMOTION;
|
||||
ev->motion.x = mouse_x = p.x;
|
||||
ev->motion.y = mouse_y = p.y;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user