diff --git a/Applications/SystemMonitor/MemoryStatsWidget.cpp b/Applications/SystemMonitor/MemoryStatsWidget.cpp index 002993c194..5895b9a1e9 100644 --- a/Applications/SystemMonitor/MemoryStatsWidget.cpp +++ b/Applications/SystemMonitor/MemoryStatsWidget.cpp @@ -1,18 +1,28 @@ #include "MemoryStatsWidget.h" #include "GraphWidget.h" #include +#include #include #include #include -#include #include #include +static MemoryStatsWidget* s_the; + +MemoryStatsWidget* MemoryStatsWidget::the() +{ + return s_the; +} + MemoryStatsWidget::MemoryStatsWidget(GraphWidget& graph, GWidget* parent) : GWidget(parent) , m_graph(graph) , m_proc_memstat(CFile::construct("/proc/memstat")) { + ASSERT(!s_the); + s_the = this; + if (!m_proc_memstat->open(CIODevice::OpenMode::ReadOnly)) ASSERT_NOT_REACHED(); set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); diff --git a/Applications/SystemMonitor/MemoryStatsWidget.h b/Applications/SystemMonitor/MemoryStatsWidget.h index d63f338836..f2ce831188 100644 --- a/Applications/SystemMonitor/MemoryStatsWidget.h +++ b/Applications/SystemMonitor/MemoryStatsWidget.h @@ -9,12 +9,15 @@ class GraphWidget; class MemoryStatsWidget final : public GWidget { C_OBJECT(MemoryStatsWidget) public: - MemoryStatsWidget(GraphWidget& graph, GWidget* parent); + static MemoryStatsWidget* the(); + virtual ~MemoryStatsWidget() override; void refresh(); private: + MemoryStatsWidget(GraphWidget& graph, GWidget* parent); + virtual void timer_event(CTimerEvent&) override; GraphWidget& m_graph; diff --git a/Applications/SystemMonitor/NetworkStatisticsWidget.cpp b/Applications/SystemMonitor/NetworkStatisticsWidget.cpp index 38e7b9a1bb..e9001cd6ef 100644 --- a/Applications/SystemMonitor/NetworkStatisticsWidget.cpp +++ b/Applications/SystemMonitor/NetworkStatisticsWidget.cpp @@ -5,63 +5,65 @@ #include NetworkStatisticsWidget::NetworkStatisticsWidget(GWidget* parent) - : GWidget(parent) + : GLazyWidget(parent) { - set_layout(make(Orientation::Vertical)); - layout()->set_margins({ 4, 4, 4, 4 }); - set_fill_with_background_color(true); - set_background_color(Color::WarmGray); + on_first_show = [this](auto&) { + set_layout(make(Orientation::Vertical)); + layout()->set_margins({ 4, 4, 4, 4 }); + set_fill_with_background_color(true); + set_background_color(Color::WarmGray); - auto adapters_group_box = GGroupBox::construct("Adapters", this); - adapters_group_box->set_layout(make(Orientation::Vertical)); - adapters_group_box->layout()->set_margins({ 6, 16, 6, 6 }); - adapters_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); - adapters_group_box->set_preferred_size(0, 120); + auto adapters_group_box = GGroupBox::construct("Adapters", this); + adapters_group_box->set_layout(make(Orientation::Vertical)); + adapters_group_box->layout()->set_margins({ 6, 16, 6, 6 }); + adapters_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + adapters_group_box->set_preferred_size(0, 120); - m_adapter_table_view = GTableView::construct(adapters_group_box); - m_adapter_table_view->set_size_columns_to_fit_content(true); + m_adapter_table_view = GTableView::construct(adapters_group_box); + m_adapter_table_view->set_size_columns_to_fit_content(true); - Vector net_adapters_fields; - net_adapters_fields.empend("name", "Name", TextAlignment::CenterLeft); - net_adapters_fields.empend("class_name", "Class", TextAlignment::CenterLeft); - net_adapters_fields.empend("mac_address", "MAC", TextAlignment::CenterLeft); - net_adapters_fields.empend("ipv4_address", "IPv4", TextAlignment::CenterLeft); - net_adapters_fields.empend("packets_in", "Pkt In", TextAlignment::CenterRight); - net_adapters_fields.empend("packets_out", "Pkt Out", TextAlignment::CenterRight); - net_adapters_fields.empend("bytes_in", "Bytes In", TextAlignment::CenterRight); - net_adapters_fields.empend("bytes_out", "Bytes Out", TextAlignment::CenterRight); - m_adapter_table_view->set_model(GJsonArrayModel::create("/proc/net/adapters", move(net_adapters_fields))); + Vector net_adapters_fields; + net_adapters_fields.empend("name", "Name", TextAlignment::CenterLeft); + net_adapters_fields.empend("class_name", "Class", TextAlignment::CenterLeft); + net_adapters_fields.empend("mac_address", "MAC", TextAlignment::CenterLeft); + net_adapters_fields.empend("ipv4_address", "IPv4", TextAlignment::CenterLeft); + net_adapters_fields.empend("packets_in", "Pkt In", TextAlignment::CenterRight); + net_adapters_fields.empend("packets_out", "Pkt Out", TextAlignment::CenterRight); + net_adapters_fields.empend("bytes_in", "Bytes In", TextAlignment::CenterRight); + net_adapters_fields.empend("bytes_out", "Bytes Out", TextAlignment::CenterRight); + m_adapter_table_view->set_model(GJsonArrayModel::create("/proc/net/adapters", move(net_adapters_fields))); - auto sockets_group_box = GGroupBox::construct("Sockets", this); - sockets_group_box->set_layout(make(Orientation::Vertical)); - sockets_group_box->layout()->set_margins({ 6, 16, 6, 6 }); - sockets_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fill); - sockets_group_box->set_preferred_size(0, 0); + auto sockets_group_box = GGroupBox::construct("Sockets", this); + sockets_group_box->set_layout(make(Orientation::Vertical)); + sockets_group_box->layout()->set_margins({ 6, 16, 6, 6 }); + sockets_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fill); + sockets_group_box->set_preferred_size(0, 0); - m_socket_table_view = GTableView::construct(sockets_group_box); - m_socket_table_view->set_size_columns_to_fit_content(true); + m_socket_table_view = GTableView::construct(sockets_group_box); + m_socket_table_view->set_size_columns_to_fit_content(true); - Vector net_tcp_fields; - net_tcp_fields.empend("peer_address", "Peer", TextAlignment::CenterLeft); - net_tcp_fields.empend("peer_port", "Port", TextAlignment::CenterRight); - net_tcp_fields.empend("local_address", "Local", TextAlignment::CenterLeft); - net_tcp_fields.empend("local_port", "Port", TextAlignment::CenterRight); - net_tcp_fields.empend("state", "State", TextAlignment::CenterLeft); - net_tcp_fields.empend("ack_number", "Ack#", TextAlignment::CenterRight); - net_tcp_fields.empend("sequence_number", "Seq#", TextAlignment::CenterRight); - net_tcp_fields.empend("packets_in", "Pkt In", TextAlignment::CenterRight); - net_tcp_fields.empend("packets_out", "Pkt Out", TextAlignment::CenterRight); - net_tcp_fields.empend("bytes_in", "Bytes In", TextAlignment::CenterRight); - net_tcp_fields.empend("bytes_out", "Bytes Out", TextAlignment::CenterRight); - m_socket_table_view->set_model(GJsonArrayModel::create("/proc/net/tcp", move(net_tcp_fields))); + Vector net_tcp_fields; + net_tcp_fields.empend("peer_address", "Peer", TextAlignment::CenterLeft); + net_tcp_fields.empend("peer_port", "Port", TextAlignment::CenterRight); + net_tcp_fields.empend("local_address", "Local", TextAlignment::CenterLeft); + net_tcp_fields.empend("local_port", "Port", TextAlignment::CenterRight); + net_tcp_fields.empend("state", "State", TextAlignment::CenterLeft); + net_tcp_fields.empend("ack_number", "Ack#", TextAlignment::CenterRight); + net_tcp_fields.empend("sequence_number", "Seq#", TextAlignment::CenterRight); + net_tcp_fields.empend("packets_in", "Pkt In", TextAlignment::CenterRight); + net_tcp_fields.empend("packets_out", "Pkt Out", TextAlignment::CenterRight); + net_tcp_fields.empend("bytes_in", "Bytes In", TextAlignment::CenterRight); + net_tcp_fields.empend("bytes_out", "Bytes Out", TextAlignment::CenterRight); + m_socket_table_view->set_model(GJsonArrayModel::create("/proc/net/tcp", move(net_tcp_fields))); - m_update_timer = CTimer::construct( - 1000, [this] { - update_models(); - }, - this); + m_update_timer = CTimer::construct( + 1000, [this] { + update_models(); + }, + this); - update_models(); + update_models(); + }; } NetworkStatisticsWidget::~NetworkStatisticsWidget() diff --git a/Applications/SystemMonitor/NetworkStatisticsWidget.h b/Applications/SystemMonitor/NetworkStatisticsWidget.h index f383289cc2..c46ee86ef2 100644 --- a/Applications/SystemMonitor/NetworkStatisticsWidget.h +++ b/Applications/SystemMonitor/NetworkStatisticsWidget.h @@ -1,11 +1,11 @@ #pragma once #include -#include +#include class GTableView; -class NetworkStatisticsWidget final : public GWidget { +class NetworkStatisticsWidget final : public GLazyWidget { C_OBJECT(NetworkStatisticsWidget) public: virtual ~NetworkStatisticsWidget() override; diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp index 32c96b3280..ec79fa0c99 100644 --- a/Applications/SystemMonitor/ProcessModel.cpp +++ b/Applications/SystemMonitor/ProcessModel.cpp @@ -8,9 +8,18 @@ #include #include -ProcessModel::ProcessModel(GraphWidget& graph) - : m_graph(graph) +static ProcessModel* s_the; + +ProcessModel& ProcessModel::the() { + ASSERT(s_the); + return *s_the; +} + +ProcessModel::ProcessModel() +{ + ASSERT(!s_the); + s_the = this; m_generic_process_icon = GraphicsBitmap::load_from_file("/res/icons/gear16.png"); m_high_priority_icon = GraphicsBitmap::load_from_file("/res/icons/highpriority16.png"); m_low_priority_icon = GraphicsBitmap::load_from_file("/res/icons/lowpriority16.png"); @@ -263,7 +272,8 @@ void ProcessModel::update() for (auto pid : pids_to_remove) m_processes.remove(pid); - m_graph.add_value(total_cpu_percent); + if (on_new_cpu_data_point) + on_new_cpu_data_point(total_cpu_percent); did_update(); } diff --git a/Applications/SystemMonitor/ProcessModel.h b/Applications/SystemMonitor/ProcessModel.h index 21381f2fed..fc54488583 100644 --- a/Applications/SystemMonitor/ProcessModel.h +++ b/Applications/SystemMonitor/ProcessModel.h @@ -27,7 +27,9 @@ public: __Count }; - static NonnullRefPtr create(GraphWidget& graph) { return adopt(*new ProcessModel(graph)); } + static ProcessModel& the(); + + static NonnullRefPtr create() { return adopt(*new ProcessModel); } virtual ~ProcessModel() override; virtual int row_count(const GModelIndex&) const override; @@ -37,10 +39,10 @@ public: virtual GVariant data(const GModelIndex&, Role = Role::Display) const override; virtual void update() override; -private: - explicit ProcessModel(GraphWidget&); + Function on_new_cpu_data_point; - GraphWidget& m_graph; +private: + ProcessModel(); struct ProcessState { pid_t pid; diff --git a/Applications/SystemMonitor/ProcessTableView.cpp b/Applications/SystemMonitor/ProcessTableView.cpp index 5c599638a6..bff0170322 100644 --- a/Applications/SystemMonitor/ProcessTableView.cpp +++ b/Applications/SystemMonitor/ProcessTableView.cpp @@ -3,11 +3,11 @@ #include #include -ProcessTableView::ProcessTableView(GraphWidget& graph, GWidget* parent) +ProcessTableView::ProcessTableView(GWidget* parent) : GTableView(parent) { set_size_columns_to_fit_content(true); - set_model(GSortingProxyModel::create(ProcessModel::create(graph))); + set_model(GSortingProxyModel::create(ProcessModel::create())); model()->set_key_column_and_sort_order(ProcessModel::Column::CPU, GSortOrder::Descending); refresh(); diff --git a/Applications/SystemMonitor/ProcessTableView.h b/Applications/SystemMonitor/ProcessTableView.h index c193e214f4..6cf85e5797 100644 --- a/Applications/SystemMonitor/ProcessTableView.h +++ b/Applications/SystemMonitor/ProcessTableView.h @@ -19,5 +19,5 @@ public: Function on_process_selected; private: - ProcessTableView(GraphWidget&, GWidget* parent); + explicit ProcessTableView(GWidget* parent = nullptr); }; diff --git a/Applications/SystemMonitor/main.cpp b/Applications/SystemMonitor/main.cpp index 36a53cbb1b..a5f1f4f457 100644 --- a/Applications/SystemMonitor/main.cpp +++ b/Applications/SystemMonitor/main.cpp @@ -4,6 +4,7 @@ #include "NetworkStatisticsWidget.h" #include "ProcessFileDescriptorMapWidget.h" #include "ProcessMemoryMapWidget.h" +#include "ProcessModel.h" #include "ProcessStacksWidget.h" #include "ProcessTableView.h" #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +44,7 @@ static String human_readable_size(u32 size) static RefPtr build_file_systems_tab(); static RefPtr build_pci_devices_tab(); static RefPtr build_devices_tab(); +static NonnullRefPtr build_graphs_tab(); int main(int argc, char** argv) { @@ -60,38 +63,7 @@ int main(int argc, char** argv) auto process_table_container = GWidget::construct(process_container_splitter.ptr()); - auto graphs_container = GWidget::construct(); - graphs_container->set_fill_with_background_color(true); - graphs_container->set_background_color(Color::WarmGray); - graphs_container->set_layout(make(Orientation::Vertical)); - graphs_container->layout()->set_margins({ 4, 4, 4, 4 }); - - auto cpu_graph_group_box = GGroupBox::construct("CPU usage", graphs_container); - cpu_graph_group_box->set_layout(make(Orientation::Vertical)); - cpu_graph_group_box->layout()->set_margins({ 6, 16, 6, 6 }); - cpu_graph_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); - cpu_graph_group_box->set_preferred_size(0, 120); - auto cpu_graph = GraphWidget::construct(cpu_graph_group_box); - cpu_graph->set_max(100); - cpu_graph->set_text_color(Color::Green); - cpu_graph->set_graph_color(Color::from_rgb(0x00bb00)); - cpu_graph->text_formatter = [](int value, int) { - return String::format("%d%%", value); - }; - - auto memory_graph_group_box = GGroupBox::construct("Memory usage", graphs_container); - memory_graph_group_box->set_layout(make(Orientation::Vertical)); - memory_graph_group_box->layout()->set_margins({ 6, 16, 6, 6 }); - memory_graph_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); - memory_graph_group_box->set_preferred_size(0, 120); - auto memory_graph = GraphWidget::construct(memory_graph_group_box); - memory_graph->set_text_color(Color::Cyan); - memory_graph->set_graph_color(Color::from_rgb(0x00bbbb)); - memory_graph->text_formatter = [](int value, int max) { - return String::format("%d / %d KB", value, max); - }; - - tabwidget->add_widget("Graphs", graphs_container); + tabwidget->add_widget("Graphs", build_graphs_tab()); tabwidget->add_widget("File systems", build_file_systems_tab()); @@ -108,12 +80,12 @@ int main(int argc, char** argv) auto toolbar = GToolBar::construct(process_table_container); toolbar->set_has_frame(false); - auto process_table_view = ProcessTableView::construct(*cpu_graph, process_table_container); - auto memory_stats_widget = MemoryStatsWidget::construct(*memory_graph, graphs_container); + auto process_table_view = ProcessTableView::construct(process_table_container); auto refresh_timer = CTimer::construct(1000, [&] { process_table_view->refresh(); - memory_stats_widget->refresh(); + if (auto* memory_stats_widget = MemoryStatsWidget::the()) + memory_stats_widget->refresh(); }); auto kill_action = GAction::create("Kill process", GraphicsBitmap::load_from_file("/res/icons/kill16.png"), [process_table_view](const GAction&) { @@ -236,133 +208,186 @@ public: RefPtr build_file_systems_tab() { - auto fs_widget = GWidget::construct(); - fs_widget->set_layout(make(Orientation::Vertical)); - fs_widget->layout()->set_margins({ 4, 4, 4, 4 }); - auto fs_table_view = GTableView::construct(fs_widget); - fs_table_view->set_size_columns_to_fit_content(true); + auto fs_widget = GLazyWidget::construct(); - Vector df_fields; - df_fields.empend("mount_point", "Mount point", TextAlignment::CenterLeft); - df_fields.empend("class_name", "Class", TextAlignment::CenterLeft); - df_fields.empend( - "Size", TextAlignment::CenterRight, - [](const JsonObject& object) { - return human_readable_size(object.get("total_block_count").to_u32() * object.get("block_size").to_u32()); - }, - [](const JsonObject& object) { - return object.get("total_block_count").to_u32() * object.get("block_size").to_u32(); - }); - df_fields.empend( - "Used", TextAlignment::CenterRight, - [](const JsonObject& object) { + fs_widget->on_first_show = [](auto& self) { + self.set_layout(make(Orientation::Vertical)); + self.layout()->set_margins({ 4, 4, 4, 4 }); + auto fs_table_view = GTableView::construct(&self); + fs_table_view->set_size_columns_to_fit_content(true); + + Vector df_fields; + df_fields.empend("mount_point", "Mount point", TextAlignment::CenterLeft); + df_fields.empend("class_name", "Class", TextAlignment::CenterLeft); + df_fields.empend( + "Size", TextAlignment::CenterRight, + [](const JsonObject& object) { + return human_readable_size(object.get("total_block_count").to_u32() * object.get("block_size").to_u32()); + }, + [](const JsonObject& object) { + return object.get("total_block_count").to_u32() * object.get("block_size").to_u32(); + }); + df_fields.empend( + "Used", TextAlignment::CenterRight, + [](const JsonObject& object) { auto total_blocks = object.get("total_block_count").to_u32(); auto free_blocks = object.get("free_block_count").to_u32(); auto used_blocks = total_blocks - free_blocks; return human_readable_size(used_blocks * object.get("block_size").to_u32()); }, - [](const JsonObject& object) { - auto total_blocks = object.get("total_block_count").to_u32(); - auto free_blocks = object.get("free_block_count").to_u32(); - auto used_blocks = total_blocks - free_blocks; - return used_blocks * object.get("block_size").to_u32(); - }, - [](const JsonObject& object) { - auto total_blocks = object.get("total_block_count").to_u32(); - if (total_blocks == 0) - return 0; - auto free_blocks = object.get("free_block_count").to_u32(); - auto used_blocks = total_blocks - free_blocks; - int percentage = (int)((float)used_blocks / (float)total_blocks * 100.0f); - return percentage; + [](const JsonObject& object) { + auto total_blocks = object.get("total_block_count").to_u32(); + auto free_blocks = object.get("free_block_count").to_u32(); + auto used_blocks = total_blocks - free_blocks; + return used_blocks * object.get("block_size").to_u32(); + }, + [](const JsonObject& object) { + auto total_blocks = object.get("total_block_count").to_u32(); + if (total_blocks == 0) + return 0; + auto free_blocks = object.get("free_block_count").to_u32(); + auto used_blocks = total_blocks - free_blocks; + int percentage = (int)((float)used_blocks / (float)total_blocks * 100.0f); + return percentage; + }); + df_fields.empend( + "Available", TextAlignment::CenterRight, + [](const JsonObject& object) { + return human_readable_size(object.get("free_block_count").to_u32() * object.get("block_size").to_u32()); + }, + [](const JsonObject& object) { + return object.get("free_block_count").to_u32() * object.get("block_size").to_u32(); + }); + df_fields.empend("Access", TextAlignment::CenterLeft, [](const JsonObject& object) { + return object.get("readonly").to_bool() ? "Read-only" : "Read/Write"; }); - df_fields.empend( - "Available", TextAlignment::CenterRight, - [](const JsonObject& object) { - return human_readable_size(object.get("free_block_count").to_u32() * object.get("block_size").to_u32()); - }, - [](const JsonObject& object) { - return object.get("free_block_count").to_u32() * object.get("block_size").to_u32(); - }); - df_fields.empend("Access", TextAlignment::CenterLeft, [](const JsonObject& object) { - return object.get("readonly").to_bool() ? "Read-only" : "Read/Write"; - }); - df_fields.empend("free_block_count", "Free blocks", TextAlignment::CenterRight); - df_fields.empend("total_block_count", "Total blocks", TextAlignment::CenterRight); - df_fields.empend("free_inode_count", "Free inodes", TextAlignment::CenterRight); - df_fields.empend("total_inode_count", "Total inodes", TextAlignment::CenterRight); - df_fields.empend("block_size", "Block size", TextAlignment::CenterRight); - fs_table_view->set_model(GSortingProxyModel::create(GJsonArrayModel::create("/proc/df", move(df_fields)))); + df_fields.empend("free_block_count", "Free blocks", TextAlignment::CenterRight); + df_fields.empend("total_block_count", "Total blocks", TextAlignment::CenterRight); + df_fields.empend("free_inode_count", "Free inodes", TextAlignment::CenterRight); + df_fields.empend("total_inode_count", "Total inodes", TextAlignment::CenterRight); + df_fields.empend("block_size", "Block size", TextAlignment::CenterRight); + fs_table_view->set_model(GSortingProxyModel::create(GJsonArrayModel::create("/proc/df", move(df_fields)))); - fs_table_view->set_cell_painting_delegate(3, make()); + fs_table_view->set_cell_painting_delegate(3, make()); - fs_table_view->model()->update(); + fs_table_view->model()->update(); + }; return fs_widget; } RefPtr build_pci_devices_tab() { - auto pci_widget = GWidget::construct(); - pci_widget->set_layout(make(Orientation::Vertical)); - pci_widget->layout()->set_margins({ 4, 4, 4, 4 }); - auto pci_table_view = GTableView::construct(pci_widget); - pci_table_view->set_size_columns_to_fit_content(true); + auto pci_widget = GLazyWidget::construct(); - auto db = PCIDB::Database::open(); + pci_widget->on_first_show = [](auto& self) { + self.set_layout(make(Orientation::Vertical)); + self.layout()->set_margins({ 4, 4, 4, 4 }); + auto pci_table_view = GTableView::construct(&self); + pci_table_view->set_size_columns_to_fit_content(true); - Vector pci_fields; - pci_fields.empend( - "Address", TextAlignment::CenterLeft, - [](const JsonObject& object) { - auto bus = object.get("bus").to_u32(); - auto slot = object.get("slot").to_u32(); - auto function = object.get("function").to_u32(); - return String::format("%02x:%02x.%d", bus, slot, function); - }); - pci_fields.empend( - "Class", TextAlignment::CenterLeft, - [db](const JsonObject& object) { - auto class_id = object.get("class").to_u32(); - String class_name = db->get_class(class_id); - return class_name == "" ? String::format("%04x", class_id) : class_name; - }); - pci_fields.empend( - "Vendor", TextAlignment::CenterLeft, - [db](const JsonObject& object) { - auto vendor_id = object.get("vendor_id").to_u32(); - String vendor_name = db->get_vendor(vendor_id); - return vendor_name == "" ? String::format("%02x", vendor_id) : vendor_name; - }); - pci_fields.empend( - "Device", TextAlignment::CenterLeft, - [db](const JsonObject& object) { - auto vendor_id = object.get("vendor_id").to_u32(); - auto device_id = object.get("device_id").to_u32(); - String device_name = db->get_device(vendor_id, device_id); - return device_name == "" ? String::format("%02x", device_id) : device_name; - }); - pci_fields.empend( - "Revision", TextAlignment::CenterRight, - [](const JsonObject& object) { - auto revision_id = object.get("revision_id").to_u32(); - return String::format("%02x", revision_id); - }); + auto db = PCIDB::Database::open(); - pci_table_view->set_model(GSortingProxyModel::create(GJsonArrayModel::create("/proc/pci", move(pci_fields)))); - pci_table_view->model()->update(); + Vector pci_fields; + pci_fields.empend( + "Address", TextAlignment::CenterLeft, + [](const JsonObject& object) { + auto bus = object.get("bus").to_u32(); + auto slot = object.get("slot").to_u32(); + auto function = object.get("function").to_u32(); + return String::format("%02x:%02x.%d", bus, slot, function); + }); + pci_fields.empend( + "Class", TextAlignment::CenterLeft, + [db](const JsonObject& object) { + auto class_id = object.get("class").to_u32(); + String class_name = db->get_class(class_id); + return class_name == "" ? String::format("%04x", class_id) : class_name; + }); + pci_fields.empend( + "Vendor", TextAlignment::CenterLeft, + [db](const JsonObject& object) { + auto vendor_id = object.get("vendor_id").to_u32(); + String vendor_name = db->get_vendor(vendor_id); + return vendor_name == "" ? String::format("%02x", vendor_id) : vendor_name; + }); + pci_fields.empend( + "Device", TextAlignment::CenterLeft, + [db](const JsonObject& object) { + auto vendor_id = object.get("vendor_id").to_u32(); + auto device_id = object.get("device_id").to_u32(); + String device_name = db->get_device(vendor_id, device_id); + return device_name == "" ? String::format("%02x", device_id) : device_name; + }); + pci_fields.empend( + "Revision", TextAlignment::CenterRight, + [](const JsonObject& object) { + auto revision_id = object.get("revision_id").to_u32(); + return String::format("%02x", revision_id); + }); + + pci_table_view->set_model(GSortingProxyModel::create(GJsonArrayModel::create("/proc/pci", move(pci_fields)))); + pci_table_view->model()->update(); + }; return pci_widget; } RefPtr build_devices_tab() { - auto devices_widget = GWidget::construct(); - devices_widget->set_layout(make(Orientation::Vertical)); - devices_widget->layout()->set_margins({ 4, 4, 4, 4 }); + auto devices_widget = GLazyWidget::construct(); - auto devices_table_view = GTableView::construct(devices_widget); - devices_table_view->set_size_columns_to_fit_content(true); - devices_table_view->set_model(GSortingProxyModel::create(DevicesModel::create())); - devices_table_view->model()->update(); + devices_widget->on_first_show = [](auto& self) { + self.set_layout(make(Orientation::Vertical)); + self.layout()->set_margins({ 4, 4, 4, 4 }); + + auto devices_table_view = GTableView::construct(&self); + devices_table_view->set_size_columns_to_fit_content(true); + devices_table_view->set_model(GSortingProxyModel::create(DevicesModel::create())); + devices_table_view->model()->update(); + }; return devices_widget; } + +NonnullRefPtr build_graphs_tab() +{ + auto graphs_container = GLazyWidget::construct(); + + graphs_container->on_first_show = [](auto& self) { + self.set_fill_with_background_color(true); + self.set_background_color(Color::WarmGray); + self.set_layout(make(Orientation::Vertical)); + self.layout()->set_margins({ 4, 4, 4, 4 }); + + auto cpu_graph_group_box = GGroupBox::construct("CPU usage", &self); + cpu_graph_group_box->set_layout(make(Orientation::Vertical)); + cpu_graph_group_box->layout()->set_margins({ 6, 16, 6, 6 }); + cpu_graph_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + cpu_graph_group_box->set_preferred_size(0, 120); + auto cpu_graph = GraphWidget::construct(cpu_graph_group_box); + cpu_graph->set_max(100); + cpu_graph->set_text_color(Color::Green); + cpu_graph->set_graph_color(Color::from_rgb(0x00bb00)); + cpu_graph->text_formatter = [](int value, int) { + return String::format("%d%%", value); + }; + + ProcessModel::the().on_new_cpu_data_point = [graph = cpu_graph.ptr()](float cpu_percent) { + graph->add_value(cpu_percent); + }; + + auto memory_graph_group_box = GGroupBox::construct("Memory usage", &self); + memory_graph_group_box->set_layout(make(Orientation::Vertical)); + memory_graph_group_box->layout()->set_margins({ 6, 16, 6, 6 }); + memory_graph_group_box->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + memory_graph_group_box->set_preferred_size(0, 120); + auto memory_graph = GraphWidget::construct(memory_graph_group_box); + memory_graph->set_text_color(Color::Cyan); + memory_graph->set_graph_color(Color::from_rgb(0x00bbbb)); + memory_graph->text_formatter = [](int value, int max) { + return String::format("%d / %d KB", value, max); + }; + + auto memory_stats_widget = MemoryStatsWidget::construct(*memory_graph, &self); + }; + return graphs_container; +}