diff --git a/Userland/Applications/SystemMonitor/CMakeLists.txt b/Userland/Applications/SystemMonitor/CMakeLists.txt index 30c42dab12..6a2c192997 100644 --- a/Userland/Applications/SystemMonitor/CMakeLists.txt +++ b/Userland/Applications/SystemMonitor/CMakeLists.txt @@ -5,6 +5,7 @@ serenity_component( ) compile_gml(SystemMonitor.gml SystemMonitorGML.h system_monitor_gml) +compile_gml(ProcessWindow.gml ProcessWindowGML.h process_window_gml) set(SOURCES GraphWidget.cpp @@ -18,6 +19,7 @@ set(SOURCES ProcessStateWidget.cpp ThreadStackWidget.cpp SystemMonitorGML.h + ProcessWindowGML.h ) serenity_app(SystemMonitor ICON app-system-monitor) diff --git a/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp b/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp index 9607dd9623..4131632763 100644 --- a/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp +++ b/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp @@ -11,6 +11,10 @@ #include #include +REGISTER_WIDGET(SystemMonitor, ProcessFileDescriptorMapWidget) + +namespace SystemMonitor { + ProcessFileDescriptorMapWidget::ProcessFileDescriptorMapWidget() { set_layout(); @@ -49,3 +53,5 @@ void ProcessFileDescriptorMapWidget::set_pid(pid_t pid) m_pid = pid; m_model->set_json_path(String::formatted("/proc/{}/fds", m_pid)); } + +} diff --git a/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h b/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h index 001766b6d5..05165434ea 100644 --- a/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h +++ b/Userland/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h @@ -9,6 +9,8 @@ #include +namespace SystemMonitor { + class ProcessFileDescriptorMapWidget final : public GUI::Widget { C_OBJECT(ProcessFileDescriptorMapWidget); @@ -24,3 +26,5 @@ private: RefPtr m_model; pid_t m_pid { -1 }; }; + +} diff --git a/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp b/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp index 5216c90a4a..f25c17cf98 100644 --- a/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp +++ b/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp @@ -14,6 +14,10 @@ #include #include +REGISTER_WIDGET(SystemMonitor, ProcessMemoryMapWidget) + +namespace SystemMonitor { + class PagemapPaintingDelegate final : public GUI::TableCellPaintingDelegate { public: virtual ~PagemapPaintingDelegate() override = default; @@ -121,3 +125,5 @@ void ProcessMemoryMapWidget::refresh() if (m_pid != -1) m_json_model->invalidate(); } + +} diff --git a/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.h b/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.h index b710a0b89a..0b97d0d819 100644 --- a/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.h +++ b/Userland/Applications/SystemMonitor/ProcessMemoryMapWidget.h @@ -9,6 +9,8 @@ #include +namespace SystemMonitor { + class ProcessMemoryMapWidget final : public GUI::Widget { C_OBJECT(ProcessMemoryMapWidget); @@ -25,3 +27,5 @@ private: pid_t m_pid { -1 }; RefPtr m_timer; }; + +} diff --git a/Userland/Applications/SystemMonitor/ProcessStateWidget.cpp b/Userland/Applications/SystemMonitor/ProcessStateWidget.cpp index 41f20aa08d..10684b241a 100644 --- a/Userland/Applications/SystemMonitor/ProcessStateWidget.cpp +++ b/Userland/Applications/SystemMonitor/ProcessStateWidget.cpp @@ -12,9 +12,14 @@ #include #include #include +#include #include #include +REGISTER_WIDGET(SystemMonitor, ProcessStateWidget) + +namespace SystemMonitor { + class ProcessStateModel final : public GUI::Model , public GUI::ModelClient { @@ -75,18 +80,33 @@ public: did_update(GUI::Model::UpdateFlag::DontInvalidateIndices); } + void set_pid(pid_t pid) + { + m_pid = pid; + refresh(); + } + pid_t pid() const { return m_pid; } + private: ProcessModel& m_target; GUI::ModelIndex m_target_index; pid_t m_pid { -1 }; }; -ProcessStateWidget::ProcessStateWidget(pid_t pid) +ProcessStateWidget::ProcessStateWidget() { set_layout(); layout()->set_margins(4); m_table_view = add(); - m_table_view->set_model(adopt_ref(*new ProcessStateModel(ProcessModel::the(), pid))); + m_table_view->set_model(adopt_ref(*new ProcessStateModel(ProcessModel::the(), 0))); m_table_view->column_header().set_visible(false); m_table_view->column_header().set_section_size(0, 90); } + +void ProcessStateWidget::set_pid(pid_t pid) +{ + static_cast(m_table_view->model())->set_pid(pid); + update(); +} + +} diff --git a/Userland/Applications/SystemMonitor/ProcessStateWidget.h b/Userland/Applications/SystemMonitor/ProcessStateWidget.h index a2fd3e7bd7..0c90b5996a 100644 --- a/Userland/Applications/SystemMonitor/ProcessStateWidget.h +++ b/Userland/Applications/SystemMonitor/ProcessStateWidget.h @@ -9,13 +9,19 @@ #include +namespace SystemMonitor { + class ProcessStateWidget final : public GUI::Widget { C_OBJECT(ProcessStateWidget); public: virtual ~ProcessStateWidget() override = default; + void set_pid(pid_t); + private: - explicit ProcessStateWidget(pid_t); + ProcessStateWidget(); RefPtr m_table_view; }; + +} diff --git a/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp b/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp index 4678192477..ba5a5c5187 100644 --- a/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp +++ b/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp @@ -10,6 +10,11 @@ #include #include #include +#include + +REGISTER_WIDGET(SystemMonitor, ProcessUnveiledPathsWidget) + +namespace SystemMonitor { ProcessUnveiledPathsWidget::ProcessUnveiledPathsWidget() { @@ -32,3 +37,5 @@ void ProcessUnveiledPathsWidget::set_pid(pid_t pid) m_pid = pid; m_model->set_json_path(String::formatted("/proc/{}/unveil", m_pid)); } + +} diff --git a/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h b/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h index eec1f4a332..7617af2568 100644 --- a/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h +++ b/Userland/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h @@ -9,6 +9,8 @@ #include +namespace SystemMonitor { + class ProcessUnveiledPathsWidget final : public GUI::Widget { C_OBJECT(ProcessUnveiledPathsWidget); @@ -24,3 +26,5 @@ private: RefPtr m_model; pid_t m_pid { -1 }; }; + +} diff --git a/Userland/Applications/SystemMonitor/ProcessWindow.gml b/Userland/Applications/SystemMonitor/ProcessWindow.gml new file mode 100644 index 0000000000..4a1a6a1e6d --- /dev/null +++ b/Userland/Applications/SystemMonitor/ProcessWindow.gml @@ -0,0 +1,65 @@ +@GUI::Widget { + fill_with_background_color: true + layout: @GUI::VerticalBoxLayout {} + + @GUI::Widget { + shrink_to_fit: true + layout: @GUI::HorizontalBoxLayout { + margins: [4] + spacing: 8 + } + + @GUI::Label { + name: "icon_label" + fixed_size: [32, 32] + } + + @GUI::Label { + name: "process_name" + font_weight: "Bold" + text_alignment: "CenterLeft" + text: "This is the process name." + } + } + + @GUI::HorizontalSeparator { + fixed_height: 2 + } + + @GUI::StackWidget { + name: "widget_stack" + + @SystemMonitor::UnavailableProcessWidget { + name: "unavailable_process" + } + + @GUI::TabWidget { + name: "available_process" + + @SystemMonitor::ProcessStateWidget { + name: "process_state" + title: "State" + } + + @SystemMonitor::ProcessMemoryMapWidget { + name: "memory_map" + title: "Memory map" + } + + @SystemMonitor::ProcessFileDescriptorMapWidget { + name: "open_files" + title: "Open files" + } + + @SystemMonitor::ProcessUnveiledPathsWidget { + name: "unveiled_paths" + title: "Unveiled paths" + } + + @SystemMonitor::ThreadStackWidget { + name: "thread_stack" + title: "Stack" + } + } + } +} diff --git a/Userland/Applications/SystemMonitor/ThreadStackWidget.cpp b/Userland/Applications/SystemMonitor/ThreadStackWidget.cpp index d63d7660ee..998cb50868 100644 --- a/Userland/Applications/SystemMonitor/ThreadStackWidget.cpp +++ b/Userland/Applications/SystemMonitor/ThreadStackWidget.cpp @@ -9,9 +9,14 @@ #include #include #include +#include #include #include +REGISTER_WIDGET(SystemMonitor, ThreadStackWidget) + +namespace SystemMonitor { + class ThreadStackModel final : public GUI::Model { enum Column { @@ -127,3 +132,5 @@ void ThreadStackWidget::custom_event(Core::CustomEvent& event) auto& completion_event = verify_cast(event); verify_cast(m_stack_table->model())->set_symbols(completion_event.symbols()); } + +} diff --git a/Userland/Applications/SystemMonitor/ThreadStackWidget.h b/Userland/Applications/SystemMonitor/ThreadStackWidget.h index 25756a1821..75bf61fa8a 100644 --- a/Userland/Applications/SystemMonitor/ThreadStackWidget.h +++ b/Userland/Applications/SystemMonitor/ThreadStackWidget.h @@ -10,6 +10,8 @@ #include #include +namespace SystemMonitor { + class ThreadStackWidget final : public GUI::Widget { C_OBJECT(ThreadStackWidget) public: @@ -30,3 +32,5 @@ private: RefPtr m_stack_table; RefPtr m_timer; }; + +} diff --git a/Userland/Applications/SystemMonitor/main.cpp b/Userland/Applications/SystemMonitor/main.cpp index 68c46550ea..59af7b682f 100644 --- a/Userland/Applications/SystemMonitor/main.cpp +++ b/Userland/Applications/SystemMonitor/main.cpp @@ -7,6 +7,7 @@ */ #include "GraphWidget.h" +#include "LibCore/EventLoop.h" #include "LibCore/Object.h" #include "MemoryStatsWidget.h" #include "NetworkStatisticsWidget.h" @@ -17,6 +18,7 @@ #include "ProcessUnveiledPathsWidget.h" #include "ThreadStackWidget.h" #include +#include #include #include #include @@ -60,18 +62,42 @@ static void build_performance_tab(GUI::Widget&); static RefPtr statusbar; +namespace SystemMonitor { + +class ProgressbarPaintingDelegate final : public GUI::TableCellPaintingDelegate { +public: + virtual ~ProgressbarPaintingDelegate() override = default; + + virtual void paint(GUI::Painter& painter, Gfx::IntRect const& a_rect, Palette const& palette, GUI::ModelIndex const& index) override + { + auto rect = a_rect.shrunken(2, 2); + auto percentage = index.data(GUI::ModelRole::Custom).to_i32(); + + auto data = index.data(); + String text; + if (data.is_string()) + text = data.as_string(); + Gfx::StylePainter::paint_progressbar(painter, rect, palette, 0, 100, percentage, text); + painter.draw_rect(rect, Color::Black); + } +}; + class UnavailableProcessWidget final : public GUI::Frame { C_OBJECT(UnavailableProcessWidget) public: virtual ~UnavailableProcessWidget() override = default; String const& text() const { return m_text; } - void set_text(String text) { m_text = move(text); } + void set_text(String text) + { + m_text = move(text); + update(); + } private: - UnavailableProcessWidget(String text) - : m_text(move(text)) + UnavailableProcessWidget() { + REGISTER_STRING_PROPERTY("text", text, set_text); } virtual void paint_event(GUI::PaintEvent& event) override @@ -87,10 +113,6 @@ private: String m_text; }; -class ProgressbarPaintingDelegate; - -namespace SystemMonitor { - class HardwareTabWidget final : public GUI::LazyWidget { C_OBJECT(HardwareTabWidget) @@ -287,6 +309,7 @@ public: REGISTER_WIDGET(SystemMonitor, HardwareTabWidget) REGISTER_WIDGET(SystemMonitor, StorageTabWidget) +REGISTER_WIDGET(SystemMonitor, UnavailableProcessWidget) static bool can_access_pid(pid_t pid) { @@ -308,7 +331,7 @@ ErrorOr serenity_main(Main::Arguments arguments) TRY(Core::System::pledge("stdio thread proc recvfd sendfd rpath exec unix")); - auto app = TRY(GUI::Application::try_create(arguments)); + auto app = TRY(GUI::Application::try_create(arguments, Core::EventLoop::MakeInspectable::Yes)); Config::pledge_domain("SystemMonitor"); @@ -564,24 +587,6 @@ ErrorOr serenity_main(Main::Arguments arguments) return app->exec(); } -class ProgressbarPaintingDelegate final : public GUI::TableCellPaintingDelegate { -public: - virtual ~ProgressbarPaintingDelegate() override = default; - - virtual void paint(GUI::Painter& painter, Gfx::IntRect const& a_rect, Palette const& palette, const GUI::ModelIndex& index) override - { - auto rect = a_rect.shrunken(2, 2); - auto percentage = index.data(GUI::ModelRole::Custom).to_i32(); - - auto data = index.data(); - String text; - if (data.is_string()) - text = data.as_string(); - Gfx::StylePainter::paint_progressbar(painter, rect, palette, 0, 100, percentage, text); - painter.draw_rect(rect, Color::Black); - } -}; - ErrorOr> build_process_window(pid_t pid) { auto window = GUI::Window::construct(); @@ -592,17 +597,7 @@ ErrorOr> build_process_window(pid_t pid) window->set_icon(app_icon.bitmap_for_size(16)); auto main_widget = TRY(window->try_set_main_widget()); - main_widget->set_fill_with_background_color(true); - main_widget->set_layout(); - - auto& hero_container = main_widget->add(); - hero_container.set_shrink_to_fit(true); - hero_container.set_layout(); - hero_container.layout()->set_margins(4); - hero_container.layout()->set_spacing(8); - - auto& icon_label = hero_container.add(); - icon_label.set_fixed_size(32, 32); + main_widget->load_from_gml(process_window_gml); GUI::ModelIndex process_index; for (int row = 0; row < ProcessModel::the().row_count({}); ++row) { @@ -615,36 +610,23 @@ ErrorOr> build_process_window(pid_t pid) VERIFY(process_index.is_valid()); if (auto icon_data = process_index.sibling_at_column(ProcessModel::Column::Icon).data(); icon_data.is_icon()) { - icon_label.set_icon(icon_data.as_icon().bitmap_for_size(32)); + main_widget->find_descendant_of_type_named("icon_label")->set_icon(icon_data.as_icon().bitmap_for_size(32)); } - auto& process_name_label = hero_container.add(); - process_name_label.set_font(Gfx::FontDatabase::default_font().bold_variant()); - process_name_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); - process_name_label.set_text(String::formatted("{} (PID {})", - process_index.sibling_at_column(ProcessModel::Column::Name).data().to_string(), - pid)); + main_widget->find_descendant_of_type_named("process_name")->set_text(String::formatted("{} (PID {})", process_index.sibling_at_column(ProcessModel::Column::Name).data().to_string(), pid)); - auto& separator = main_widget->add(); - separator.set_fixed_height(2); + main_widget->find_descendant_of_type_named("process_state")->set_pid(pid); + main_widget->find_descendant_of_type_named("open_files")->set_pid(pid); + main_widget->find_descendant_of_type_named("thread_stack")->set_ids(pid, pid); + main_widget->find_descendant_of_type_named("memory_map")->set_pid(pid); + main_widget->find_descendant_of_type_named("unveiled_paths")->set_pid(pid); - auto& widget_stack = main_widget->add(); - auto& unavailable_process_widget = widget_stack.add(String::formatted("Unable to access PID {}", pid)); - - auto& process_tab_widget = widget_stack.add(); - process_tab_widget.add_tab("State", pid); - auto& memory_map_widget = process_tab_widget.add_tab("Memory map"); - auto& open_files_widget = process_tab_widget.add_tab("Open files"); - auto& unveiled_paths_widget = process_tab_widget.add_tab("Unveiled paths"); - auto& thread_stack_widget = process_tab_widget.add_tab("Stack"); - - open_files_widget.set_pid(pid); - thread_stack_widget.set_ids(pid, pid); - memory_map_widget.set_pid(pid); - unveiled_paths_widget.set_pid(pid); + auto& widget_stack = *main_widget->find_descendant_of_type_named("widget_stack"); + auto& unavailable_process_widget = *widget_stack.find_descendant_of_type_named("unavailable_process"); + unavailable_process_widget.set_text(String::formatted("Unable to access PID {}", pid)); if (can_access_pid(pid)) - widget_stack.set_active_widget(&process_tab_widget); + widget_stack.set_active_widget(widget_stack.find_descendant_of_type_named("available_process")); else widget_stack.set_active_widget(&unavailable_process_widget);