/* Looking Glass - KVM FrameRelay (KVMFR) Client Copyright (C) 2017-2021 Geoffrey McRae https://looking-glass.hostfission.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "interface/displayserver.h" #include #include "app.h" #include "kb.h" #include "common/debug.h" struct SDLDSState { bool keyboardGrabbed; bool pointerGrabbed; bool exiting; }; static struct SDLDSState sdl; static bool sdlEarlyInit(void) { return true; } static bool sdlInit(SDL_SysWMinfo * info) { memset(&sdl, 0, sizeof(sdl)); return true; } static void sdlStartup(void) { } static void sdlShutdown(void) { } static void sdlFree(void) { } static bool sdlGetProp(LG_DSProperty prop, void * ret) { return false; } static bool sdlEventFilter(SDL_Event * event) { switch(event->type) { case SDL_QUIT: app_handleCloseEvent(); return true; case SDL_MOUSEMOTION: // stop motion events during the warp out of the window if (sdl.exiting) return true; app_updateCursorPos(event->motion.x, event->motion.y); if (app_cursorIsGrabbed()) app_handleMouseGrabbed(event->motion.xrel, event->motion.yrel); else app_handleMouseNormal(event->motion.xrel, event->motion.yrel); return true; case SDL_MOUSEBUTTONDOWN: { int button = event->button.button; if (button > 3) button += 2; app_handleButtonPress(button); return true; } case SDL_MOUSEBUTTONUP: { int button = event->button.button; if (button > 3) button += 2; app_handleButtonRelease(button); return true; } case SDL_MOUSEWHEEL: { int button = event->wheel.y > 0 ? 4 : 5; app_handleButtonPress(button); app_handleButtonRelease(button); return true; } case SDL_KEYDOWN: { SDL_Scancode sc = event->key.keysym.scancode; app_handleKeyPress(sdl_to_xfree86[sc]); break; } case SDL_KEYUP: { SDL_Scancode sc = event->key.keysym.scancode; app_handleKeyRelease(sdl_to_xfree86[sc]); break; } case SDL_WINDOWEVENT: switch(event->window.event) { case SDL_WINDOWEVENT_ENTER: app_handleEnterEvent(true); return true; case SDL_WINDOWEVENT_LEAVE: sdl.exiting = false; app_handleEnterEvent(false); return true; case SDL_WINDOWEVENT_FOCUS_GAINED: app_handleFocusEvent(true); return true; case SDL_WINDOWEVENT_FOCUS_LOST: app_handleFocusEvent(false); return true; case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_RESIZED: app_handleResizeEvent(event->window.data1, event->window.data2); return true; case SDL_WINDOWEVENT_MOVED: app_updateWindowPos(event->window.data1, event->window.data2); return true; case SDL_WINDOWEVENT_CLOSE: app_handleCloseEvent(); return true; } break; } return false; } static void sdlShowPointer(bool show) { SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE); } static void sdlGrabPointer(void) { SDL_SetWindowGrab(app_getWindow(), SDL_TRUE); SDL_SetRelativeMouseMode(SDL_TRUE); sdl.pointerGrabbed = true; } static void sdlUngrabPointer(void) { SDL_SetWindowGrab(app_getWindow(), SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE); sdl.pointerGrabbed = false; } static void sdlGrabKeyboard(void) { if (sdl.pointerGrabbed) SDL_SetWindowGrab(app_getWindow(), SDL_FALSE); else { DEBUG_WARN("SDL does not support grabbing only the keyboard, grabbing all"); sdl.pointerGrabbed = true; } SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); SDL_SetWindowGrab(app_getWindow(), SDL_TRUE); sdl.keyboardGrabbed = true; } static void sdlUngrabKeyboard(void) { SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "0"); SDL_SetWindowGrab(app_getWindow(), SDL_FALSE); if (sdl.pointerGrabbed) SDL_SetWindowGrab(app_getWindow(), SDL_TRUE); sdl.keyboardGrabbed = false; } static void sdlWarpPointer(int x, int y, bool exiting) { if (sdl.exiting) return; sdl.exiting = exiting; // if exiting turn off relative mode if (exiting) SDL_SetRelativeMouseMode(SDL_FALSE); // issue the warp SDL_WarpMouseInWindow(app_getWindow(), x, y); } static void sdlRealignPointer(void) { // no need to care about grab, realign only happens in normal mode app_handleMouseNormal(0, 0); } static bool sdlIsValidPointerPos(int x, int y) { const int displays = SDL_GetNumVideoDisplays(); for(int i = 0; i < displays; ++i) { SDL_Rect r; SDL_GetDisplayBounds(i, &r); if ((x >= r.x && x < r.x + r.w) && (y >= r.y && y < r.y + r.h)) return true; } return false; } static void sdlInhibitIdle(void) { SDL_DisableScreenSaver(); } static void sdlUninhibitIdle(void) { SDL_EnableScreenSaver(); } struct LG_DisplayServerOps LGDS_SDL = { .subsystem = SDL_SYSWM_UNKNOWN, .earlyInit = sdlEarlyInit, .init = sdlInit, .startup = sdlStartup, .shutdown = sdlShutdown, .free = sdlFree, .getProp = sdlGetProp, .eventFilter = sdlEventFilter, .showPointer = sdlShowPointer, .grabPointer = sdlGrabPointer, .ungrabPointer = sdlUngrabPointer, .grabKeyboard = sdlGrabKeyboard, .ungrabKeyboard = sdlUngrabKeyboard, .warpPointer = sdlWarpPointer, .realignPointer = sdlRealignPointer, .isValidPointerPos = sdlIsValidPointerPos, .inhibitIdle = sdlInhibitIdle, .uninhibitIdle = sdlUninhibitIdle, /* SDL does not have clipboard support */ .cbInit = NULL, };