Serenity Operating System
at master 452 lines 22 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#pragma once 9 10#include <AK/DeprecatedString.h> 11#include <AK/Forward.h> 12#include <AK/HashMap.h> 13#include <AK/IntrusiveList.h> 14#include <AK/Noncopyable.h> 15#include <AK/OwnPtr.h> 16#include <AK/StringView.h> 17#include <AK/TypeCasts.h> 18#include <AK/Weakable.h> 19#include <LibCore/Forward.h> 20#include <LibCore/Property.h> 21 22namespace Core { 23 24#define REGISTER_ABSTRACT_CORE_OBJECT(namespace_, class_name) \ 25 namespace Core { \ 26 namespace Registration { \ 27 Core::ObjectClassRegistration registration_##class_name(#namespace_ "::" #class_name##sv, []() { return Error::from_string_literal("Attempted to construct an abstract object."); }); \ 28 } \ 29 } 30 31#define REGISTER_CORE_OBJECT(namespace_, class_name) \ 32 namespace Core { \ 33 namespace Registration { \ 34 Core::ObjectClassRegistration registration_##class_name(#namespace_ "::" #class_name##sv, []() { return namespace_::class_name::try_create(); }); \ 35 } \ 36 } 37 38class ObjectClassRegistration { 39 AK_MAKE_NONCOPYABLE(ObjectClassRegistration); 40 AK_MAKE_NONMOVABLE(ObjectClassRegistration); 41 42public: 43 ObjectClassRegistration(StringView class_name, Function<ErrorOr<NonnullRefPtr<Object>>()> factory, ObjectClassRegistration* parent_class = nullptr); 44 ~ObjectClassRegistration() = default; 45 46 StringView class_name() const { return m_class_name; } 47 ObjectClassRegistration const* parent_class() const { return m_parent_class; } 48 ErrorOr<NonnullRefPtr<Object>> construct() const { return m_factory(); } 49 bool is_derived_from(ObjectClassRegistration const& base_class) const; 50 51 static void for_each(Function<void(ObjectClassRegistration const&)>); 52 static ObjectClassRegistration const* find(StringView class_name); 53 54private: 55 StringView m_class_name; 56 Function<ErrorOr<NonnullRefPtr<Object>>()> m_factory; 57 ObjectClassRegistration* m_parent_class { nullptr }; 58}; 59 60class InspectorServerConnection; 61 62enum class TimerShouldFireWhenNotVisible { 63 No = 0, 64 Yes 65}; 66 67#define C_OBJECT(klass) \ 68public: \ 69 virtual StringView class_name() const override \ 70 { \ 71 return #klass##sv; \ 72 } \ 73 template<typename Klass = klass, class... Args> \ 74 static NonnullRefPtr<klass> construct(Args&&... args) \ 75 { \ 76 return adopt_ref(*new Klass(::forward<Args>(args)...)); \ 77 } \ 78 template<typename Klass = klass, class... Args> \ 79 static ErrorOr<NonnullRefPtr<klass>> try_create(Args&&... args) \ 80 { \ 81 return adopt_nonnull_ref_or_enomem(new (nothrow) Klass(::forward<Args>(args)...)); \ 82 } 83 84#define C_OBJECT_ABSTRACT(klass) \ 85public: \ 86 virtual StringView class_name() const override \ 87 { \ 88 return #klass##sv; \ 89 } 90 91class Object 92 : public RefCounted<Object> 93 , public Weakable<Object> { 94 // NOTE: No C_OBJECT macro for Core::Object itself. 95 96 AK_MAKE_NONCOPYABLE(Object); 97 AK_MAKE_NONMOVABLE(Object); 98 99 IntrusiveListNode<Object> m_all_objects_list_node; 100 101public: 102 virtual ~Object(); 103 104 virtual StringView class_name() const = 0; 105 106 template<typename T> 107 bool fast_is() const = delete; 108 109 virtual bool is_widget() const { return false; } 110 111 DeprecatedString const& name() const { return m_name; } 112 void set_name(DeprecatedString name) { m_name = move(name); } 113 114 Vector<NonnullRefPtr<Object>>& children() { return m_children; } 115 Vector<NonnullRefPtr<Object>> const& children() const { return m_children; } 116 117 template<typename Callback> 118 void for_each_child(Callback callback) 119 { 120 for (auto& child : m_children) { 121 if (callback(*child) == IterationDecision::Break) 122 return; 123 } 124 } 125 126 template<typename T, typename Callback> 127 void for_each_child_of_type(Callback callback) 128 requires IsBaseOf<Object, T>; 129 130 template<typename T> 131 T* find_child_of_type_named(DeprecatedString const&) 132 requires IsBaseOf<Object, T>; 133 134 template<typename T> 135 T* find_descendant_of_type_named(DeprecatedString const&) 136 requires IsBaseOf<Object, T>; 137 138 bool is_ancestor_of(Object const&) const; 139 140 Object* parent() { return m_parent; } 141 Object const* parent() const { return m_parent; } 142 143 void start_timer(int ms, TimerShouldFireWhenNotVisible = TimerShouldFireWhenNotVisible::No); 144 void stop_timer(); 145 bool has_timer() const { return m_timer_id; } 146 147 ErrorOr<void> try_add_child(Object&); 148 149 void add_child(Object&); 150 void insert_child_before(Object& new_child, Object& before_child); 151 void remove_child(Object&); 152 void remove_all_children(); 153 154 void set_event_filter(Function<bool(Core::Event&)>); 155 156 void dump_tree(int indent = 0); 157 158 void deferred_invoke(Function<void()>); 159 160 void save_to(JsonObject&); 161 162 bool set_property(DeprecatedString const& name, JsonValue const& value); 163 JsonValue property(DeprecatedString const& name) const; 164 HashMap<DeprecatedString, NonnullOwnPtr<Property>> const& properties() const { return m_properties; } 165 166 static IntrusiveList<&Object::m_all_objects_list_node>& all_objects(); 167 168 void dispatch_event(Core::Event&, Object* stay_within = nullptr); 169 170 void remove_from_parent() 171 { 172 if (m_parent) 173 m_parent->remove_child(*this); 174 } 175 176 template<class T, class... Args> 177 inline T& add(Args&&... args) 178 { 179 auto child = T::construct(forward<Args>(args)...); 180 add_child(*child); 181 return child; 182 } 183 184 template<class T, class... Args> 185 inline ErrorOr<NonnullRefPtr<T>> try_add(Args&&... args) 186 { 187 auto child = TRY(T::try_create(forward<Args>(args)...)); 188 TRY(try_add_child(*child)); 189 return child; 190 } 191 192 virtual bool is_visible_for_timer_purposes() const; 193 194 bool is_being_inspected() const { return m_inspector_count; } 195 196 void increment_inspector_count(Badge<InspectorServerConnection>); 197 void decrement_inspector_count(Badge<InspectorServerConnection>); 198 199protected: 200 explicit Object(Object* parent = nullptr); 201 202 void register_property(DeprecatedString const& name, Function<JsonValue()> getter, Function<bool(JsonValue const&)> setter = nullptr); 203 204 virtual void event(Core::Event&); 205 206 virtual void timer_event(TimerEvent&); 207 virtual void custom_event(CustomEvent&); 208 209 // NOTE: You may get child events for children that are not yet fully constructed! 210 virtual void child_event(ChildEvent&); 211 212 virtual void did_begin_inspection() { } 213 virtual void did_end_inspection() { } 214 215private: 216 Object* m_parent { nullptr }; 217 DeprecatedString m_name; 218 int m_timer_id { 0 }; 219 unsigned m_inspector_count { 0 }; 220 HashMap<DeprecatedString, NonnullOwnPtr<Property>> m_properties; 221 Vector<NonnullRefPtr<Object>> m_children; 222 Function<bool(Core::Event&)> m_event_filter; 223}; 224 225} 226 227template<> 228struct AK::Formatter<Core::Object> : AK::Formatter<FormatString> { 229 ErrorOr<void> format(FormatBuilder& builder, Core::Object const& value) 230 { 231 return AK::Formatter<FormatString>::format(builder, "{}({})"sv, value.class_name(), &value); 232 } 233}; 234 235namespace Core { 236template<typename T, typename Callback> 237inline void Object::for_each_child_of_type(Callback callback) 238requires IsBaseOf<Object, T> 239{ 240 for_each_child([&](auto& child) { 241 if (is<T>(child)) 242 return callback(static_cast<T&>(child)); 243 return IterationDecision::Continue; 244 }); 245} 246 247template<typename T> 248T* Object::find_child_of_type_named(DeprecatedString const& name) 249requires IsBaseOf<Object, T> 250{ 251 T* found_child = nullptr; 252 for_each_child_of_type<T>([&](auto& child) { 253 if (child.name() == name) { 254 found_child = &child; 255 return IterationDecision::Break; 256 } 257 return IterationDecision::Continue; 258 }); 259 260 return found_child; 261} 262 263template<typename T> 264T* Object::find_descendant_of_type_named(DeprecatedString const& name) 265requires IsBaseOf<Object, T> 266{ 267 if (is<T>(*this) && this->name() == name) { 268 return static_cast<T*>(this); 269 } 270 T* found_child = nullptr; 271 for_each_child([&](auto& child) { 272 found_child = child.template find_descendant_of_type_named<T>(name); 273 if (found_child) 274 return IterationDecision::Break; 275 return IterationDecision::Continue; 276 }); 277 return found_child; 278} 279 280#define REGISTER_INT_PROPERTY(property_name, getter, setter) \ 281 register_property( \ 282 property_name, \ 283 [this] { return this->getter(); }, \ 284 [this](auto& value) { \ 285 this->setter(value.template to_number<int>()); \ 286 return true; \ 287 }); 288 289#define REGISTER_BOOL_PROPERTY(property_name, getter, setter) \ 290 register_property( \ 291 property_name, \ 292 [this] { return this->getter(); }, \ 293 [this](auto& value) { \ 294 this->setter(value.to_bool()); \ 295 return true; \ 296 }); 297 298#define REGISTER_STRING_PROPERTY(property_name, getter, setter) \ 299 register_property( \ 300 property_name, \ 301 [this] { return this->getter(); }, \ 302 [this](auto& value) { \ 303 this->setter(value.to_deprecated_string()); \ 304 return true; \ 305 }); 306 307#define REGISTER_READONLY_STRING_PROPERTY(property_name, getter) \ 308 register_property( \ 309 property_name, \ 310 [this] { return this->getter(); }, \ 311 {}); 312 313#define REGISTER_WRITE_ONLY_STRING_PROPERTY(property_name, setter) \ 314 register_property( \ 315 property_name, \ 316 {}, \ 317 [this](auto& value) { \ 318 this->setter(value.to_deprecated_string()); \ 319 return true; \ 320 }); 321 322#define REGISTER_READONLY_SIZE_PROPERTY(property_name, getter) \ 323 register_property( \ 324 property_name, \ 325 [this] { \ 326 auto size = this->getter(); \ 327 JsonArray size_array; \ 328 size_array.append(size.width()); \ 329 size_array.append(size.height()); \ 330 return size_array; \ 331 }, \ 332 {}); 333 334#define REGISTER_RECT_PROPERTY(property_name, getter, setter) \ 335 register_property( \ 336 property_name, \ 337 [this] { \ 338 auto rect = this->getter(); \ 339 JsonObject rect_object; \ 340 rect_object.set("x"sv, rect.x()); \ 341 rect_object.set("y"sv, rect.y()); \ 342 rect_object.set("width"sv, rect.width()); \ 343 rect_object.set("height"sv, rect.height()); \ 344 return rect_object; \ 345 }, \ 346 [this](auto& value) { \ 347 Gfx::IntRect rect; \ 348 if (value.is_object()) { \ 349 rect.set_x(value.as_object().get_i32("x"sv).value_or(0)); \ 350 rect.set_y(value.as_object().get_i32("y"sv).value_or(0)); \ 351 rect.set_width(value.as_object().get_i32("width"sv).value_or(0)); \ 352 rect.set_height(value.as_object().get_i32("height"sv).value_or(0)); \ 353 } else if (value.is_array() && value.as_array().size() == 4) { \ 354 rect.set_x(value.as_array()[0].to_i32()); \ 355 rect.set_y(value.as_array()[1].to_i32()); \ 356 rect.set_width(value.as_array()[2].to_i32()); \ 357 rect.set_height(value.as_array()[3].to_i32()); \ 358 } else { \ 359 return false; \ 360 } \ 361 setter(rect); \ 362 \ 363 return true; \ 364 }); 365 366#define REGISTER_SIZE_PROPERTY(property_name, getter, setter) \ 367 register_property( \ 368 property_name, \ 369 [this] { \ 370 auto size = this->getter(); \ 371 JsonArray size_array; \ 372 size_array.append(size.width()); \ 373 size_array.append(size.height()); \ 374 return size_array; \ 375 }, \ 376 [this](auto& value) { \ 377 if (!value.is_array()) \ 378 return false; \ 379 Gfx::IntSize size; \ 380 size.set_width(value.as_array()[0].to_i32()); \ 381 size.set_height(value.as_array()[1].to_i32()); \ 382 setter(size); \ 383 return true; \ 384 }); 385 386#define REGISTER_ENUM_PROPERTY(property_name, getter, setter, EnumType, ...) \ 387 register_property( \ 388 property_name, \ 389 [this]() -> JsonValue { \ 390 struct { \ 391 EnumType enum_value; \ 392 DeprecatedString string_value; \ 393 } options[] = { __VA_ARGS__ }; \ 394 auto enum_value = getter(); \ 395 for (size_t i = 0; i < array_size(options); ++i) { \ 396 auto& option = options[i]; \ 397 if (enum_value == option.enum_value) \ 398 return option.string_value; \ 399 } \ 400 return JsonValue(); \ 401 }, \ 402 [this](auto& value) { \ 403 struct { \ 404 EnumType enum_value; \ 405 DeprecatedString string_value; \ 406 } options[] = { __VA_ARGS__ }; \ 407 if (!value.is_string()) \ 408 return false; \ 409 auto string_value = value.as_string(); \ 410 for (size_t i = 0; i < array_size(options); ++i) { \ 411 auto& option = options[i]; \ 412 if (string_value == option.string_value) { \ 413 setter(option.enum_value); \ 414 return true; \ 415 } \ 416 } \ 417 return false; \ 418 }) 419 420#define REGISTER_TEXT_ALIGNMENT_PROPERTY(property_name, getter, setter) \ 421 REGISTER_ENUM_PROPERTY( \ 422 property_name, getter, setter, Gfx::TextAlignment, \ 423 { Gfx::TextAlignment::Center, "Center" }, \ 424 { Gfx::TextAlignment::CenterLeft, "CenterLeft" }, \ 425 { Gfx::TextAlignment::CenterRight, "CenterRight" }, \ 426 { Gfx::TextAlignment::TopCenter, "TopCenter" }, \ 427 { Gfx::TextAlignment::TopLeft, "TopLeft" }, \ 428 { Gfx::TextAlignment::TopRight, "TopRight" }, \ 429 { Gfx::TextAlignment::BottomCenter, "BottomCenter" }, \ 430 { Gfx::TextAlignment::BottomLeft, "BottomLeft" }, \ 431 { Gfx::TextAlignment::BottomRight, "BottomRight" }) 432 433#define REGISTER_FONT_WEIGHT_PROPERTY(property_name, getter, setter) \ 434 REGISTER_ENUM_PROPERTY( \ 435 property_name, getter, setter, unsigned, \ 436 { Gfx::FontWeight::Thin, "Thin" }, \ 437 { Gfx::FontWeight::ExtraLight, "ExtraLight" }, \ 438 { Gfx::FontWeight::Light, "Light" }, \ 439 { Gfx::FontWeight::Regular, "Regular" }, \ 440 { Gfx::FontWeight::Medium, "Medium" }, \ 441 { Gfx::FontWeight::SemiBold, "SemiBold" }, \ 442 { Gfx::FontWeight::Bold, "Bold" }, \ 443 { Gfx::FontWeight::ExtraBold, "ExtraBold" }, \ 444 { Gfx::FontWeight::Black, "Black" }, \ 445 { Gfx::FontWeight::ExtraBlack, "ExtraBlack" }) 446 447#define REGISTER_TEXT_WRAPPING_PROPERTY(property_name, getter, setter) \ 448 REGISTER_ENUM_PROPERTY( \ 449 property_name, getter, setter, Gfx::TextWrapping, \ 450 { Gfx::TextWrapping::Wrap, "Wrap" }, \ 451 { Gfx::TextWrapping::DontWrap, "DontWrap" }) 452}