Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/Forward.h>
30#include <AK/IntrusiveList.h>
31#include <AK/Noncopyable.h>
32#include <AK/NonnullRefPtrVector.h>
33#include <AK/String.h>
34#include <AK/Weakable.h>
35#include <LibCore/Forward.h>
36
37namespace Core {
38
39class RPCClient;
40
41enum class TimerShouldFireWhenNotVisible {
42 No = 0,
43 Yes
44};
45
46#define C_OBJECT(klass) \
47public: \
48 virtual const char* class_name() const override { return #klass; } \
49 template<class... Args> \
50 static inline NonnullRefPtr<klass> construct(Args&&... args) \
51 { \
52 return adopt(*new klass(forward<Args>(args)...)); \
53 }
54
55#define C_OBJECT_ABSTRACT(klass) \
56public: \
57 virtual const char* class_name() const override { return #klass; }
58
59class Object
60 : public RefCounted<Object>
61 , public Weakable<Object> {
62 // NOTE: No C_OBJECT macro for Core::Object itself.
63
64 AK_MAKE_NONCOPYABLE(Object)
65 AK_MAKE_NONMOVABLE(Object)
66public:
67 IntrusiveListNode m_all_objects_list_node;
68
69 virtual ~Object();
70
71 virtual const char* class_name() const = 0;
72 virtual void event(Core::Event&);
73
74 const String& name() const { return m_name; }
75 void set_name(const StringView& name) { m_name = name; }
76
77 NonnullRefPtrVector<Object>& children() { return m_children; }
78 const NonnullRefPtrVector<Object>& children() const { return m_children; }
79
80 template<typename Callback>
81 void for_each_child(Callback callback)
82 {
83 for (auto& child : m_children) {
84 if (callback(child) == IterationDecision::Break)
85 return;
86 }
87 }
88
89 template<typename T, typename Callback>
90 void for_each_child_of_type(Callback callback);
91
92 bool is_ancestor_of(const Object&) const;
93
94 Object* parent() { return m_parent; }
95 const Object* parent() const { return m_parent; }
96
97 void start_timer(int ms, TimerShouldFireWhenNotVisible = TimerShouldFireWhenNotVisible::No);
98 void stop_timer();
99 bool has_timer() const { return m_timer_id; }
100
101 void add_child(Object&);
102 void insert_child_before(Object& new_child, Object& before_child);
103 void remove_child(Object&);
104
105 void dump_tree(int indent = 0);
106
107 void deferred_invoke(Function<void(Object&)>);
108
109 bool is_widget() const { return m_widget; }
110 virtual bool is_action() const { return false; }
111 virtual bool is_window() const { return false; }
112
113 virtual void save_to(AK::JsonObject&);
114 virtual bool set_property(const StringView& name, const JsonValue& value);
115
116 static IntrusiveList<Object, &Object::m_all_objects_list_node>& all_objects();
117
118 void dispatch_event(Core::Event&, Object* stay_within = nullptr);
119
120 void remove_from_parent()
121 {
122 if (m_parent)
123 m_parent->remove_child(*this);
124 }
125
126 template<class T, class... Args>
127 inline T& add(Args&&... args)
128 {
129 auto child = T::construct(forward<Args>(args)...);
130 add_child(*child);
131 return child;
132 }
133
134 virtual bool is_visible_for_timer_purposes() const;
135
136 bool is_being_inspected() const { return m_inspector_count; }
137
138 void increment_inspector_count(Badge<RPCClient>);
139 void decrement_inspector_count(Badge<RPCClient>);
140
141protected:
142 explicit Object(Object* parent = nullptr, bool is_widget = false);
143
144 virtual void timer_event(TimerEvent&);
145 virtual void custom_event(CustomEvent&);
146
147 // NOTE: You may get child events for children that are not yet fully constructed!
148 virtual void child_event(ChildEvent&);
149
150 virtual void did_begin_inspection() {}
151 virtual void did_end_inspection() {}
152
153private:
154 Object* m_parent { nullptr };
155 String m_name;
156 int m_timer_id { 0 };
157 unsigned m_inspector_count { 0 };
158 bool m_widget { false };
159 NonnullRefPtrVector<Object> m_children;
160};
161
162template<typename T>
163inline bool is(const Object&) { return false; }
164
165template<typename T>
166inline T& to(Object& object)
167{
168 ASSERT(is<typename RemoveConst<T>::Type>(object));
169 return static_cast<T&>(object);
170}
171
172template<typename T>
173inline const T& to(const Object& object)
174{
175 ASSERT(is<typename RemoveConst<T>::Type>(object));
176 return static_cast<const T&>(object);
177}
178
179template<typename T, typename Callback>
180inline void Object::for_each_child_of_type(Callback callback)
181{
182 for_each_child([&](auto& child) {
183 if (is<T>(child))
184 return callback(to<T>(child));
185 return IterationDecision::Continue;
186 });
187}
188
189const LogStream& operator<<(const LogStream&, const Object&);
190
191}