// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_DBUS_MENU_MENU_H_ #define COMPONENTS_DBUS_MENU_MENU_H_ #include #include #include #include #include #include "base/callback_forward.h" #include "base/component_export.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "components/dbus/menu/menu_property_list.h" #include "components/dbus/properties/types.h" #include "dbus/bus.h" #include "dbus/exported_object.h" #include "dbus/message.h" namespace ui { class MenuModel; } class DbusProperties; // Implements the com.canonical.dbusmenu interface. class COMPONENT_EXPORT(DBUS) DbusMenu { public: using InitializedCallback = base::OnceCallback; using MenuItemReference = std::pair; // The exported DBus object will not be unregistered upon deletion. It is the // responsibility of the caller to remove it after |this| is deleted. DbusMenu(dbus::ExportedObject* exported_object, InitializedCallback callback); ~DbusMenu(); // Should be called when there's a new root menu. void SetModel(ui::MenuModel* model, bool send_signal); // Should be called when items are added/removed/reordered in a menu. Prefer // this over SetModel(). void MenuLayoutUpdated(ui::MenuModel* model); // Should be called when properties on (a group of) menu items change. Prefer // this over SetModel(). void MenuItemsPropertiesUpdated( const std::vector& menu_items); private: struct MenuItem { public: MenuItem(int32_t id, MenuItemProperties&& properties, std::vector&& children, ui::MenuModel* menu, ui::MenuModel* containing_menu, int containing_menu_index); ~MenuItem(); const int32_t id; MenuItemProperties properties; std::vector children; // The MenuModel corresponding to this MenuItem, or null if this MenuItem is // not a submenu. This can happen for leaf items or an empty root item. ui::MenuModel* const menu; // |containing_menu| will be null for the root item. If it's null, then // |containing_menu_index| is meaningless. ui::MenuModel* const containing_menu; const int containing_menu_index; DISALLOW_COPY_AND_ASSIGN(MenuItem); }; class ScopedMethodResponse { public: ScopedMethodResponse(dbus::MethodCall* method_call, dbus::ExportedObject::ResponseSender response_sender); ~ScopedMethodResponse(); dbus::MessageWriter& Writer(); void EnsureResponse(); dbus::MessageReader& reader() { return reader_; } private: dbus::MethodCall* method_call_; dbus::ExportedObject::ResponseSender response_sender_; // |reader_| is always needed for all methods on this interface, so it's not // created lazily. dbus::MessageReader reader_; std::unique_ptr writer_; std::unique_ptr response_; }; static dbus::ExportedObject::MethodCallCallback WrapMethodCallback( base::RepeatingCallback callback); void OnExported(const std::string& interface_name, const std::string& method_name, bool success); // Methods. void OnAboutToShow(ScopedMethodResponse* response); void OnAboutToShowGroup(ScopedMethodResponse* response); void OnEvent(ScopedMethodResponse* response); void OnEventGroup(ScopedMethodResponse* response); void OnGetGroupProperties(ScopedMethodResponse* response); void OnGetLayout(ScopedMethodResponse* response); void OnGetProperty(ScopedMethodResponse* response); bool AboutToShowImpl(int32_t id); bool EventImpl(dbus::MessageReader* reader, int32_t* id_error); // Get the next item ID, handling overflow and skipping over the root item // which must have ID 0. int32_t NextItemId(); // Converts |menu| to zero or more MenuItem's and adds them to |items_|. // Returns a vector of IDs that index into |items_|. std::vector ConvertMenu(ui::MenuModel* menu); // A |depth| of -1 means infinite depth. If |property_filter| is empty, all // properties will be sent. void WriteMenuItem(const MenuItem* item, dbus::MessageWriter* writer, int32_t depth, const MenuPropertyList& property_filter) const; void WriteUpdatedProperties(dbus::MessageWriter* writer, const MenuPropertyChanges& updated_props) const; // Recursively searches |item| and its descendants for the MenuItem // corresponding to |model|. MenuItem* FindMenuItemForModel(const ui::MenuModel* model, MenuItem* item) const; void DeleteItem(MenuItem* item); void DeleteItemChildren(MenuItem* item); void SendLayoutChangedSignal(int32_t id); dbus::ExportedObject* menu_ = nullptr; base::RepeatingCallback barrier_; std::unique_ptr properties_; uint32_t revision_ = 0; int32_t last_item_id_ = 0; std::map> items_; base::WeakPtrFactory weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(DbusMenu); }; #endif // COMPONENTS_DBUS_MENU_MENU_H_