/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __nsMenuObject_h__ #define __nsMenuObject_h__ #include "mozilla/Attributes.h" #include "nsCOMPtr.h" #include "nsDbusmenu.h" #include "nsNativeMenuDocListener.h" class nsIAtom; class nsIContent; class nsStyleContext; class nsMenuContainer; class nsMenuObjectIconLoader; #define DBUSMENU_PROPERTIES \ DBUSMENU_PROPERTY(Label, DBUSMENU_MENUITEM_PROP_LABEL, 0) \ DBUSMENU_PROPERTY(Enabled, DBUSMENU_MENUITEM_PROP_ENABLED, 1) \ DBUSMENU_PROPERTY(Visible, DBUSMENU_MENUITEM_PROP_VISIBLE, 2) \ DBUSMENU_PROPERTY(IconData, DBUSMENU_MENUITEM_PROP_ICON_DATA, 3) \ DBUSMENU_PROPERTY(Type, DBUSMENU_MENUITEM_PROP_TYPE, 4) \ DBUSMENU_PROPERTY(Shortcut, DBUSMENU_MENUITEM_PROP_SHORTCUT, 5) \ DBUSMENU_PROPERTY(ToggleType, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, 6) \ DBUSMENU_PROPERTY(ToggleState, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, 7) \ DBUSMENU_PROPERTY(ChildDisplay, DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY, 8) /* * This is the base class for all menu nodes. Each instance represents * a single node in the menu hierarchy. It wraps the corresponding DOM node and * native menu node, keeps them in sync and transfers events between the two. * It is not reference counted - each node is owned by its parent (the top * level menubar is owned by the window) and keeps a weak pointer to its * parent (which is guaranteed to always be valid because a node will never * outlive its parent). It is not safe to keep a reference to nsMenuObject * externally. */ class nsMenuObject : public nsNativeMenuChangeObserver { public: enum EType { eType_MenuBar, eType_Menu, eType_MenuItem }; virtual ~nsMenuObject(); // Get the native menu item node DbusmenuMenuitem* GetNativeData() const { return mNativeData; } // Get the parent menu object nsMenuContainer* Parent() const { return mParent; } // Get the content node nsIContent* ContentNode() const { return mContent; } // Get the type of this node. Must be provided by subclasses virtual EType Type() const = 0; // Get the document listener nsNativeMenuDocListener* DocListener() const { return mListener; } // Create the native menu item node (called by containers) void CreateNativeData(); // Adopt the specified native menu item node (called by containers) nsresult AdoptNativeData(DbusmenuMenuitem* aNativeData); // Called by the container to tell us that it's opening void ContainerIsOpening(); protected: nsMenuObject(nsMenuContainer* aParent, nsIContent* aContent); nsMenuObject(nsNativeMenuDocListener* aListener, nsIContent* aContent); enum PropertyFlags { #define DBUSMENU_PROPERTY(e, s, b) eProp##e = (1 << b), DBUSMENU_PROPERTIES #undef DBUSMENU_PROPERTY }; void UpdateLabel(); void UpdateVisibility(nsStyleContext* aStyleContext); void UpdateSensitivity(); void UpdateIcon(nsStyleContext* aStyleContext); already_AddRefed GetStyleContext(); private: friend class nsMenuObjectIconLoader; // Set up initial properties on the native data, connect to signals etc. // This should be implemented by subclasses virtual void InitializeNativeData(); // Return the properties that this menu object type supports // This should be implemented by subclasses virtual PropertyFlags SupportedProperties() const; // Determine whether this menu object could use the specified // native item. Returns true by default but can be overridden by subclasses virtual bool IsCompatibleWithNativeData(DbusmenuMenuitem* aNativeData) const; // Update attributes on this objects content node when the container opens. // This is called before style resolution, and should be implemented by // subclasses who want to modify attributes that might affect style. // This will not be called when there are script blockers virtual void UpdateContentAttributes(); // Update properties that should be refreshed when the container opens. // This should be implemented by subclasses that have properties which // need refreshing virtual void Update(nsStyleContext* aStyleContext); bool ShouldShowIcon() const; void ClearIcon(); nsCOMPtr mContent; // mListener is a strong ref for simplicity - someone in the tree needs to // own it, and this only really needs to be the top-level object (as no // children outlives their parent). However, we need to keep it alive until // after running the nsMenuObject destructor for the top-level menu object, // hence the strong ref RefPtr mListener; nsMenuContainer* mParent; // [weak] DbusmenuMenuitem* mNativeData; // [strong] RefPtr mIconLoader; }; // Keep a weak pointer to a menu object class nsWeakMenuObject { public: nsWeakMenuObject() : mPrev(nullptr), mMenuObject(nullptr) {} nsWeakMenuObject(nsMenuObject* aMenuObject) : mPrev(nullptr), mMenuObject(aMenuObject) { AddWeakReference(this); } ~nsWeakMenuObject() { RemoveWeakReference(this); } nsMenuObject* get() const { return mMenuObject; } nsMenuObject* operator->() const { return mMenuObject; } explicit operator bool() const { return !!mMenuObject; } static void NotifyDestroyed(nsMenuObject* aMenuObject); private: static void AddWeakReference(nsWeakMenuObject* aWeak); static void RemoveWeakReference(nsWeakMenuObject* aWeak); nsWeakMenuObject* mPrev; static nsWeakMenuObject* sHead; nsMenuObject* mMenuObject; }; #endif /* __nsMenuObject_h__ */