diff options
Diffstat (limited to 'xbmc/interfaces/legacy/WindowInterceptor.h')
-rw-r--r-- | xbmc/interfaces/legacy/WindowInterceptor.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/xbmc/interfaces/legacy/WindowInterceptor.h b/xbmc/interfaces/legacy/WindowInterceptor.h new file mode 100644 index 0000000..4890150 --- /dev/null +++ b/xbmc/interfaces/legacy/WindowInterceptor.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "Window.h" +#include "guilib/GUIWindow.h" + +namespace XBMCAddon +{ + namespace xbmcgui + { + +#ifndef SWIG + class Window; + class ref; + + /** + * These two classes are closely associated with the Interceptor template below. + * For more detailed explanation, see that class. + */ + class InterceptorBase + { + protected: + AddonClass::Ref<Window> window; + // This instance is in Window.cpp + static thread_local ref* upcallTls; + + InterceptorBase() : window(NULL) { upcallTls = NULL; } + + /** + * Calling up ONCE resets the upcall to to false. The reason is that when + * a call is recursive we cannot assume the ref has cleared the flag. + * so ... + * + * ref(window)->UpCall() + * + * during the context of 'UpCall' it's possible that another call will + * be made back on the window from the xbmc core side (this happens in + * sometimes in OnMessage). In that case, if upcall is still 'true', than + * the call will wrongly proceed back to the xbmc core side rather than + * to the Addon API side. + */ + static bool up() { bool ret = ((upcallTls) != NULL); upcallTls = NULL; return ret; } + public: + + virtual ~InterceptorBase() { if (window.isNotNull()) { window->interceptorClear(); } } + + virtual CGUIWindow* get() = 0; + + virtual void SetRenderOrder(int renderOrder) { } + + virtual void setActive(bool active) { } + virtual bool isActive() { return false; } + + friend class ref; + }; + + /** + * Guard class. But instead of managing memory or thread resources, + * any call made using the operator-> results in an 'upcall.' That is, + * it expects the call about to be made to have come from the XBMCAddon + * xbmcgui Window API and not from either the scripting language or the + * XBMC core Windowing system. + * + * This class is meant to hold references to instances of Interceptor<P>. + * see that template definition below. + */ + class ref + { + InterceptorBase* w; + public: + inline explicit ref(InterceptorBase* b) : w(b) { w->upcallTls = this; } + inline ~ref() { w->upcallTls = NULL; } + inline CGUIWindow* operator->() { return w->get(); } + inline CGUIWindow* get() { return w->get(); } + }; + + /** + * The intention of this class is to intercept calls from + * multiple points in the CGUIWindow class hierarchy and pass + * those calls over to the XBMCAddon API Window hierarchy. It + * is a class template that uses the type template parameter + * to determine the parent class. + * + * Since this class also maintains two way communication between + * the XBMCAddon API Window hierarchy and the core XBMC CGUIWindow + * hierarchy, it is used as a general bridge. For calls going + * TO the window hierarchy (as in callbacks) it operates in a + * straightforward manner. In the reverse direction (from the + * XBMCAddon hierarchy) it uses some hackery in a "smart pointer" + * overloaded -> operator. + */ + +#define checkedb(methcall) ( window.isNotNull() ? window-> methcall : false ) +#define checkedv(methcall) { if (window.isNotNull()) window-> methcall ; } + + template <class P /* extends CGUIWindow*/> class Interceptor : + public P, public InterceptorBase + { + std::string classname; + protected: + CGUIWindow* get() override { return this; } + + public: + Interceptor(const char* specializedName, + Window* _window, int windowid) : P(windowid, ""), + classname("Interceptor<" + std::string(specializedName) + ">") + { +#ifdef ENABLE_XBMC_TRACE_API + XBMCAddonUtils::TraceGuard tg; + CLog::Log(LOGDEBUG, "{}NEWADDON constructing {} 0x{:x}", tg.getSpaces(), classname, + (long)(((void*)this))); +#endif + window.reset(_window); + P::SetLoadType(CGUIWindow::LOAD_ON_GUI_INIT); + } + + Interceptor(const char* specializedName, + Window* _window, int windowid, + const char* xmlfile) : P(windowid, xmlfile), + classname("Interceptor<" + std::string(specializedName) + ">") + { +#ifdef ENABLE_XBMC_TRACE_API + XBMCAddonUtils::TraceGuard tg; + CLog::Log(LOGDEBUG, "{}NEWADDON constructing {} 0x{:x}", tg.getSpaces(), classname, + (long)(((void*)this))); +#endif + window.reset(_window); + P::SetLoadType(CGUIWindow::LOAD_ON_GUI_INIT); + } + +#ifdef ENABLE_XBMC_TRACE_API + ~Interceptor() override + { + XBMCAddonUtils::TraceGuard tg; + CLog::Log(LOGDEBUG, "{}NEWADDON LIFECYCLE destroying {} 0x{:x}", tg.getSpaces(), classname, + (long)(((void*)this))); + } +#else + ~Interceptor() override = default; +#endif + + bool OnMessage(CGUIMessage& message) override + { XBMC_TRACE; return up() ? P::OnMessage(message) : checkedb(OnMessage(message)); } + bool OnAction(const CAction &action) override + { XBMC_TRACE; return up() ? P::OnAction(action) : checkedb(OnAction(action)); } + + // NOTE!!: This ALWAYS skips up to the CGUIWindow instance. + bool OnBack(int actionId) override + { XBMC_TRACE; return up() ? CGUIWindow::OnBack(actionId) : checkedb(OnBack(actionId)); } + + void OnDeinitWindow(int nextWindowID) override + { XBMC_TRACE; if(up()) P::OnDeinitWindow(nextWindowID); else checkedv(OnDeinitWindow(nextWindowID)); } + + bool IsModalDialog() const override + { + XBMC_TRACE; + return checkedb(IsModalDialog()); + } + + bool IsDialogRunning() const override + { + XBMC_TRACE; + return checkedb(IsDialogRunning()); + } + bool IsDialog() const override + { + XBMC_TRACE; + return checkedb(IsDialog()); + } + bool IsMediaWindow() const override + { + XBMC_TRACE; + return checkedb(IsMediaWindow()); + } + + void SetRenderOrder(int renderOrder) override { XBMC_TRACE; P::m_renderOrder = renderOrder; } + + void setActive(bool active) override { XBMC_TRACE; P::m_active = active; } + bool isActive() override { XBMC_TRACE; return P::m_active; } + }; + + template <class P /* extends CGUIWindow*/> class InterceptorDialog : + public Interceptor<P> + { + public: + InterceptorDialog(const char* specializedName, + Window* _window, int windowid) : + Interceptor<P>(specializedName, _window, windowid) + { } + + InterceptorDialog(const char* specializedName, + Window* _window, int windowid, + const char* xmlfile) : + Interceptor<P>(specializedName, _window, windowid,xmlfile) + { } + }; + +#undef checkedb +#undef checkedv + +#endif + } +} |