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