From 2deed84c84e513ee1c2a2fbbcd3946c1d772fcbb Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 16 Sep 2016 00:12:26 +0300 Subject: [PATCH 01/16] Remove glViewport calls from GLContext They've been broken for a long time with mspgl, probably since framebuffer objects were implemented. The new GL::View class takes care of viewport size syncing better. --- source/graphics/cgl/glcontext.cpp | 1 - source/graphics/egl_android/glcontext.cpp | 6 ++---- source/graphics/glx/glcontext.cpp | 1 - source/graphics/wgl/glcontext.cpp | 4 +--- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/source/graphics/cgl/glcontext.cpp b/source/graphics/cgl/glcontext.cpp index 8283825..748b9b1 100644 --- a/source/graphics/cgl/glcontext.cpp +++ b/source/graphics/cgl/glcontext.cpp @@ -75,7 +75,6 @@ void GLContext::swap_buffers() void GLContext::window_resized(unsigned w, unsigned h) { // XXX Call [context update] here? - glViewport(0, 0, w, h); } } // namespace Graphics diff --git a/source/graphics/egl_android/glcontext.cpp b/source/graphics/egl_android/glcontext.cpp index ecf9a63..0e98739 100644 --- a/source/graphics/egl_android/glcontext.cpp +++ b/source/graphics/egl_android/glcontext.cpp @@ -114,10 +114,8 @@ void GLContext::swap_buffers() eglSwapBuffers(priv->display, priv->surface); } -void GLContext::window_resized(unsigned w, unsigned h) -{ - glViewport(0, 0, w, h); -} +void GLContext::window_resized(unsigned, unsigned) +{ } void GLContext::Private::attach(WindowHandle native_window) diff --git a/source/graphics/glx/glcontext.cpp b/source/graphics/glx/glcontext.cpp index 26275a4..e4662f3 100644 --- a/source/graphics/glx/glcontext.cpp +++ b/source/graphics/glx/glcontext.cpp @@ -92,7 +92,6 @@ void GLContext::swap_buffers() void GLContext::window_resized(unsigned w, unsigned h) { XMoveResizeWindow(display.get_private().display, priv->subwnd, 0, 0, w, h); - glViewport(0, 0, w, h); } } // namespace Graphics diff --git a/source/graphics/wgl/glcontext.cpp b/source/graphics/wgl/glcontext.cpp index 05f9533..b6b2c5f 100644 --- a/source/graphics/wgl/glcontext.cpp +++ b/source/graphics/wgl/glcontext.cpp @@ -61,9 +61,7 @@ void GLContext::swap_buffers() } void GLContext::window_resized(unsigned w, unsigned h) -{ - glViewport(0, 0, w, h); -} +{ } } // namespace Graphics } // namespace Msp -- 2.43.0 From a8a9191481151f049781b670ea8883025a594a5f Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 17 Sep 2016 00:34:26 +0300 Subject: [PATCH 02/16] Refactor storage of monitor settings --- source/graphics/display.cpp | 8 ++-- source/graphics/monitor.cpp | 14 ++++--- source/graphics/monitor.h | 16 ++++--- source/graphics/window.cpp | 2 +- source/graphics/windows/display.cpp | 4 +- source/graphics/x11/display.cpp | 65 ++++++++++++++--------------- 6 files changed, 58 insertions(+), 51 deletions(-) diff --git a/source/graphics/display.cpp b/source/graphics/display.cpp index 1c7b639..ebf14ea 100644 --- a/source/graphics/display.cpp +++ b/source/graphics/display.cpp @@ -25,16 +25,16 @@ void Display::remove_window(Window &wnd) const VideoMode &Display::get_desktop_mode() const { - if(!primary_monitor || !primary_monitor->desktop_mode) + if(!primary_monitor || !primary_monitor->desktop_settings.mode) throw logic_error("no desktop mode"); - return *primary_monitor->desktop_mode; + return *primary_monitor->desktop_settings.mode; } void Display::restore_mode() { for(list::const_iterator i=monitors.begin(); i!=monitors.end(); ++i) - if(i->desktop_mode) - set_mode(*i->desktop_mode, false); + if(i->desktop_settings.mode) + set_mode(*i->desktop_settings.mode, false); } const VideoMode *Display::find_mode(const VideoMode &mode, float rate_tolerance) const diff --git a/source/graphics/monitor.cpp b/source/graphics/monitor.cpp index 1ac4383..d1bdd43 100644 --- a/source/graphics/monitor.cpp +++ b/source/graphics/monitor.cpp @@ -7,15 +7,17 @@ namespace Graphics { Monitor::Monitor(): index(0), - desktop_mode(0), - desktop_rotation(ROTATE_NORMAL), - current_mode(0), - current_rotation(ROTATE_NORMAL), - x(0), - y(0), next_left(0), next_right(0) { } + +Monitor::Settings::Settings(): + mode(0), + rotation(ROTATE_NORMAL), + x(0), + y(0) +{ } + } // namespace Graphics } // namespace Msp diff --git a/source/graphics/monitor.h b/source/graphics/monitor.h index 35abce1..fefd986 100644 --- a/source/graphics/monitor.h +++ b/source/graphics/monitor.h @@ -10,14 +10,20 @@ namespace Graphics { struct Monitor { + struct Settings + { + const VideoMode *mode; + VideoRotation rotation; + int x, y; + + Settings(); + }; + unsigned index; std::string name; std::list video_modes; - const VideoMode *desktop_mode; - VideoRotation desktop_rotation; - const VideoMode *current_mode; - VideoRotation current_rotation; - int x, y; + Settings desktop_settings; + Settings current_settings; const Monitor *next_left; const Monitor *next_right; diff --git a/source/graphics/window.cpp b/source/graphics/window.cpp index 073cd8d..958667e 100644 --- a/source/graphics/window.cpp +++ b/source/graphics/window.cpp @@ -91,7 +91,7 @@ void Window::reconfigure(const WindowOptions &opts) void Window::set_fullscreen_mode() { VideoMode mode(options.width, options.height); - mode.rotation = display.get_desktop_mode().monitor->desktop_rotation; + mode.rotation = display.get_desktop_mode().monitor->desktop_settings.rotation; if(mode.rotation==ROTATE_LEFT || mode.rotation==ROTATE_RIGHT) swap(mode.width, mode.height); display.set_mode(mode, true); diff --git a/source/graphics/windows/display.cpp b/source/graphics/windows/display.cpp index d767beb..aaaa985 100644 --- a/source/graphics/windows/display.cpp +++ b/source/graphics/windows/display.cpp @@ -53,7 +53,7 @@ Display::Display(const string &): monitor.video_modes.push_back(&modes.back()); if(have_current && info.dmPelsWidth==current.dmPelsWidth && info.dmPelsHeight==current.dmPelsHeight && info.dmDisplayFrequency==current.dmDisplayFrequency) - monitor.desktop_mode = &modes.back(); + monitor.desktop_settings.mode = &modes.back(); } } } @@ -89,7 +89,7 @@ void Display::set_mode(const VideoMode &requested_mode, bool) for(list::iterator i=monitors.begin(); i!=monitors.end(); ++i) if(&*i==mode->monitor) - i->current_mode = mode; + i->current_settings.mode = mode; } bool Display::process_events() diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp index a48f3f8..ba8d253 100644 --- a/source/graphics/x11/display.cpp +++ b/source/graphics/x11/display.cpp @@ -63,9 +63,9 @@ inline Rotation rotation_to_sys(Msp::Graphics::VideoRotation r) inline bool monitor_x_compare(const Msp::Graphics::Monitor &m1, const Msp::Graphics::Monitor &m2) { - if(m1.desktop_mode && !m2.desktop_mode) + if(m1.desktop_settings.mode && !m2.desktop_settings.mode) return true; - return m1.xrotation); - monitor.current_rotation = monitor.desktop_rotation; - monitor.x = crtc->x; - monitor.y = crtc->y; + monitor.desktop_settings.rotation = rotation_from_sys(crtc->rotation); + monitor.desktop_settings.x = crtc->x; + monitor.desktop_settings.y = crtc->y; } if(res->outputs[i]==primary) @@ -184,12 +183,11 @@ Display::Display(const string &disp_name): monitor.video_modes.push_back(&modes.back()); if(crtc && info->id==crtc->mode) - { - monitor.desktop_mode = &modes.back(); - monitor.current_mode = monitor.desktop_mode; - } + monitor.desktop_settings.mode = &modes.back(); } + monitor.current_settings = monitor.desktop_settings; + XRRFreeOutputInfo(output); if(crtc) XRRFreeCrtcInfo(crtc); @@ -200,7 +198,7 @@ Display::Display(const string &disp_name): monitors.sort(monitor_x_compare); Monitor *prev_enabled = 0; for(list::iterator i=monitors.begin(); i!=monitors.end(); ++i) - if(i->desktop_mode) + if(i->desktop_settings.mode) { i->next_left = prev_enabled; if(prev_enabled) @@ -208,14 +206,14 @@ Display::Display(const string &disp_name): prev_enabled = &*i; } - if(!primary_monitor || !primary_monitor->desktop_mode) + if(!primary_monitor || !primary_monitor->desktop_settings.mode) { // XRandR didn't give a sensible primary monitor. Try to guess one. unsigned largest = 0; for(list::iterator i=monitors.begin(); i!=monitors.end(); ++i) - if(i->desktop_mode) + if(const VideoMode *desktop_mode = i->desktop_settings.mode) { - unsigned size = i->desktop_mode->width*i->desktop_mode->height; + unsigned size = desktop_mode->width*desktop_mode->height; if(size>largest) { largest = size; @@ -244,7 +242,7 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) VideoRotation requested_rotation = requested_mode.rotation; if(requested_rotation==ROTATE_ANY) - requested_rotation = mode->monitor->desktop_rotation; + requested_rotation = mode->monitor->desktop_settings.rotation; XRRScreenResources *res = XRRGetScreenResources(priv->display, priv->root_window); RROutput output = priv->monitors[mode->monitor->index]; @@ -289,22 +287,23 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, 0, 0, 0, RR_Rotate_0, 0, 0); XRRFreeOutputInfo(o); - i->current_mode = 0; - i->current_rotation = ROTATE_NORMAL; - i->x = 0; - i->y = 0; + i->current_settings.mode = 0; + i->current_settings.rotation = ROTATE_NORMAL; + i->current_settings.x = 0; + i->current_settings.y = 0; } } else { const Monitor *left = mode->monitor->next_left; - while(left && !left->current_mode) + while(left && !left->current_settings.mode) left = left->next_left; if(left) { - x = left->x+mode_width(*left->current_mode, left->current_rotation); - y = left->y; + const Monitor::Settings &cs = left->current_settings; + x = cs.x+mode_width(*cs.mode, cs.rotation); + y = cs.y; } } @@ -314,10 +313,10 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) for(i=monitors.begin(); i!=monitors.end(); ++i) if(&*i==mode->monitor) { - i->current_mode = mode; - i->current_rotation = requested_rotation; - i->x = x; - i->y = y; + i->current_settings.mode = mode; + i->current_settings.rotation = requested_rotation; + i->current_settings.x = x; + i->current_settings.y = y; x += mode_width(*mode, requested_rotation); ++i; @@ -325,17 +324,17 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) } for(; i!=monitors.end(); ++i) - if(i->current_mode) + if(i->current_settings.mode) { XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i->index]); - XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, x, y, priv->modes[i->current_mode->index], rotation_to_sys(i->current_rotation), &priv->monitors[i->index], 1); + XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, x, y, priv->modes[i->current_settings.mode->index], rotation_to_sys(i->current_settings.rotation), &priv->monitors[i->index], 1); XRRPanning panning; panning.timestamp = CurrentTime; panning.left = x; panning.top = y; - panning.width = i->current_mode->width; - panning.height = i->current_mode->height; + panning.width = i->current_settings.mode->width; + panning.height = i->current_settings.mode->height; panning.track_left = panning.left; panning.track_top = panning.top; panning.track_width = panning.width; @@ -348,10 +347,10 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) XRRFreeOutputInfo(o); - i->x = x; - i->y = y; + i->current_settings.x = x; + i->current_settings.y = y; - x += mode_width(*i->current_mode, i->current_rotation); + x += mode_width(*i->current_settings.mode, i->current_settings.rotation); } XRRFreeOutputInfo(output_info); -- 2.43.0 From 171f2b47008522ad7e950dc67447a08406f4888d Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 17 Sep 2016 00:43:15 +0300 Subject: [PATCH 03/16] Remove names from unused parameters --- source/graphics/cgl/glcontext.cpp | 2 +- source/graphics/wgl/glcontext.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/graphics/cgl/glcontext.cpp b/source/graphics/cgl/glcontext.cpp index 748b9b1..4d51052 100644 --- a/source/graphics/cgl/glcontext.cpp +++ b/source/graphics/cgl/glcontext.cpp @@ -72,7 +72,7 @@ void GLContext::swap_buffers() flush_gl_buffer(priv->context); } -void GLContext::window_resized(unsigned w, unsigned h) +void GLContext::window_resized(unsigned, unsigned) { // XXX Call [context update] here? } diff --git a/source/graphics/wgl/glcontext.cpp b/source/graphics/wgl/glcontext.cpp index b6b2c5f..844f7a7 100644 --- a/source/graphics/wgl/glcontext.cpp +++ b/source/graphics/wgl/glcontext.cpp @@ -60,7 +60,7 @@ void GLContext::swap_buffers() ReleaseDC(window.get_private().window, dc); } -void GLContext::window_resized(unsigned w, unsigned h) +void GLContext::window_resized(unsigned, unsigned) { } } // namespace Graphics -- 2.43.0 From 35d4d400521d30d84c20cd1434626e131cbf9304 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 17 Sep 2016 02:00:36 +0300 Subject: [PATCH 04/16] Retain monitor positions when setting non-exclusive modes Trying to rearrange the monitors was a stupid idea, as it can easily mess up the user's configuration. --- source/graphics/x11/display.cpp | 72 +++++++-------------------------- 1 file changed, 15 insertions(+), 57 deletions(-) diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp index ba8d253..972cc82 100644 --- a/source/graphics/x11/display.cpp +++ b/source/graphics/x11/display.cpp @@ -273,11 +273,17 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) } } - int x = 0; - int y = 0; + /* Due to the semantics of find_mode, the mode's monitor pointer must point + to one of the elements of the monitors list, which is non-const here. */ + Monitor *monitor = const_cast(mode->monitor); if(exclusive) { + monitor->current_settings.mode = mode; + monitor->current_settings.rotation = requested_rotation; + monitor->current_settings.x = 0; + monitor->current_settings.y = 0; + // Disable other outputs for exclusive mode for(list::iterator i=monitors.begin(); i!=monitors.end(); ++i) if(&*i!=mode->monitor) @@ -295,63 +301,15 @@ void Display::set_mode(const VideoMode &requested_mode, bool exclusive) } else { - const Monitor *left = mode->monitor->next_left; - while(left && !left->current_settings.mode) - left = left->next_left; - - if(left) - { - const Monitor::Settings &cs = left->current_settings; - x = cs.x+mode_width(*cs.mode, cs.rotation); - y = cs.y; - } + monitor->current_settings.x = monitor->desktop_settings.x; + monitor->current_settings.y = monitor->desktop_settings.y; } - XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, x, y, priv->modes[mode->index], rotation_to_sys(requested_rotation), &output, 1); - - list::iterator i; - for(i=monitors.begin(); i!=monitors.end(); ++i) - if(&*i==mode->monitor) - { - i->current_settings.mode = mode; - i->current_settings.rotation = requested_rotation; - i->current_settings.x = x; - i->current_settings.y = y; - - x += mode_width(*mode, requested_rotation); - ++i; - break; - } - - for(; i!=monitors.end(); ++i) - if(i->current_settings.mode) - { - XRROutputInfo *o = XRRGetOutputInfo(priv->display, res, priv->monitors[i->index]); - XRRSetCrtcConfig(priv->display, res, o->crtc, CurrentTime, x, y, priv->modes[i->current_settings.mode->index], rotation_to_sys(i->current_settings.rotation), &priv->monitors[i->index], 1); - - XRRPanning panning; - panning.timestamp = CurrentTime; - panning.left = x; - panning.top = y; - panning.width = i->current_settings.mode->width; - panning.height = i->current_settings.mode->height; - panning.track_left = panning.left; - panning.track_top = panning.top; - panning.track_width = panning.width; - panning.track_height = panning.height; - panning.border_left = 0; - panning.border_top = 0; - panning.border_right = 0; - panning.border_bottom = 0; - XRRSetPanning(priv->display, res, o->crtc, &panning); - - XRRFreeOutputInfo(o); - - i->current_settings.x = x; - i->current_settings.y = y; - - x += mode_width(*i->current_settings.mode, i->current_settings.rotation); - } + RRMode mode_id = priv->modes[mode->index]; + int x = monitor->current_settings.x; + int y = monitor->current_settings.y; + Rotation sys_rot = rotation_to_sys(requested_rotation); + XRRSetCrtcConfig(priv->display, res, crtc, CurrentTime, x, y, mode_id, sys_rot, &output, 1); XRRFreeOutputInfo(output_info); XRRFreeCrtcInfo(crtc_info); -- 2.43.0 From 95480fceabec2dd6354b87a200b4a219b39d4f0a Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 17 Sep 2016 02:08:45 +0300 Subject: [PATCH 05/16] Implement additional fullscreen options for Window --- source/graphics/window.cpp | 9 +++++++-- source/graphics/window.h | 3 +++ source/graphics/x11/window.cpp | 12 ++++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/source/graphics/window.cpp b/source/graphics/window.cpp index 958667e..d27f41f 100644 --- a/source/graphics/window.cpp +++ b/source/graphics/window.cpp @@ -15,6 +15,8 @@ WindowOptions::WindowOptions(): width(640), height(480), fullscreen(false), + fullscreen_monitor(0), + fullscreen_exclusive(true), resizable(false) { } @@ -90,11 +92,14 @@ void Window::reconfigure(const WindowOptions &opts) void Window::set_fullscreen_mode() { + if(!options.fullscreen_monitor) + options.fullscreen_monitor = display.get_desktop_mode().monitor; VideoMode mode(options.width, options.height); - mode.rotation = display.get_desktop_mode().monitor->desktop_settings.rotation; + mode.monitor = options.fullscreen_monitor; + mode.rotation = mode.monitor->desktop_settings.rotation; if(mode.rotation==ROTATE_LEFT || mode.rotation==ROTATE_RIGHT) swap(mode.width, mode.height); - display.set_mode(mode, true); + display.set_mode(mode, options.fullscreen_exclusive); } void Window::set_keyboard_autorepeat(bool r) diff --git a/source/graphics/window.h b/source/graphics/window.h index 443cac7..b9a50fe 100644 --- a/source/graphics/window.h +++ b/source/graphics/window.h @@ -8,6 +8,7 @@ namespace Msp { namespace Graphics { class Display; +class Monitor; struct WindowOptions { @@ -17,6 +18,8 @@ struct WindowOptions unsigned width; unsigned height; bool fullscreen; + const Monitor *fullscreen_monitor; + bool fullscreen_exclusive; bool resizable; WindowOptions(); diff --git a/source/graphics/x11/window.cpp b/source/graphics/x11/window.cpp index 7513d3f..07ff755 100644 --- a/source/graphics/x11/window.cpp +++ b/source/graphics/x11/window.cpp @@ -111,7 +111,15 @@ void Window::platform_reconfigure(bool fullscreen_changed) XSetWMNormalHints(dpy, priv->window, &hints); if(options.fullscreen) - XMoveResizeWindow(dpy, priv->window, 0, 0, options.width, options.height); + { + if(options.fullscreen_exclusive) + XMoveResizeWindow(dpy, priv->window, 0, 0, options.width, options.height); + else + { + const Monitor::Settings &ms = options.fullscreen_monitor->current_settings; + XMoveResizeWindow(dpy, priv->window, ms.x, ms.y, options.width, options.height); + } + } else if(options.user_position) XMoveResizeWindow(dpy, priv->window, options.x, options.y, options.width, options.height); else @@ -244,7 +252,7 @@ bool Window::event(const Event &evnt) XSetInputFocus(display.get_private().display, priv->window, RevertToParent, CurrentTime); break; case MapNotify: - if(options.fullscreen) + if(options.fullscreen && options.fullscreen_exclusive) XGrabPointer(display.get_private().display, priv->window, true, None, GrabModeAsync, GrabModeAsync, priv->window, None, CurrentTime); break; case Expose: -- 2.43.0 From 39aba31df0b4ed2ae600e966c233bdeec721dc44 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 17 Sep 2016 18:47:36 +0300 Subject: [PATCH 06/16] Paint the window in WM_PAINT Failing to do so will result the application in getting stuck in the event loop. --- source/graphics/windows/window.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/graphics/windows/window.cpp b/source/graphics/windows/window.cpp index c6aab7d..cc36472 100644 --- a/source/graphics/windows/window.cpp +++ b/source/graphics/windows/window.cpp @@ -199,6 +199,10 @@ bool Window::event(const Event &evnt) unsigned width = update_rect.right-update_rect.left; unsigned height = update_rect.bottom-update_rect.top; signal_expose.emit(update_rect.left, update_rect.top, width, height, evnt); + + PAINTSTRUCT paint; + if(BeginPaint(priv->window, &paint)) + EndPaint(priv->window, &paint); } break; case WM_SETFOCUS: -- 2.43.0 From 971d9f711244232c991d77e09b2d801eba8e6d1a Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 19 Sep 2016 20:32:22 +0300 Subject: [PATCH 07/16] Add focus events to the event test program --- examples/ev.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/examples/ev.cpp b/examples/ev.cpp index 8029df2..cc15e71 100644 --- a/examples/ev.cpp +++ b/examples/ev.cpp @@ -23,6 +23,8 @@ public: private: virtual void tick(); + void got_focus(); + void lost_focus(); void key_press(unsigned); void key_release(unsigned); void character(StringCodec::unichar); @@ -36,6 +38,8 @@ Ev::Ev(int, char **): keyboard(window), mouse(window) { + window.get_display().signal_got_focus.connect(sigc::mem_fun(this, &Ev::got_focus)); + window.get_display().signal_lost_focus.connect(sigc::mem_fun(this, &Ev::lost_focus)); window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Ev::exit), 0)); keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::key_press), false)); keyboard.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::key_release), false)); @@ -53,6 +57,16 @@ void Ev::tick() Time::sleep(Time::msec); } +void Ev::got_focus() +{ + IO::print("got_focus\n"); +} + +void Ev::lost_focus() +{ + IO::print("lost_focus\n"); +} + void Ev::key_press(unsigned key) { IO::print("key_press: %s\n", keyboard.get_button_name(key)); -- 2.43.0 From bb50090c6cd069832ba06772e3387639fe4dca6e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 19 Sep 2016 20:32:45 +0300 Subject: [PATCH 08/16] Add touchscreen and gestures to the event test program --- examples/ev.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/examples/ev.cpp b/examples/ev.cpp index cc15e71..1c4e59c 100644 --- a/examples/ev.cpp +++ b/examples/ev.cpp @@ -1,7 +1,9 @@ #include #include +#include #include #include +#include #include #include #include @@ -16,9 +18,12 @@ private: Graphics::SimpleWindow window; Input::Keyboard keyboard; Input::Mouse mouse; + Input::Touchscreen *touch; + Input::GestureDetector *gesture; public: Ev(int, char **); + ~Ev(); private: virtual void tick(); @@ -31,12 +36,20 @@ private: void button_press(unsigned); void button_release(unsigned); void axis_motion(unsigned, float, float); + void touch_press(unsigned); + void touch_release(unsigned); + void touch_motion(unsigned, float, float); + void gesture_started(unsigned); + void gesture_ended(unsigned); + void gesture_axis(unsigned, float, float); }; Ev::Ev(int, char **): window(200, 200), keyboard(window), - mouse(window) + mouse(window), + touch(0), + gesture(0) { window.get_display().signal_got_focus.connect(sigc::mem_fun(this, &Ev::got_focus)); window.get_display().signal_lost_focus.connect(sigc::mem_fun(this, &Ev::lost_focus)); @@ -47,10 +60,27 @@ Ev::Ev(int, char **): mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::button_press), false)); mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::button_release), false)); mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::axis_motion), false)); + if(Input::Touchscreen::is_available()) + { + touch = new Input::Touchscreen(window); + gesture = new Input::GestureDetector(*touch); + touch->signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::touch_press), false)); + touch->signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::touch_release), false)); + touch->signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::touch_motion), false)); + gesture->signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::gesture_started), false)); + gesture->signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::gesture_ended), false)); + gesture->signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Ev::gesture_axis), false)); + } window.set_title("Event tester"); window.show(); } +Ev::~Ev() +{ + delete gesture; + delete touch; +} + void Ev::tick() { window.tick(); @@ -96,3 +126,33 @@ void Ev::axis_motion(unsigned axis, float value, float rel) { IO::print("axis_motion: %s %.3f %+.3f\n", mouse.get_axis_name(axis), value, rel); } + +void Ev::touch_press(unsigned btn) +{ + IO::print("touch_press: %s\n", touch->get_button_name(btn)); +} + +void Ev::touch_release(unsigned btn) +{ + IO::print("touch_release: %s\n", touch->get_button_name(btn)); +} + +void Ev::touch_motion(unsigned axis, float value, float rel) +{ + IO::print("touch_motion: %s %.3f %+.3f\n", touch->get_axis_name(axis), value, rel); +} + +void Ev::gesture_started(unsigned type) +{ + IO::print("gesture_started: %s\n", gesture->get_button_name(type)); +} + +void Ev::gesture_ended(unsigned type) +{ + IO::print("gesture_ended: %s\n", gesture->get_button_name(type)); +} + +void Ev::gesture_axis(unsigned axis, float value, float rel) +{ + IO::print("gesture_axis: %s %.3f %.3f\n", gesture->get_axis_name(axis), value, rel); +} -- 2.43.0 From ab03781d9d893bb50a1947cbef6ef2c35ae10d16 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 19 Sep 2016 20:51:32 +0300 Subject: [PATCH 09/16] Tweak GestureDetector button and axis names Tap gesture buttons were missing names and the progress axis was outdated. --- source/input/gesturedetector.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/input/gesturedetector.cpp b/source/input/gesturedetector.cpp index 49ddba2..145262a 100644 --- a/source/input/gesturedetector.cpp +++ b/source/input/gesturedetector.cpp @@ -28,7 +28,11 @@ GestureDetector::GestureDetector(Touchscreen &ts): string GestureDetector::get_button_name(unsigned btn) const { - if(btn==GESTURE_DRAG) + if(btn==GESTURE_TAP) + return "Tap"; + else if(btn==GESTURE_TAP_2) + return "Two-finger tap"; + else if(btn==GESTURE_DRAG) return "Drag"; else if(btn==GESTURE_DRAG_2) return "Two-finger drag"; @@ -47,7 +51,9 @@ string GestureDetector::get_axis_name(unsigned axis) const else if(axis==1) return "Y"; else if(axis==2) - return "Progress"; + return "Delta X"; + else if(axis==3) + return "Delta Y"; else return Device::get_axis_name(axis); } -- 2.43.0 From 598786409491a119ba761eca53c5eb2d94a4d9e8 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 19 Sep 2016 23:30:14 +0300 Subject: [PATCH 10/16] Refactor GestureDetector logic Active_points only ever had the one or two bottom bits set and always matched current gesture. It's simpler to just use the number of points for the gesture. --- source/input/gesturedetector.cpp | 83 ++++++++++++++++++-------------- source/input/gesturedetector.h | 5 +- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/source/input/gesturedetector.cpp b/source/input/gesturedetector.cpp index 145262a..26968c0 100644 --- a/source/input/gesturedetector.cpp +++ b/source/input/gesturedetector.cpp @@ -12,7 +12,6 @@ namespace Input { GestureDetector::GestureDetector(Touchscreen &ts): touchscreen(ts), current_gesture(GESTURE_NONE), - active_points(0), pending_tap(GESTURE_NONE), invalid_gesture(false) { @@ -90,7 +89,7 @@ void GestureDetector::touch_up(unsigned btn) p.y += p.down_y; p.down = false; - if(active_points&(1<((pending_tap-GESTURE_TAP)+1, MAX_POINTS); - set_gesture_location((1<2*abs(p.x*p2.y-p.y*p2.x)) // If both points moved in the same direction, it's a two-finger drag. current_gesture = GESTURE_DRAG_2; - - if(current_gesture!=GESTURE_NONE) - active_points = 3; } else - { current_gesture = GESTURE_DRAG; - active_points = 1; - } - if(current_gesture!=GESTURE_NONE) { - set_gesture_location(active_points); + set_gesture_location(gesture_points(current_gesture)); update_progress(); set_button_state(current_gesture, true, true); } @@ -196,40 +187,41 @@ void GestureDetector::start_gesture() invalid_gesture = true; } -void GestureDetector::set_gesture_location(unsigned mask) +void GestureDetector::set_gesture_location(unsigned n_points) { float x = 0; float y = 0; - unsigned count = 0; - for(unsigned i=0; i=GESTURE_DRAG && current_gesture<=GESTURE_DRAG_2) + set_gesture_delta(gesture_points(current_gesture)); else if(current_gesture==GESTURE_PINCH || current_gesture==GESTURE_ROTATE) { + TouchPoint &p = points[0]; TouchPoint &p2 = points[1]; /* Pinch progress is the ratio between the current distance of the points and their distance when they were pressed. */ @@ -255,7 +247,6 @@ void GestureDetector::end_gesture() set_button_state(current_gesture, false, true); set_axis_value(2, 0, false); current_gesture = GESTURE_NONE; - active_points = 0; pending_tap = GESTURE_NONE; } @@ -275,5 +266,23 @@ GestureDetector::TouchPoint::TouchPoint(): threshold_exceeded(false) { } + +unsigned gesture_points(Gesture gesture) +{ + switch(gesture) + { + case GESTURE_NONE: return 0; + case GESTURE_TAP: return 1; + case GESTURE_TAP_2: return 2; + case GESTURE_TAP_3: return 3; + case GESTURE_DRAG: return 1; + case GESTURE_DRAG_2: return 2; + case GESTURE_DRAG_3: return 3; + case GESTURE_PINCH: return 2; + case GESTURE_ROTATE: return 2; + default: throw invalid_argument("gesture_points"); + } +} + } // namespace Input } // namespace Msp diff --git a/source/input/gesturedetector.h b/source/input/gesturedetector.h index a6186fd..f39fdce 100644 --- a/source/input/gesturedetector.h +++ b/source/input/gesturedetector.h @@ -48,7 +48,6 @@ private: Touchscreen &touchscreen; TouchPoint points[MAX_POINTS]; Gesture current_gesture; - unsigned active_points; Gesture pending_tap; bool invalid_gesture; float threshold_x_sq; @@ -66,11 +65,15 @@ private: void touch_move(unsigned, float, float); void start_gesture(); void set_gesture_location(unsigned); + void set_gesture_delta(unsigned); void update_progress(); void end_gesture(); void window_resized(unsigned, unsigned); }; + +unsigned gesture_points(Gesture); + } // namespace Input } // namespace Msp -- 2.43.0 From 301e09d687a1217130fbb2240b7a80f1a00aacdc Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 19 Sep 2016 23:31:45 +0300 Subject: [PATCH 11/16] Implement three-finger tap and drag gestures --- source/input/gesturedetector.cpp | 24 ++++++++++++++++++++++-- source/input/gesturedetector.h | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/source/input/gesturedetector.cpp b/source/input/gesturedetector.cpp index 26968c0..62ac3f0 100644 --- a/source/input/gesturedetector.cpp +++ b/source/input/gesturedetector.cpp @@ -31,10 +31,14 @@ string GestureDetector::get_button_name(unsigned btn) const return "Tap"; else if(btn==GESTURE_TAP_2) return "Two-finger tap"; + else if(btn==GESTURE_TAP_3) + return "Three-finger tap"; else if(btn==GESTURE_DRAG) return "Drag"; else if(btn==GESTURE_DRAG_2) return "Two-finger drag"; + else if(btn==GESTURE_DRAG_3) + return "Three-finger drag"; else if(btn==GESTURE_PINCH) return "Pinch"; else if(btn==GESTURE_ROTATE) @@ -76,6 +80,8 @@ void GestureDetector::touch_down(unsigned btn) pending_tap = GESTURE_TAP; else if(btn==1) pending_tap = GESTURE_TAP_2; + else if(btn==2) + pending_tap = GESTURE_TAP_3; } } @@ -153,7 +159,21 @@ void GestureDetector::start_gesture() return; invalid_gesture = false; - if(points[1].down) + if(points[2].down) + { + bool same_direction = true; + for(unsigned i=0; (same_direction && i<2); ++i) + for(unsigned j=i+1; (same_direction && j<3); ++j) + { + TouchPoint &pi = points[i]; + TouchPoint &pj = points[j]; + same_direction = ((pi.x*pj.x+pi.y*pj.y)>2*abs(pi.x*pj.y-pi.y*pj.x)); + } + + if(same_direction) + current_gesture = GESTURE_DRAG_3; + } + else if(points[1].down) { TouchPoint &p2 = points[1]; float ddx = p.down_x-p2.down_x; @@ -217,7 +237,7 @@ void GestureDetector::set_gesture_delta(unsigned n_points) void GestureDetector::update_progress() { - if(current_gesture>=GESTURE_DRAG && current_gesture<=GESTURE_DRAG_2) + if(current_gesture>=GESTURE_DRAG && current_gesture<=GESTURE_DRAG_3) set_gesture_delta(gesture_points(current_gesture)); else if(current_gesture==GESTURE_PINCH || current_gesture==GESTURE_ROTATE) { diff --git a/source/input/gesturedetector.h b/source/input/gesturedetector.h index f39fdce..51af312 100644 --- a/source/input/gesturedetector.h +++ b/source/input/gesturedetector.h @@ -13,8 +13,10 @@ enum Gesture GESTURE_NONE, GESTURE_TAP, GESTURE_TAP_2, + GESTURE_TAP_3, GESTURE_DRAG, GESTURE_DRAG_2, + GESTURE_DRAG_3, GESTURE_PINCH, GESTURE_ROTATE }; -- 2.43.0 From 0c815f73032aa6006647aff94b5498ac9d1e859b Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 19 Sep 2016 23:36:51 +0300 Subject: [PATCH 12/16] Fix GameController multiple inclusion guards --- source/input/gamecontroller.h | 4 ++-- source/input/linux/gamecontroller_platform.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/input/gamecontroller.h b/source/input/gamecontroller.h index 5aaa631..84c50b5 100644 --- a/source/input/gamecontroller.h +++ b/source/input/gamecontroller.h @@ -1,5 +1,5 @@ -#ifndef GAMECONTROLLER_H_ -#define GAMECONTROLLER_H_ +#ifndef MSP_INPUT_GAMECONTROLLER_H_ +#define MSP_INPUT_GAMECONTROLLER_H_ #include #include diff --git a/source/input/linux/gamecontroller_platform.h b/source/input/linux/gamecontroller_platform.h index 517b1b0..cd63839 100644 --- a/source/input/linux/gamecontroller_platform.h +++ b/source/input/linux/gamecontroller_platform.h @@ -1,5 +1,5 @@ -#ifndef GAMECONTROLLER_PRIVATE_H_ -#define GAMECONTROLLER_PRIVATE_H_ +#ifndef MSP_INPUT_GAMECONTROLLER_PLATFORM_H_ +#define MSP_INPUT_GAMECONTROLLER_PLATFORM_H_ #include #include -- 2.43.0 From 7262f1e7e9ea88a021c14de9dc06ebe76112afd7 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 19 Sep 2016 23:39:14 +0300 Subject: [PATCH 13/16] Enumerate available game controllers Assign indices from zero to N-1 internally. This makes it easier for applications to use game controllers as the first available controller will always have index zero. --- source/input/gamecontroller.cpp | 18 ++++++++++++++ source/input/gamecontroller.h | 6 +++++ source/input/generic/gamecontroller.cpp | 6 +++++ source/input/linux/gamecontroller.cpp | 26 +++++++++++++++++++- source/input/linux/gamecontroller_platform.h | 2 ++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 source/input/gamecontroller.cpp diff --git a/source/input/gamecontroller.cpp b/source/input/gamecontroller.cpp new file mode 100644 index 0000000..1ad8757 --- /dev/null +++ b/source/input/gamecontroller.cpp @@ -0,0 +1,18 @@ +#include "gamecontroller.h" + +namespace Msp { +namespace Input { + +bool GameController::detect_done = false; +unsigned GameController::n_detected_controllers = 0; + +bool GameController::is_available(unsigned index) +{ + if(!detect_done) + detect(); + + return index #include #include +#include #include #include #include "gamecontroller.h" @@ -11,10 +12,17 @@ using namespace std; namespace Msp { namespace Input { +vector GameController::Private::detected_controllers; + GameController::GameController(unsigned index): event_disp(0) { - JsDevice *device = new JsDevice(format("/dev/input/js%d", index)); + if(!detect_done) + detect(); + if(index>=Private::detected_controllers.size()) + throw device_not_available(format("GameController(%d)", index)); + + JsDevice *device = new JsDevice(Private::detected_controllers[index]); priv = new Private; priv->dev = device; @@ -29,6 +37,22 @@ GameController::~GameController() delete priv; } +unsigned GameController::detect() +{ + Private::detected_controllers.clear(); + + FS::Path dev_input = "/dev/input"; + list devices = FS::list_filtered(dev_input, "^js[0-9]+"); + for(list::const_iterator i=devices.begin(); i!=devices.end(); ++i) + // TODO check permissions + Private::detected_controllers.push_back((dev_input / *i).str()); + + detect_done = true; + n_detected_controllers = Private::detected_controllers.size(); + + return Private::detected_controllers.size(); +} + void GameController::use_event_dispatcher(IO::EventDispatcher *ed) { if(event_disp) diff --git a/source/input/linux/gamecontroller_platform.h b/source/input/linux/gamecontroller_platform.h index cd63839..2951076 100644 --- a/source/input/linux/gamecontroller_platform.h +++ b/source/input/linux/gamecontroller_platform.h @@ -30,6 +30,8 @@ public: struct GameController::Private { JsDevice *dev; + + static std::vector detected_controllers; }; } // namespace Input -- 2.43.0 From 130d5570e08c32d9db9d3e5324c2c8e99d1cdb02 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 20 Sep 2016 11:14:07 +0300 Subject: [PATCH 14/16] Implement game controllers on Windows through XInput --- Build | 1 + source/input/windows/gamecontroller.cpp | 188 ++++++++++++++++++ .../input/windows/gamecontroller_platform.h | 52 +++++ 3 files changed, 241 insertions(+) create mode 100644 source/input/windows/gamecontroller.cpp create mode 100644 source/input/windows/gamecontroller_platform.h diff --git a/Build b/Build index 69d9b6b..d9d7fc7 100644 --- a/Build +++ b/Build @@ -14,6 +14,7 @@ package "mspgui" build_info { library "gdi32"; + library "xinput"; }; }; if_arch "darwin" diff --git a/source/input/windows/gamecontroller.cpp b/source/input/windows/gamecontroller.cpp new file mode 100644 index 0000000..43a947b --- /dev/null +++ b/source/input/windows/gamecontroller.cpp @@ -0,0 +1,188 @@ +#include +#include +#include "gamecontroller.h" +#include "gamecontroller_platform.h" + +using namespace std; + +namespace Msp { +namespace Input { + +vector GameController::Private::detected_controllers; + +GameController::GameController(unsigned index) +{ + if(!detect_done) + detect(); + if(index>=Private::detected_controllers.size()) + throw device_not_available(format("GameController(%d)", index)); + + unsigned user_index = Private::detected_controllers[index]; + + XINPUT_STATE state; + DWORD err = XInputGetState(user_index, &state); + if(err!=ERROR_SUCCESS) + throw device_not_available(format("GameController(%d)", index)); + + priv = new Private; + priv->index = user_index; + priv->update_state(*this, state, false); + + name = format("Controller %d", user_index); +} + +GameController::~GameController() +{ + use_event_dispatcher(0); + + delete priv; +} + +unsigned GameController::detect() +{ + Private::detected_controllers.clear(); + + XINPUT_STATE state; + for(unsigned i=0; iremove(*priv->event_pipe); + + event_disp = ed; + if(event_disp) + { + if(!priv->event_pipe) + { + priv->event_pipe = new IO::Pipe; + priv->event_pipe->signal_data_available.connect(sigc::mem_fun(this, static_cast(&GameController::tick))); + priv->timer_slot = &GameControllerTimerThread::add_slot(); + priv->timer_slot->signal_timeout.connect(sigc::mem_fun(priv, &Private::generate_event)); + } + + event_disp->add(*priv->event_pipe); + } + else if(priv->event_pipe) + { + GameControllerTimerThread::remove_slot(*priv->timer_slot); + priv->timer_slot = 0; + delete priv->event_pipe; + priv->event_pipe = 0; + } +} + +void GameController::tick() +{ + if(priv->event_pipe) + { + char buf[64]; + priv->event_pipe->read(buf, sizeof(buf)); + } + + XINPUT_STATE state; + DWORD err = XInputGetState(priv->index, &state); + if(err==ERROR_SUCCESS) + priv->update_state(*this, state, true); +} + +void GameController::tick(const Time::TimeDelta &) +{ + tick(); +} + + +GameController::Private::Private(): + index(0), + last_packet_number(0), + event_pipe(0), + timer_slot(0) +{ } + +bool GameController::Private::generate_event() +{ + event_pipe->put(1); + return true; +} + +void GameController::Private::update_state(GameController &ctrl, const XINPUT_STATE &state, bool event) +{ + if(state.dwPacketNumber==last_packet_number) + return; + last_packet_number = state.dwPacketNumber; + + ctrl.set_axis_value(0, state.Gamepad.sThumbLX/32768.0, event); + ctrl.set_axis_value(1, -state.Gamepad.sThumbLY/32768.0, event); + ctrl.set_axis_value(3, state.Gamepad.sThumbRX/32768.0, event); + ctrl.set_axis_value(4, -state.Gamepad.sThumbRY/32768.0, event); + WORD dpad_x = state.Gamepad.wButtons&(XINPUT_GAMEPAD_DPAD_LEFT|XINPUT_GAMEPAD_DPAD_RIGHT); + WORD dpad_y = state.Gamepad.wButtons&(XINPUT_GAMEPAD_DPAD_UP|XINPUT_GAMEPAD_DPAD_DOWN); + ctrl.set_axis_value(6, (dpad_x==XINPUT_GAMEPAD_DPAD_LEFT ? -1 : dpad_x==XINPUT_GAMEPAD_DPAD_RIGHT ? 1 : 0), event); + ctrl.set_axis_value(7, (dpad_y==XINPUT_GAMEPAD_DPAD_UP ? -1 : dpad_y==XINPUT_GAMEPAD_DPAD_DOWN ? 1 : 0), event); + ctrl.set_button_state(0, state.Gamepad.wButtons&XINPUT_GAMEPAD_A, event); + ctrl.set_button_state(1, state.Gamepad.wButtons&XINPUT_GAMEPAD_B, event); + ctrl.set_button_state(2, state.Gamepad.wButtons&XINPUT_GAMEPAD_X, event); + ctrl.set_button_state(3, state.Gamepad.wButtons&XINPUT_GAMEPAD_Y, event); + ctrl.set_button_state(4, state.Gamepad.wButtons&XINPUT_GAMEPAD_LEFT_SHOULDER, event); + ctrl.set_button_state(5, state.Gamepad.wButtons&XINPUT_GAMEPAD_RIGHT_SHOULDER, event); + ctrl.set_button_state(6, state.Gamepad.wButtons&XINPUT_GAMEPAD_BACK, event); + ctrl.set_button_state(7, state.Gamepad.wButtons&XINPUT_GAMEPAD_START, event); + ctrl.set_button_state(8, state.Gamepad.wButtons&XINPUT_GAMEPAD_LEFT_THUMB, event); + ctrl.set_button_state(9, state.Gamepad.wButtons&XINPUT_GAMEPAD_RIGHT_THUMB, event); +} + + +GameControllerTimerThread *GameControllerTimerThread::thread = 0; + +GameControllerTimerThread::GameControllerTimerThread(): + Thread("GameController"), + n_users(0) +{ + launch(); +} + +GameControllerTimerThread::~GameControllerTimerThread() +{ + timer.add(Time::zero); + join(); +} + +Time::Timer::Slot &GameControllerTimerThread::add_slot() +{ + if(!thread) + thread = new GameControllerTimerThread; + ++thread->n_users; + return thread->timer.add(100*Time::msec); +} + +void GameControllerTimerThread::remove_slot(Time::Timer::Slot &slot) +{ + thread->timer.cancel(slot); + if(!--thread->n_users) + { + thread->timer.add(Time::zero); + delete thread; + thread = 0; + } +} + +void GameControllerTimerThread::main() +{ + while(1) + { + timer.tick(); + if(!n_users) + break; + } +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/windows/gamecontroller_platform.h b/source/input/windows/gamecontroller_platform.h new file mode 100644 index 0000000..46c2dd8 --- /dev/null +++ b/source/input/windows/gamecontroller_platform.h @@ -0,0 +1,52 @@ +#ifndef MSP_INPUT_GAMECONTROLLER_PLATFORM_H_ +#define MSP_INPUT_GAMECONTROLLER_PLATFORM_H_ + +#include +#include +#include +#include +#include + +namespace Msp { +namespace Input { + +class GameControllerTimerThread: public Msp::Thread +{ +private: + Time::Timer timer; + unsigned n_users; + + static GameControllerTimerThread *thread; + + GameControllerTimerThread(); + ~GameControllerTimerThread(); +public: + static Time::Timer::Slot &add_slot(); + static void remove_slot(Time::Timer::Slot &); + +private: + virtual void main(); +}; + + +struct GameController::Private +{ + unsigned index; + unsigned last_packet_number; + IO::Pipe *event_pipe; + Time::Timer::Slot *timer_slot; + + static std::vector detected_controllers; + + Private(); + + bool generate_event(); + + void update_state(GameController &, const XINPUT_STATE &, bool); + +}; + +} // namespace Input +} // namespace Msp + +#endif -- 2.43.0 From 213ca43656411a06bbf1c0d18e4ebacaf545eb34 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 3 Oct 2016 00:10:01 +0300 Subject: [PATCH 15/16] Add support for swap interval control --- source/graphics/cgl/glcontext.cpp | 5 +++++ source/graphics/egl_android/glcontext.cpp | 5 +++++ source/graphics/glcontext.cpp | 3 +++ source/graphics/glcontext.h | 2 ++ source/graphics/glx/glcontext.cpp | 9 +++++++++ source/graphics/wgl/glcontext.cpp | 11 +++++++++++ 6 files changed, 35 insertions(+) diff --git a/source/graphics/cgl/glcontext.cpp b/source/graphics/cgl/glcontext.cpp index 4d51052..02c4d44 100644 --- a/source/graphics/cgl/glcontext.cpp +++ b/source/graphics/cgl/glcontext.cpp @@ -67,6 +67,11 @@ GLContext::~GLContext() delete priv; } +void GLContext::set_swap_interval(unsigned) +{ + // TODO +} + void GLContext::swap_buffers() { flush_gl_buffer(priv->context); diff --git a/source/graphics/egl_android/glcontext.cpp b/source/graphics/egl_android/glcontext.cpp index 0e98739..7853b21 100644 --- a/source/graphics/egl_android/glcontext.cpp +++ b/source/graphics/egl_android/glcontext.cpp @@ -109,6 +109,11 @@ GLContext::~GLContext() delete priv; } +void GLContext::set_swap_interval(unsigned) +{ + // TODO +} + void GLContext::swap_buffers() { eglSwapBuffers(priv->display, priv->surface); diff --git a/source/graphics/glcontext.cpp b/source/graphics/glcontext.cpp index ab0ea7a..47e1e59 100644 --- a/source/graphics/glcontext.cpp +++ b/source/graphics/glcontext.cpp @@ -41,6 +41,9 @@ void GLContext::platform_init(const GLOptions &) GLContext::~GLContext() { } +void GLContext::set_swap_interval(unsigned) +{ } + void GLContext::swap_buffers() { } diff --git a/source/graphics/glcontext.h b/source/graphics/glcontext.h index a248090..8cf75c8 100644 --- a/source/graphics/glcontext.h +++ b/source/graphics/glcontext.h @@ -44,6 +44,8 @@ private: public: ~GLContext(); + void set_swap_interval(unsigned); + void swap_buffers(); private: void window_resized(unsigned, unsigned); diff --git a/source/graphics/glx/glcontext.cpp b/source/graphics/glx/glcontext.cpp index e4662f3..46da6d1 100644 --- a/source/graphics/glx/glcontext.cpp +++ b/source/graphics/glx/glcontext.cpp @@ -84,6 +84,15 @@ GLContext::~GLContext() delete priv; } +void GLContext::set_swap_interval(unsigned i) +{ + const GLubyte *name = reinterpret_cast("glXSwapIntervalEXT"); + PFNGLXSWAPINTERVALEXTPROC func = reinterpret_cast(glXGetProcAddress(name)); + if(!func) + throw runtime_error("glXSwapIntervalEXT not found"); + func(display.get_private().display, priv->subwnd, i); +} + void GLContext::swap_buffers() { glXSwapBuffers(display.get_private().display, priv->subwnd); diff --git a/source/graphics/wgl/glcontext.cpp b/source/graphics/wgl/glcontext.cpp index 844f7a7..3df83f3 100644 --- a/source/graphics/wgl/glcontext.cpp +++ b/source/graphics/wgl/glcontext.cpp @@ -1,8 +1,11 @@ #include #include +#include #include "glcontext.h" #include "window_private.h" +using namespace std; + namespace Msp { namespace Graphics { @@ -53,6 +56,14 @@ GLContext::~GLContext() delete priv; } +void GLContext::set_swap_interval(unsigned i) +{ + PFNWGLSWAPINTERVALEXTPROC func = reinterpret_cast(wglGetProcAddress("wglSwapIntervalEXT")); + if(!func) + throw runtime_error("wglSwapIntervalEXT not found"); + func(i); +} + void GLContext::swap_buffers() { HDC dc = GetDC(window.get_private().window); -- 2.43.0 From 207eec91afc6b538753ddc44905ac9ddbc907ac0 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 8 Oct 2016 01:27:56 +0300 Subject: [PATCH 16/16] Fix a memory leak --- source/graphics/windows/display.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/graphics/windows/display.cpp b/source/graphics/windows/display.cpp index aaaa985..2364f6d 100644 --- a/source/graphics/windows/display.cpp +++ b/source/graphics/windows/display.cpp @@ -60,6 +60,7 @@ Display::Display(const string &): Display::~Display() { + delete priv; } void Display::set_mode(const VideoMode &requested_mode, bool) -- 2.43.0