From: Mikko Rasa Date: Sun, 7 Feb 2016 13:53:19 +0000 (+0200) Subject: Track the currently focused window in Display X-Git-Url: http://git.tdb.fi/?p=libs%2Fgui.git;a=commitdiff_plain;h=e15959a69551c2027029470e65a17ea5a305545b Track the currently focused window in Display On mobile platforms it's important for applications to stop rendering or otherwise using excessive amounts of CPU power when inactive. OS X code is a dummy implementation because I need more time to understand the relevant events on that platform. --- diff --git a/source/graphics/android/display.cpp b/source/graphics/android/display.cpp index 5823b91..bd2cf27 100644 --- a/source/graphics/android/display.cpp +++ b/source/graphics/android/display.cpp @@ -9,7 +9,8 @@ namespace Msp { namespace Graphics { Display::Display(const string &): - primary_monitor(0) + primary_monitor(0), + focus_window(0) { Android::MainThread *thread = reinterpret_cast(Application::get_data()); if(!thread->is_starting_up()) diff --git a/source/graphics/android/window.cpp b/source/graphics/android/window.cpp index 3a58420..be1441a 100644 --- a/source/graphics/android/window.cpp +++ b/source/graphics/android/window.cpp @@ -57,6 +57,7 @@ bool Window::event(const Event &evnt) display.remove_window(*this); display.add_window(*this); priv->signal_window_acquired.emit(priv->window); + signal_got_focus.emit(); break; case WINDOW_RESIZED: options.width = ANativeWindow_getWidth(priv->window); @@ -64,6 +65,7 @@ bool Window::event(const Event &evnt) signal_resize.emit(options.width, options.height); break; case WINDOW_DESTROYED: + signal_lost_focus.emit(); priv->signal_window_lost.emit(); priv->window = 0; display.remove_window(*this); diff --git a/source/graphics/cocoa/display.cpp b/source/graphics/cocoa/display.cpp index f5c39d8..b9ce492 100644 --- a/source/graphics/cocoa/display.cpp +++ b/source/graphics/cocoa/display.cpp @@ -10,7 +10,8 @@ namespace Graphics { Display::Display(const string &): primary_monitor(0), - priv(new Private) + priv(new Private), + focus_window(0) { static ErrorDialog err_dlg(0); diff --git a/source/graphics/cocoa/window.cpp b/source/graphics/cocoa/window.cpp index abaefe2..796e969 100644 --- a/source/graphics/cocoa/window.cpp +++ b/source/graphics/cocoa/window.cpp @@ -63,6 +63,7 @@ bool Window::event(const Event &ev) case KEY_UP: case OTHER_MOUSE_DOWN: case OTHER_MOUSE_UP: + signal_got_focus.emit(); signal_input_event.emit(ev); break; case MOUSE_MOVED: diff --git a/source/graphics/display.cpp b/source/graphics/display.cpp index 40112a3..1c7b639 100644 --- a/source/graphics/display.cpp +++ b/source/graphics/display.cpp @@ -1,4 +1,5 @@ #include +#include #include "display.h" #include "display_private.h" #include "window.h" @@ -11,11 +12,15 @@ namespace Graphics { void Display::add_window(Window &wnd) { priv->windows[wnd.get_private().window] = &wnd; + wnd.signal_got_focus.connect(sigc::bind(sigc::mem_fun(this, &Display::window_got_focus), sigc::ref(wnd))); + wnd.signal_lost_focus.connect(sigc::mem_fun(this, &Display::window_lost_focus)); } void Display::remove_window(Window &wnd) { priv->windows.erase(wnd.get_private().window); + if(&wnd==focus_window) + focus_window = 0; } const VideoMode &Display::get_desktop_mode() const @@ -66,11 +71,28 @@ const VideoMode *Display::find_mode(unsigned width, unsigned height) const return find_mode(VideoMode(width, height)); } +void Display::window_got_focus(Window &w) +{ + focus_window = &w; +} + +void Display::window_lost_focus() +{ + focus_window = 0; +} + void Display::tick() { check_error(); + Window *old_focus = focus_window; + while(process_events()) ; + + if(old_focus && !focus_window) + signal_lost_focus.emit(); + else if(!old_focus && focus_window) + signal_got_focus.emit(); } } // namespace Graphics diff --git a/source/graphics/display.h b/source/graphics/display.h index 9c62b51..092abbe 100644 --- a/source/graphics/display.h +++ b/source/graphics/display.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "errordialog.h" #include "monitor.h" #include "videomode.h" @@ -18,12 +19,16 @@ class Display public: struct Private; + sigc::signal signal_got_focus; + sigc::signal signal_lost_focus; + private: std::list monitors; Monitor *primary_monitor; std::list modes; Private *priv; ErrorDialog *err_dialog; + Window *focus_window; public: Display(const std::string &disp_name = std::string()); @@ -42,6 +47,13 @@ public: const VideoMode *find_mode(const VideoMode &, float = 0.5f) const; const VideoMode *find_mode(unsigned, unsigned) const; +private: + void window_got_focus(Window &); + void window_lost_focus(); +public: + Window *get_focus_window() const { return focus_window; } + +public: void tick(); private: bool process_events(); diff --git a/source/graphics/window.h b/source/graphics/window.h index 31fa248..2d4376e 100644 --- a/source/graphics/window.h +++ b/source/graphics/window.h @@ -33,6 +33,9 @@ public: objects instead. */ sigc::signal signal_input_event; + sigc::signal signal_got_focus; + sigc::signal signal_lost_focus; + sigc::signal signal_move; sigc::signal signal_resize; sigc::signal signal_expose; diff --git a/source/graphics/windows/display.cpp b/source/graphics/windows/display.cpp index b9388e3..d767beb 100644 --- a/source/graphics/windows/display.cpp +++ b/source/graphics/windows/display.cpp @@ -9,7 +9,8 @@ namespace Graphics { Display::Display(const string &): primary_monitor(0), - priv(new Private) + priv(new Private), + focus_window(0) { static ErrorDialog err_dlg(0); diff --git a/source/graphics/windows/window.cpp b/source/graphics/windows/window.cpp index 046894f..c6aab7d 100644 --- a/source/graphics/windows/window.cpp +++ b/source/graphics/windows/window.cpp @@ -201,6 +201,12 @@ bool Window::event(const Event &evnt) signal_expose.emit(update_rect.left, update_rect.top, width, height, evnt); } break; + case WM_SETFOCUS: + signal_got_focus.emit(); + break; + case WM_KILLFOCUS: + signal_lost_focus.emit(); + break; default: return false; } diff --git a/source/graphics/x11/display.cpp b/source/graphics/x11/display.cpp index 634e910..c23f46d 100644 --- a/source/graphics/x11/display.cpp +++ b/source/graphics/x11/display.cpp @@ -84,7 +84,8 @@ namespace Graphics { Display::Display(const string &disp_name): primary_monitor(0), - priv(new Private) + priv(new Private), + focus_window(0) { if(disp_name.empty()) priv->display = XOpenDisplay(0); diff --git a/source/graphics/x11/window.cpp b/source/graphics/x11/window.cpp index 52f37a3..7513d3f 100644 --- a/source/graphics/x11/window.cpp +++ b/source/graphics/x11/window.cpp @@ -32,7 +32,7 @@ void Window::platform_init() XSetWindowAttributes attr; attr.override_redirect = options.fullscreen; - attr.event_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask|ExposureMask; + attr.event_mask = ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|EnterWindowMask|ExposureMask|FocusChangeMask; priv->window = XCreateWindow(dpy, display.get_private().root_window, @@ -250,6 +250,12 @@ bool Window::event(const Event &evnt) case Expose: signal_expose.emit(ev.xexpose.x, ev.xexpose.y, ev.xexpose.width, ev.xexpose.height, evnt); break; + case FocusIn: + signal_got_focus.emit(); + break; + case FocusOut: + signal_lost_focus.emit(); + break; default: return false; }