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
39enum class TimerShouldFireWhenNotVisible {
40 No = 0,
41 Yes
42};
43
44#define C_OBJECT(klass) \
45public: \
46 virtual const char* class_name() const override { return #klass; } \
47 template<class... Args> \
48 static inline NonnullRefPtr<klass> construct(Args&&... args) \
49 { \
50 return adopt(*new klass(forward<Args>(args)...)); \
51 }
52
53#define C_OBJECT_ABSTRACT(klass) \
54public: \
55 virtual const char* class_name() const override { return #klass; }
56
57class Object
58 : public RefCounted<Object>
59 , public Weakable<Object> {
60 // NOTE: No C_OBJECT macro for Core::Object itself.
61
62 AK_MAKE_NONCOPYABLE(Object)
63 AK_MAKE_NONMOVABLE(Object)
64public:
65 IntrusiveListNode m_all_objects_list_node;
66
67 virtual ~Object();
68
69 virtual const char* class_name() const = 0;
70 virtual void event(Core::Event&);
71
72 const String& name() const { return m_name; }
73 void set_name(const StringView& name) { m_name = name; }
74
75 NonnullRefPtrVector<Object>& children() { return m_children; }
76 const NonnullRefPtrVector<Object>& children() const { return m_children; }
77
78 template<typename Callback>
79 void for_each_child(Callback callback)
80 {
81 for (auto& child : m_children) {
82 if (callback(child) == IterationDecision::Break)
83 return;
84 }
85 }
86
87 template<typename T, typename Callback>
88 void for_each_child_of_type(Callback callback);
89
90 bool is_ancestor_of(const Object&) const;
91
92 Object* parent() { return m_parent; }
93 const Object* parent() const { return m_parent; }
94
95 void start_timer(int ms, TimerShouldFireWhenNotVisible = TimerShouldFireWhenNotVisible::No);
96 void stop_timer();
97 bool has_timer() const { return m_timer_id; }
98
99 void add_child(Object&);
100 void insert_child_before(Object& new_child, Object& before_child);
101 void remove_child(Object&);
102
103 void dump_tree(int indent = 0);
104
105 void deferred_invoke(Function<void(Object&)>);
106
107 bool is_widget() const { return m_widget; }
108 virtual bool is_action() const { return false; }
109 virtual bool is_window() const { return false; }
110
111 virtual void save_to(AK::JsonObject&);
112
113 static IntrusiveList<Object, &Object::m_all_objects_list_node>& all_objects();
114
115 void dispatch_event(Core::Event&, Object* stay_within = nullptr);
116
117 void remove_from_parent()
118 {
119 if (m_parent)
120 m_parent->remove_child(*this);
121 }
122
123 template<class T, class... Args>
124 inline NonnullRefPtr<T> add(Args&&... args)
125 {
126 auto t = T::construct(forward<Args>(args)...);
127 add_child(*t);
128 return t;
129 }
130
131 virtual bool is_visible_for_timer_purposes() const;
132
133protected:
134 explicit Object(Object* parent = nullptr, bool is_widget = false);
135
136 virtual void timer_event(TimerEvent&);
137 virtual void custom_event(CustomEvent&);
138
139 // NOTE: You may get child events for children that are not yet fully constructed!
140 virtual void child_event(ChildEvent&);
141
142private:
143 Object* m_parent { nullptr };
144 String m_name;
145 int m_timer_id { 0 };
146 bool m_widget { false };
147 NonnullRefPtrVector<Object> m_children;
148};
149
150template<typename T>
151inline bool is(const Object&) { return false; }
152
153template<typename T>
154inline T& to(Object& object)
155{
156 ASSERT(is<typename RemoveConst<T>::Type>(object));
157 return static_cast<T&>(object);
158}
159
160template<typename T>
161inline const T& to(const Object& object)
162{
163 ASSERT(is<typename RemoveConst<T>::Type>(object));
164 return static_cast<const T&>(object);
165}
166
167template<typename T, typename Callback>
168inline void Object::for_each_child_of_type(Callback callback)
169{
170 for_each_child([&](auto& child) {
171 if (is<T>(child))
172 return callback(to<T>(child));
173 return IterationDecision::Continue;
174 });
175}
176
177const LogStream& operator<<(const LogStream&, const Object&);
178
179}