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#include <AK/Assertions.h>
28#include <AK/Badge.h>
29#include <AK/JsonObject.h>
30#include <LibCore/Event.h>
31#include <LibCore/EventLoop.h>
32#include <LibCore/Object.h>
33#include <stdio.h>
34
35namespace Core {
36
37IntrusiveList<Object, &Object::m_all_objects_list_node>& Object::all_objects()
38{
39 static IntrusiveList<Object, &Object::m_all_objects_list_node> objects;
40 return objects;
41}
42
43Object::Object(Object* parent, bool is_widget)
44 : m_parent(parent)
45 , m_widget(is_widget)
46{
47 all_objects().append(*this);
48 if (m_parent)
49 m_parent->add_child(*this);
50}
51
52Object::~Object()
53{
54 // NOTE: We move our children out to a stack vector to prevent other
55 // code from trying to iterate over them.
56 auto children = move(m_children);
57 // NOTE: We also unparent the children, so that they won't try to unparent
58 // themselves in their own destructors.
59 for (auto& child : children)
60 child.m_parent = nullptr;
61
62 all_objects().remove(*this);
63 stop_timer();
64 if (m_parent)
65 m_parent->remove_child(*this);
66}
67
68void Object::event(Core::Event& event)
69{
70 switch (event.type()) {
71 case Core::Event::Timer:
72 return timer_event(static_cast<TimerEvent&>(event));
73 case Core::Event::ChildAdded:
74 case Core::Event::ChildRemoved:
75 return child_event(static_cast<ChildEvent&>(event));
76 case Core::Event::Invalid:
77 ASSERT_NOT_REACHED();
78 break;
79 case Core::Event::Custom:
80 return custom_event(static_cast<CustomEvent&>(event));
81 default:
82 break;
83 }
84}
85
86void Object::add_child(Object& object)
87{
88 // FIXME: Should we support reparenting objects?
89 ASSERT(!object.parent() || object.parent() == this);
90 object.m_parent = this;
91 m_children.append(object);
92 event(*make<Core::ChildEvent>(Core::Event::ChildAdded, object));
93}
94
95void Object::insert_child_before(Object& new_child, Object& before_child)
96{
97 // FIXME: Should we support reparenting objects?
98 ASSERT(!new_child.parent() || new_child.parent() == this);
99 new_child.m_parent = this;
100 m_children.insert_before_matching(new_child, [&](auto& existing_child) { return existing_child.ptr() == &before_child; });
101 event(*make<Core::ChildEvent>(Core::Event::ChildAdded, new_child, &before_child));
102}
103
104void Object::remove_child(Object& object)
105{
106 for (size_t i = 0; i < m_children.size(); ++i) {
107 if (m_children.ptr_at(i).ptr() == &object) {
108 // NOTE: We protect the child so it survives the handling of ChildRemoved.
109 NonnullRefPtr<Object> protector = object;
110 object.m_parent = nullptr;
111 m_children.remove(i);
112 event(*make<Core::ChildEvent>(Core::Event::ChildRemoved, object));
113 return;
114 }
115 }
116 ASSERT_NOT_REACHED();
117}
118
119void Object::timer_event(Core::TimerEvent&)
120{
121}
122
123void Object::child_event(Core::ChildEvent&)
124{
125}
126
127void Object::custom_event(CustomEvent&)
128{
129}
130
131void Object::start_timer(int ms, TimerShouldFireWhenNotVisible fire_when_not_visible)
132{
133 if (m_timer_id) {
134 dbgprintf("Object{%p} already has a timer!\n", this);
135 ASSERT_NOT_REACHED();
136 }
137
138 m_timer_id = Core::EventLoop::register_timer(*this, ms, true, fire_when_not_visible);
139}
140
141void Object::stop_timer()
142{
143 if (!m_timer_id)
144 return;
145 bool success = Core::EventLoop::unregister_timer(m_timer_id);
146 ASSERT(success);
147 m_timer_id = 0;
148}
149
150void Object::dump_tree(int indent)
151{
152 for (int i = 0; i < indent; ++i) {
153 printf(" ");
154 }
155 printf("%s{%p}\n", class_name(), this);
156
157 for_each_child([&](auto& child) {
158 child.dump_tree(indent + 2);
159 return IterationDecision::Continue;
160 });
161}
162
163void Object::deferred_invoke(Function<void(Object&)> invokee)
164{
165 Core::EventLoop::current().post_event(*this, make<Core::DeferredInvocationEvent>(move(invokee)));
166}
167
168void Object::save_to(JsonObject& json)
169{
170 json.set("class_name", class_name());
171 json.set("address", (FlatPtr)this);
172 json.set("name", name());
173 json.set("parent", (FlatPtr)parent());
174}
175
176bool Object::set_property(const StringView& name, const JsonValue& value)
177{
178 if (name == "name") {
179 set_name(value.to_string());
180 return true;
181 }
182 return false;
183}
184
185bool Object::is_ancestor_of(const Object& other) const
186{
187 if (&other == this)
188 return false;
189 for (auto* ancestor = other.parent(); ancestor; ancestor = ancestor->parent()) {
190 if (ancestor == this)
191 return true;
192 }
193 return false;
194}
195
196void Object::dispatch_event(Core::Event& e, Object* stay_within)
197{
198 ASSERT(!stay_within || stay_within == this || stay_within->is_ancestor_of(*this));
199 auto* target = this;
200 do {
201 target->event(e);
202 target = target->parent();
203 if (target == stay_within) {
204 // Prevent the event from bubbling any further.
205 e.accept();
206 break;
207 }
208 } while (target && !e.is_accepted());
209}
210
211bool Object::is_visible_for_timer_purposes() const
212{
213 if (parent())
214 return parent()->is_visible_for_timer_purposes();
215 return true;
216}
217
218void Object::increment_inspector_count(Badge<RPCClient>)
219{
220 ++m_inspector_count;
221 if (m_inspector_count == 1)
222 did_begin_inspection();
223}
224
225void Object::decrement_inspector_count(Badge<RPCClient>)
226{
227 --m_inspector_count;
228 if (!m_inspector_count)
229 did_end_inspection();
230}
231
232const LogStream& operator<<(const LogStream& stream, const Object& object)
233{
234 return stream << object.class_name() << '{' << &object << '}';
235}
236
237}