diff options
Diffstat (limited to 'Applications/SystemMonitor')
22 files changed, 0 insertions, 2782 deletions
diff --git a/Applications/SystemMonitor/CMakeLists.txt b/Applications/SystemMonitor/CMakeLists.txt deleted file mode 100644 index ee2e4d2323..0000000000 --- a/Applications/SystemMonitor/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(SOURCES - DevicesModel.cpp - GraphWidget.cpp - InterruptsWidget.cpp - main.cpp - MemoryStatsWidget.cpp - NetworkStatisticsWidget.cpp - ProcessFileDescriptorMapWidget.cpp - ProcessMemoryMapWidget.cpp - ProcessModel.cpp - ProcessUnveiledPathsWidget.cpp - ThreadStackWidget.cpp -) - -serenity_app(SystemMonitor ICON app-system-monitor) -target_link_libraries(SystemMonitor LibGUI LibPCIDB) diff --git a/Applications/SystemMonitor/DevicesModel.cpp b/Applications/SystemMonitor/DevicesModel.cpp deleted file mode 100644 index f0692cdd24..0000000000 --- a/Applications/SystemMonitor/DevicesModel.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "DevicesModel.h" -#include <AK/JsonArray.h> -#include <AK/JsonObject.h> -#include <AK/JsonValue.h> -#include <LibCore/DirIterator.h> -#include <LibCore/File.h> -#include <sys/stat.h> - -NonnullRefPtr<DevicesModel> DevicesModel::create() -{ - return adopt(*new DevicesModel); -} - -DevicesModel::DevicesModel() -{ -} - -DevicesModel::~DevicesModel() -{ -} - -int DevicesModel::row_count(const GUI::ModelIndex&) const -{ - return m_devices.size(); -} - -int DevicesModel::column_count(const GUI::ModelIndex&) const -{ - return Column::__Count; -} - -String DevicesModel::column_name(int column) const -{ - switch (column) { - case Column::Device: - return "Device"; - case Column::Major: - return "Major"; - case Column::Minor: - return "Minor"; - case Column::ClassName: - return "Class"; - case Column::Type: - return "Type"; - default: - ASSERT_NOT_REACHED(); - } -} - -GUI::Variant DevicesModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const -{ - ASSERT(is_valid(index)); - - if (role == GUI::ModelRole::TextAlignment) { - switch (index.column()) { - case Column::Device: - return Gfx::TextAlignment::CenterLeft; - case Column::Major: - return Gfx::TextAlignment::CenterRight; - case Column::Minor: - return Gfx::TextAlignment::CenterRight; - case Column::ClassName: - return Gfx::TextAlignment::CenterLeft; - case Column::Type: - return Gfx::TextAlignment::CenterLeft; - } - return {}; - } - - if (role == GUI::ModelRole::Sort) { - const DeviceInfo& device = m_devices[index.row()]; - switch (index.column()) { - case Column::Device: - return device.path; - case Column::Major: - return device.major; - case Column::Minor: - return device.minor; - case Column::ClassName: - return device.class_name; - case Column::Type: - return device.type; - default: - ASSERT_NOT_REACHED(); - } - } - - if (role == GUI::ModelRole::Display) { - const DeviceInfo& device = m_devices[index.row()]; - switch (index.column()) { - case Column::Device: - return device.path; - case Column::Major: - return device.major; - case Column::Minor: - return device.minor; - case Column::ClassName: - return device.class_name; - case Column::Type: - switch (device.type) { - case DeviceInfo::Type::Block: - return "Block"; - case DeviceInfo::Type::Character: - return "Character"; - default: - ASSERT_NOT_REACHED(); - } - default: - ASSERT_NOT_REACHED(); - } - } - - return {}; -} - -void DevicesModel::update() -{ - auto proc_devices = Core::File::construct("/proc/devices"); - if (!proc_devices->open(Core::IODevice::OpenMode::ReadOnly)) - ASSERT_NOT_REACHED(); - - auto json = JsonValue::from_string(proc_devices->read_all()); - ASSERT(json.has_value()); - - m_devices.clear(); - json.value().as_array().for_each([this](auto& value) { - JsonObject device = value.as_object(); - DeviceInfo device_info; - - device_info.major = device.get("major").to_uint(); - device_info.minor = device.get("minor").to_uint(); - device_info.class_name = device.get("class_name").to_string(); - - String type_str = device.get("type").to_string(); - if (type_str == "block") - device_info.type = DeviceInfo::Type::Block; - else if (type_str == "character") - device_info.type = DeviceInfo::Type::Character; - else - ASSERT_NOT_REACHED(); - - m_devices.append(move(device_info)); - }); - - auto fill_in_paths_from_dir = [this](const String& dir) { - Core::DirIterator dir_iter { dir, Core::DirIterator::Flags::SkipDots }; - while (dir_iter.has_next()) { - auto name = dir_iter.next_path(); - auto path = String::format("%s/%s", dir.characters(), name.characters()); - struct stat statbuf; - if (lstat(path.characters(), &statbuf) != 0) { - ASSERT_NOT_REACHED(); - } - if (!S_ISBLK(statbuf.st_mode) && !S_ISCHR(statbuf.st_mode)) - continue; - unsigned _major = major(statbuf.st_rdev); - unsigned _minor = minor(statbuf.st_rdev); - - auto it = m_devices.find_if([_major, _minor](const auto& device_info) { - return device_info.major == _major && device_info.minor == _minor; - }); - if (it != m_devices.end()) { - (*it).path = move(path); - } - } - }; - - fill_in_paths_from_dir("/dev"); - fill_in_paths_from_dir("/dev/pts"); - - did_update(); -} diff --git a/Applications/SystemMonitor/DevicesModel.h b/Applications/SystemMonitor/DevicesModel.h deleted file mode 100644 index dd8cacc7e0..0000000000 --- a/Applications/SystemMonitor/DevicesModel.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/String.h> -#include <AK/Vector.h> -#include <LibGUI/Model.h> - -class DevicesModel final : public GUI::Model { -public: - enum Column { - Device = 0, - Major, - Minor, - ClassName, - Type, - __Count - }; - - virtual ~DevicesModel() override; - static NonnullRefPtr<DevicesModel> create(); - - virtual int row_count(const GUI::ModelIndex&) const override; - virtual int column_count(const GUI::ModelIndex&) const override; - virtual String column_name(int column) const override; - virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override; - virtual void update() override; - -private: - DevicesModel(); - - struct DeviceInfo { - String path; - unsigned major; - unsigned minor; - String class_name; - enum Type { - Block, - Character - }; - Type type; - }; - - Vector<DeviceInfo> m_devices; -}; diff --git a/Applications/SystemMonitor/GraphWidget.cpp b/Applications/SystemMonitor/GraphWidget.cpp deleted file mode 100644 index 5c1d9982d4..0000000000 --- a/Applications/SystemMonitor/GraphWidget.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "GraphWidget.h" -#include <LibGUI/Painter.h> -#include <LibGfx/Font.h> -#include <LibGfx/Path.h> - -GraphWidget::GraphWidget() -{ -} - -GraphWidget::~GraphWidget() -{ -} - -void GraphWidget::add_value(Vector<int, 1>&& value) -{ - m_values.enqueue(move(value)); - update(); -} - -void GraphWidget::paint_event(GUI::PaintEvent& event) -{ - GUI::Frame::paint_event(event); - GUI::Painter painter(*this); - painter.add_clip_rect(event.rect()); - painter.add_clip_rect(frame_inner_rect()); - painter.fill_rect(event.rect(), m_background_color); - - auto inner_rect = frame_inner_rect(); - float scale = (float)inner_rect.height() / (float)m_max; - - if (!m_values.is_empty()) { - // Draw one set of values at a time - for (size_t k = 0; k < m_value_format.size(); k++) { - const auto& format = m_value_format[k]; - if (format.line_color == Color::Transparent && format.background_color == Color::Transparent) - continue; - m_calculated_points.clear_with_capacity(); - for (size_t i = 0; i < m_values.size(); i++) { - int x = inner_rect.right() - (i * 2) + 1; - if (x < 0) - break; - const auto& current_values = m_values.at(m_values.size() - i - 1); - if (current_values.size() <= k) { - // Don't have a data point - m_calculated_points.append({ -1, -1 }); - continue; - } - float value = current_values[k]; - if (m_stack_values) { - for (size_t l = k + 1; l < current_values.size(); l++) - value += current_values[l]; - } - float scaled_value = value * scale; - Gfx::IntPoint current_point { x, inner_rect.bottom() - (int)scaled_value }; - m_calculated_points.append(current_point); - } - ASSERT(m_calculated_points.size() <= m_values.size()); - if (format.background_color != Color::Transparent) { - // Fill the background for the area we have values for - Gfx::Path path; - size_t points_in_path = 0; - bool started_path = false; - const Gfx::IntPoint* current_point = nullptr; - const Gfx::IntPoint* first_point = nullptr; - auto check_fill_area = [&]() { - if (!started_path) - return; - if (points_in_path > 1) { - ASSERT(current_point); - ASSERT(first_point); - path.line_to({ current_point->x() - 1, inner_rect.bottom() + 1 }); - path.line_to({ first_point->x() + 1, inner_rect.bottom() + 1 }); - path.close(); - painter.fill_path(path, format.background_color, Gfx::Painter::WindingRule::EvenOdd); - } else if (points_in_path == 1 && current_point) { - // Can't fill any area, we only have one data point. - // Just draw a vertical line as a "fill"... - painter.draw_line(*current_point, { current_point->x(), inner_rect.bottom() }, format.background_color); - } - path = {}; - points_in_path = 0; - first_point = nullptr; - started_path = false; - }; - for (size_t i = 0; i < m_calculated_points.size(); i++) { - current_point = &m_calculated_points[i]; - if (current_point->x() < 0) { - check_fill_area(); - continue; - } - if (!started_path) { - path.move_to({ current_point->x() + 1, current_point->y() }); - points_in_path = 1; - first_point = current_point; - started_path = true; - } else { - path.line_to({ current_point->x(), current_point->y() }); - points_in_path++; - } - } - check_fill_area(); - } - if (format.line_color != Color::Transparent) { - // Draw the line for the data points we have - const Gfx::IntPoint* previous_point = nullptr; - for (size_t i = 0; i < m_calculated_points.size(); i++) { - const auto& current_point = m_calculated_points[i]; - if (current_point.x() < 0) { - previous_point = nullptr; - continue; - } - if (previous_point) - painter.draw_line(*previous_point, current_point, format.line_color); - previous_point = ¤t_point; - } - } - } - } - - if (!m_values.is_empty() && !m_value_format.is_empty()) { - const auto& current_values = m_values.last(); - int y = 0; - for (size_t i = 0; i < min(m_value_format.size(), current_values.size()); i++) { - const auto& format = m_value_format[i]; - if (!format.text_formatter) - continue; - auto constrain_rect = inner_rect.shrunken(8, 8); - auto text_rect = constrain_rect.translated(0, y).intersected(constrain_rect); - text_rect.set_height(font().glyph_height()); - auto text = format.text_formatter(current_values[i]); - if (format.text_shadow_color != Color::Transparent) - painter.draw_text(text_rect.translated(1, 1), text.characters(), Gfx::TextAlignment::CenterRight, format.text_shadow_color); - painter.draw_text(text_rect, text.characters(), Gfx::TextAlignment::CenterRight, format.line_color); - y += text_rect.height() + 4; - } - } -} diff --git a/Applications/SystemMonitor/GraphWidget.h b/Applications/SystemMonitor/GraphWidget.h deleted file mode 100644 index fc40f59bbd..0000000000 --- a/Applications/SystemMonitor/GraphWidget.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/CircularQueue.h> -#include <LibGUI/Frame.h> - -class GraphWidget final : public GUI::Frame { - C_OBJECT(GraphWidget) -public: - virtual ~GraphWidget() override; - - void set_max(int max) { m_max = max; } - int max() const { return m_max; } - - void add_value(Vector<int, 1>&&); - - void set_background_color(Color color) { m_background_color = color; } - - struct ValueFormat { - Color line_color { Color::Transparent }; - Color background_color { Color::Transparent }; - Color text_shadow_color { Color::Transparent }; - Function<String(int)> text_formatter; - }; - void set_value_format(size_t index, ValueFormat&& format) - { - if (m_value_format.size() <= index) - m_value_format.resize(index + 1); - m_value_format[index] = move(format); - } - void set_stack_values(bool stack_values) { m_stack_values = stack_values; } - -private: - explicit GraphWidget(); - - virtual void paint_event(GUI::PaintEvent&) override; - - int m_max { 100 }; - Vector<ValueFormat, 1> m_value_format; - CircularQueue<Vector<int, 1>, 4000> m_values; - Color m_background_color { Color::Black }; - bool m_stack_values { false }; - - Vector<Gfx::IntPoint, 1> m_calculated_points; -}; diff --git a/Applications/SystemMonitor/InterruptsWidget.cpp b/Applications/SystemMonitor/InterruptsWidget.cpp deleted file mode 100644 index 3e56f29ec4..0000000000 --- a/Applications/SystemMonitor/InterruptsWidget.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "InterruptsWidget.h" -#include <LibGUI/BoxLayout.h> -#include <LibGUI/GroupBox.h> -#include <LibGUI/JsonArrayModel.h> -#include <LibGUI/SortingProxyModel.h> -#include <LibGUI/TableView.h> - -InterruptsWidget::InterruptsWidget() -{ - on_first_show = [this](auto&) { - set_layout<GUI::VerticalBoxLayout>(); - layout()->set_margins({ 4, 4, 4, 4 }); - - Vector<GUI::JsonArrayModel::FieldSpec> interrupts_field; - interrupts_field.empend("interrupt_line", "Line", Gfx::TextAlignment::CenterRight); - interrupts_field.empend("purpose", "Purpose", Gfx::TextAlignment::CenterLeft); - interrupts_field.empend("controller", "Controller", Gfx::TextAlignment::CenterLeft); - interrupts_field.empend("cpu_handler", "CPU Handler", Gfx::TextAlignment::CenterRight); - interrupts_field.empend("device_sharing", "# Devices Sharing", Gfx::TextAlignment::CenterRight); - interrupts_field.empend("call_count", "Call Count", Gfx::TextAlignment::CenterRight); - - m_interrupt_table_view = add<GUI::TableView>(); - m_interrupt_model = GUI::JsonArrayModel::create("/proc/interrupts", move(interrupts_field)); - m_interrupt_table_view->set_model(GUI::SortingProxyModel::create(*m_interrupt_model)); - - m_update_timer = add<Core::Timer>( - 1000, [this] { - update_model(); - }); - - update_model(); - }; -} - -InterruptsWidget::~InterruptsWidget() -{ -} - -void InterruptsWidget::update_model() -{ - m_interrupt_table_view->model()->update(); -} diff --git a/Applications/SystemMonitor/InterruptsWidget.h b/Applications/SystemMonitor/InterruptsWidget.h deleted file mode 100644 index bc11215217..0000000000 --- a/Applications/SystemMonitor/InterruptsWidget.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibCore/Timer.h> -#include <LibGUI/LazyWidget.h> - -class InterruptsWidget final : public GUI::LazyWidget { - C_OBJECT(InterruptsWidget) -public: - virtual ~InterruptsWidget() override; - -private: - InterruptsWidget(); - void update_model(); - - RefPtr<GUI::TableView> m_interrupt_table_view; - RefPtr<GUI::JsonArrayModel> m_interrupt_model; - RefPtr<Core::Timer> m_update_timer; -}; diff --git a/Applications/SystemMonitor/MemoryStatsWidget.cpp b/Applications/SystemMonitor/MemoryStatsWidget.cpp deleted file mode 100644 index 6675ea8c4a..0000000000 --- a/Applications/SystemMonitor/MemoryStatsWidget.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "MemoryStatsWidget.h" -#include "GraphWidget.h" -#include <AK/ByteBuffer.h> -#include <AK/JsonObject.h> -#include <LibCore/File.h> -#include <LibGUI/BoxLayout.h> -#include <LibGUI/Label.h> -#include <LibGUI/Painter.h> -#include <LibGfx/Font.h> -#include <LibGfx/FontDatabase.h> -#include <LibGfx/StylePainter.h> -#include <stdio.h> -#include <stdlib.h> - -static MemoryStatsWidget* s_the; - -MemoryStatsWidget* MemoryStatsWidget::the() -{ - return s_the; -} - -MemoryStatsWidget::MemoryStatsWidget(GraphWidget& graph) - : m_graph(graph) -{ - ASSERT(!s_the); - s_the = this; - - set_fixed_height(110); - - set_layout<GUI::VerticalBoxLayout>(); - layout()->set_margins({ 0, 8, 0, 0 }); - layout()->set_spacing(3); - - auto build_widgets_for_label = [this](const String& description) -> RefPtr<GUI::Label> { - auto& container = add<GUI::Widget>(); - container.set_layout<GUI::HorizontalBoxLayout>(); - container.set_fixed_size(275, 12); - auto& description_label = container.add<GUI::Label>(description); - description_label.set_font(Gfx::FontDatabase::default_bold_font()); - description_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); - auto& label = container.add<GUI::Label>(); - label.set_text_alignment(Gfx::TextAlignment::CenterRight); - return label; - }; - - m_user_physical_pages_label = build_widgets_for_label("Physical memory:"); - m_user_physical_pages_committed_label = build_widgets_for_label("Committed memory:"); - m_supervisor_physical_pages_label = build_widgets_for_label("Supervisor physical:"); - m_kmalloc_space_label = build_widgets_for_label("Kernel heap:"); - m_kmalloc_count_label = build_widgets_for_label("Calls kmalloc:"); - m_kfree_count_label = build_widgets_for_label("Calls kfree:"); - m_kmalloc_difference_label = build_widgets_for_label("Difference:"); - - refresh(); -} - -MemoryStatsWidget::~MemoryStatsWidget() -{ -} - -static inline size_t page_count_to_kb(size_t kb) -{ - return (kb * 4096) / 1024; -} - -static inline size_t bytes_to_kb(size_t bytes) -{ - return bytes / 1024; -} - -void MemoryStatsWidget::refresh() -{ - auto proc_memstat = Core::File::construct("/proc/memstat"); - if (!proc_memstat->open(Core::IODevice::OpenMode::ReadOnly)) - ASSERT_NOT_REACHED(); - - auto file_contents = proc_memstat->read_all(); - auto json_result = JsonValue::from_string(file_contents); - ASSERT(json_result.has_value()); - auto json = json_result.value().as_object(); - - [[maybe_unused]] unsigned kmalloc_eternal_allocated = json.get("kmalloc_eternal_allocated").to_u32(); - unsigned kmalloc_allocated = json.get("kmalloc_allocated").to_u32(); - unsigned kmalloc_available = json.get("kmalloc_available").to_u32(); - unsigned user_physical_allocated = json.get("user_physical_allocated").to_u32(); - unsigned user_physical_available = json.get("user_physical_available").to_u32(); - unsigned user_physical_committed = json.get("user_physical_committed").to_u32(); - unsigned user_physical_uncommitted = json.get("user_physical_uncommitted").to_u32(); - unsigned super_physical_alloc = json.get("super_physical_allocated").to_u32(); - unsigned super_physical_free = json.get("super_physical_available").to_u32(); - unsigned kmalloc_call_count = json.get("kmalloc_call_count").to_u32(); - unsigned kfree_call_count = json.get("kfree_call_count").to_u32(); - - size_t kmalloc_bytes_total = kmalloc_allocated + kmalloc_available; - size_t user_physical_pages_total = user_physical_allocated + user_physical_available; - size_t supervisor_pages_total = super_physical_alloc + super_physical_free; - - size_t physical_pages_total = user_physical_pages_total + supervisor_pages_total; - size_t physical_pages_in_use = user_physical_allocated + super_physical_alloc; - size_t total_userphysical_and_swappable_pages = user_physical_allocated + user_physical_committed + user_physical_uncommitted; - - m_kmalloc_space_label->set_text(String::formatted("{}K/{}K", bytes_to_kb(kmalloc_allocated), bytes_to_kb(kmalloc_bytes_total))); - m_user_physical_pages_label->set_text(String::formatted("{}K/{}K", page_count_to_kb(physical_pages_in_use), page_count_to_kb(physical_pages_total))); - m_user_physical_pages_committed_label->set_text(String::formatted("{}K", page_count_to_kb(user_physical_committed))); - m_supervisor_physical_pages_label->set_text(String::formatted("{}K/{}K", page_count_to_kb(super_physical_alloc), page_count_to_kb(supervisor_pages_total))); - m_kmalloc_count_label->set_text(String::formatted("{}", kmalloc_call_count)); - m_kfree_count_label->set_text(String::formatted("{}", kfree_call_count)); - m_kmalloc_difference_label->set_text(String::formatted("{:+}", kmalloc_call_count - kfree_call_count)); - - m_graph.set_max(page_count_to_kb(total_userphysical_and_swappable_pages) + bytes_to_kb(kmalloc_bytes_total)); - m_graph.add_value({ (int)page_count_to_kb(user_physical_committed), (int)page_count_to_kb(user_physical_allocated), (int)bytes_to_kb(kmalloc_bytes_total) }); -} diff --git a/Applications/SystemMonitor/MemoryStatsWidget.h b/Applications/SystemMonitor/MemoryStatsWidget.h deleted file mode 100644 index e915730257..0000000000 --- a/Applications/SystemMonitor/MemoryStatsWidget.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibGUI/Widget.h> - -class GraphWidget; - -class MemoryStatsWidget final : public GUI::Widget { - C_OBJECT(MemoryStatsWidget) -public: - static MemoryStatsWidget* the(); - - virtual ~MemoryStatsWidget() override; - - void refresh(); - -private: - MemoryStatsWidget(GraphWidget& graph); - - GraphWidget& m_graph; - RefPtr<GUI::Label> m_user_physical_pages_label; - RefPtr<GUI::Label> m_user_physical_pages_committed_label; - RefPtr<GUI::Label> m_supervisor_physical_pages_label; - RefPtr<GUI::Label> m_kmalloc_space_label; - RefPtr<GUI::Label> m_kmalloc_count_label; - RefPtr<GUI::Label> m_kfree_count_label; - RefPtr<GUI::Label> m_kmalloc_difference_label; -}; diff --git a/Applications/SystemMonitor/NetworkStatisticsWidget.cpp b/Applications/SystemMonitor/NetworkStatisticsWidget.cpp deleted file mode 100644 index 7ee2450ee1..0000000000 --- a/Applications/SystemMonitor/NetworkStatisticsWidget.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "NetworkStatisticsWidget.h" -#include <LibGUI/BoxLayout.h> -#include <LibGUI/GroupBox.h> -#include <LibGUI/JsonArrayModel.h> -#include <LibGUI/SortingProxyModel.h> -#include <LibGUI/TableView.h> - -NetworkStatisticsWidget::NetworkStatisticsWidget() -{ - on_first_show = [this](auto&) { - set_layout<GUI::VerticalBoxLayout>(); - layout()->set_margins({ 4, 4, 4, 4 }); - set_fill_with_background_color(true); - - auto& adapters_group_box = add<GUI::GroupBox>("Adapters"); - adapters_group_box.set_layout<GUI::VerticalBoxLayout>(); - adapters_group_box.layout()->set_margins({ 6, 16, 6, 6 }); - adapters_group_box.set_fixed_height(120); - - m_adapter_table_view = adapters_group_box.add<GUI::TableView>(); - - Vector<GUI::JsonArrayModel::FieldSpec> net_adapters_fields; - net_adapters_fields.empend("name", "Name", Gfx::TextAlignment::CenterLeft); - net_adapters_fields.empend("class_name", "Class", Gfx::TextAlignment::CenterLeft); - net_adapters_fields.empend("mac_address", "MAC", Gfx::TextAlignment::CenterLeft); - net_adapters_fields.empend("ipv4_address", "IPv4", Gfx::TextAlignment::CenterLeft); - net_adapters_fields.empend("packets_in", "Pkt In", Gfx::TextAlignment::CenterRight); - net_adapters_fields.empend("packets_out", "Pkt Out", Gfx::TextAlignment::CenterRight); - net_adapters_fields.empend("bytes_in", "Bytes In", Gfx::TextAlignment::CenterRight); - net_adapters_fields.empend("bytes_out", "Bytes Out", Gfx::TextAlignment::CenterRight); - m_adapter_model = GUI::JsonArrayModel::create("/proc/net/adapters", move(net_adapters_fields)); - m_adapter_table_view->set_model(GUI::SortingProxyModel::create(*m_adapter_model)); - - auto& sockets_group_box = add<GUI::GroupBox>("Sockets"); - sockets_group_box.set_layout<GUI::VerticalBoxLayout>(); - sockets_group_box.layout()->set_margins({ 6, 16, 6, 6 }); - - m_socket_table_view = sockets_group_box.add<GUI::TableView>(); - - Vector<GUI::JsonArrayModel::FieldSpec> net_tcp_fields; - net_tcp_fields.empend("peer_address", "Peer", Gfx::TextAlignment::CenterLeft); - net_tcp_fields.empend("peer_port", "Port", Gfx::TextAlignment::CenterRight); - net_tcp_fields.empend("local_address", "Local", Gfx::TextAlignment::CenterLeft); - net_tcp_fields.empend("local_port", "Port", Gfx::TextAlignment::CenterRight); - net_tcp_fields.empend("state", "State", Gfx::TextAlignment::CenterLeft); - net_tcp_fields.empend("ack_number", "Ack#", Gfx::TextAlignment::CenterRight); - net_tcp_fields.empend("sequence_number", "Seq#", Gfx::TextAlignment::CenterRight); - net_tcp_fields.empend("packets_in", "Pkt In", Gfx::TextAlignment::CenterRight); - net_tcp_fields.empend("packets_out", "Pkt Out", Gfx::TextAlignment::CenterRight); - net_tcp_fields.empend("bytes_in", "Bytes In", Gfx::TextAlignment::CenterRight); - net_tcp_fields.empend("bytes_out", "Bytes Out", Gfx::TextAlignment::CenterRight); - m_socket_model = GUI::JsonArrayModel::create("/proc/net/tcp", move(net_tcp_fields)); - m_socket_table_view->set_model(GUI::SortingProxyModel::create(*m_socket_model)); - - m_update_timer = add<Core::Timer>( - 1000, [this] { - update_models(); - }); - - update_models(); - }; -} - -NetworkStatisticsWidget::~NetworkStatisticsWidget() -{ -} - -void NetworkStatisticsWidget::update_models() -{ - m_adapter_table_view->model()->update(); - m_socket_table_view->model()->update(); -} diff --git a/Applications/SystemMonitor/NetworkStatisticsWidget.h b/Applications/SystemMonitor/NetworkStatisticsWidget.h deleted file mode 100644 index d49a9641c8..0000000000 --- a/Applications/SystemMonitor/NetworkStatisticsWidget.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibCore/Timer.h> -#include <LibGUI/LazyWidget.h> - -class NetworkStatisticsWidget final : public GUI::LazyWidget { - C_OBJECT(NetworkStatisticsWidget) -public: - virtual ~NetworkStatisticsWidget() override; - -private: - NetworkStatisticsWidget(); - void update_models(); - - RefPtr<GUI::TableView> m_adapter_table_view; - RefPtr<GUI::TableView> m_socket_table_view; - RefPtr<GUI::JsonArrayModel> m_adapter_model; - RefPtr<GUI::JsonArrayModel> m_socket_model; - RefPtr<Core::Timer> m_update_timer; -}; diff --git a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp b/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp deleted file mode 100644 index 48dfae098d..0000000000 --- a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ProcessFileDescriptorMapWidget.h" -#include <LibGUI/BoxLayout.h> -#include <LibGUI/JsonArrayModel.h> -#include <LibGUI/SortingProxyModel.h> -#include <LibGUI/TableView.h> - -ProcessFileDescriptorMapWidget::ProcessFileDescriptorMapWidget() -{ - set_layout<GUI::VerticalBoxLayout>(); - layout()->set_margins({ 4, 4, 4, 4 }); - m_table_view = add<GUI::TableView>(); - - Vector<GUI::JsonArrayModel::FieldSpec> pid_fds_fields; - pid_fds_fields.empend("fd", "FD", Gfx::TextAlignment::CenterRight); - pid_fds_fields.empend("class", "Class", Gfx::TextAlignment::CenterLeft); - pid_fds_fields.empend("offset", "Offset", Gfx::TextAlignment::CenterRight); - pid_fds_fields.empend("absolute_path", "Path", Gfx::TextAlignment::CenterLeft); - pid_fds_fields.empend("Access", Gfx::TextAlignment::CenterLeft, [](auto& object) { - return object.get("seekable").to_bool() ? "Seekable" : "Sequential"; - }); - pid_fds_fields.empend("Blocking", Gfx::TextAlignment::CenterLeft, [](auto& object) { - return object.get("blocking").to_bool() ? "Blocking" : "Nonblocking"; - }); - pid_fds_fields.empend("On exec", Gfx::TextAlignment::CenterLeft, [](auto& object) { - return object.get("cloexec").to_bool() ? "Close" : "Keep"; - }); - pid_fds_fields.empend("Can read", Gfx::TextAlignment::CenterLeft, [](auto& object) { - return object.get("can_read").to_bool() ? "Yes" : "No"; - }); - pid_fds_fields.empend("Can write", Gfx::TextAlignment::CenterLeft, [](auto& object) { - return object.get("can_write").to_bool() ? "Yes" : "No"; - }); - - m_model = GUI::JsonArrayModel::create({}, move(pid_fds_fields)); - m_table_view->set_model(GUI::SortingProxyModel::create(*m_model)); -} - -ProcessFileDescriptorMapWidget::~ProcessFileDescriptorMapWidget() -{ -} - -void ProcessFileDescriptorMapWidget::set_pid(pid_t pid) -{ - if (m_pid == pid) - return; - m_pid = pid; - m_model->set_json_path(String::formatted("/proc/{}/fds", m_pid)); -} diff --git a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h b/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h deleted file mode 100644 index 2c45577525..0000000000 --- a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibGUI/Widget.h> - -class ProcessFileDescriptorMapWidget final : public GUI::Widget { - C_OBJECT(ProcessFileDescriptorMapWidget); - -public: - virtual ~ProcessFileDescriptorMapWidget() override; - - void set_pid(pid_t); - -private: - ProcessFileDescriptorMapWidget(); - - RefPtr<GUI::TableView> m_table_view; - RefPtr<GUI::JsonArrayModel> m_model; - pid_t m_pid { -1 }; -}; diff --git a/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp b/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp deleted file mode 100644 index d36a7f57ab..0000000000 --- a/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ProcessMemoryMapWidget.h" -#include <LibCore/Timer.h> -#include <LibGUI/BoxLayout.h> -#include <LibGUI/JsonArrayModel.h> -#include <LibGUI/Painter.h> -#include <LibGUI/SortingProxyModel.h> -#include <LibGUI/TableView.h> -#include <LibGfx/Palette.h> - -class PagemapPaintingDelegate final : public GUI::TableCellPaintingDelegate { -public: - virtual ~PagemapPaintingDelegate() override { } - - virtual void paint(GUI::Painter& painter, const Gfx::IntRect& a_rect, const Gfx::Palette&, const GUI::ModelIndex& index) override - { - auto rect = a_rect.shrunken(2, 2); - auto pagemap = index.data(GUI::ModelRole::Custom).to_string(); - - float scale_factor = (float)pagemap.length() / (float)rect.width(); - - for (int i = 0; i < rect.width(); ++i) { - int x = rect.x() + i; - char c = pagemap[(float)i * scale_factor]; - Color color; - if (c == 'N') // Null (no page at all, typically an inode-backed page that hasn't been paged in.) - color = Color::White; - else if (c == 'Z') // Zero (globally shared zero page, typically an untouched anonymous page.) - color = Color::from_rgb(0xc0c0ff); - else if (c == 'P') // Physical (a resident page) - color = Color::Black; - else - ASSERT_NOT_REACHED(); - - painter.draw_line({ x, rect.top() }, { x, rect.bottom() }, color); - } - - painter.draw_rect(rect, Color::Black); - } -}; - -ProcessMemoryMapWidget::ProcessMemoryMapWidget() -{ - set_layout<GUI::VerticalBoxLayout>(); - layout()->set_margins({ 4, 4, 4, 4 }); - m_table_view = add<GUI::TableView>(); - Vector<GUI::JsonArrayModel::FieldSpec> pid_vm_fields; - pid_vm_fields.empend( - "Address", Gfx::TextAlignment::CenterLeft, - [](auto& object) { return String::formatted("{:#x}", object.get("address").to_u32()); }, - [](auto& object) { return object.get("address").to_u32(); }); - pid_vm_fields.empend("size", "Size", Gfx::TextAlignment::CenterRight); - pid_vm_fields.empend("amount_resident", "Resident", Gfx::TextAlignment::CenterRight); - pid_vm_fields.empend("amount_dirty", "Dirty", Gfx::TextAlignment::CenterRight); - pid_vm_fields.empend("Access", Gfx::TextAlignment::CenterLeft, [](auto& object) { - StringBuilder builder; - if (!object.get("user_accessible").to_bool()) - builder.append('K'); - if (object.get("readable").to_bool()) - builder.append('R'); - if (object.get("writable").to_bool()) - builder.append('W'); - if (object.get("executable").to_bool()) - builder.append('X'); - if (object.get("shared").to_bool()) - builder.append('S'); - if (object.get("stack").to_bool()) - builder.append('T'); - return builder.to_string(); - }); - pid_vm_fields.empend("vmobject", "VMObject type", Gfx::TextAlignment::CenterLeft); - pid_vm_fields.empend("Purgeable", Gfx::TextAlignment::CenterLeft, [](auto& object) { - if (object.get("volatile").to_bool()) - return "Volatile"; - return "Non-volatile"; - }); - pid_vm_fields.empend( - "Page map", Gfx::TextAlignment::CenterLeft, - [](auto&) { - return GUI::Variant(); - }, - [](auto&) { - return GUI::Variant(0); - }, - [](const JsonObject& object) { - auto pagemap = object.get("pagemap").as_string_or({}); - return pagemap; - }); - pid_vm_fields.empend("cow_pages", "# CoW", Gfx::TextAlignment::CenterRight); - pid_vm_fields.empend("name", "Name", Gfx::TextAlignment::CenterLeft); - m_json_model = GUI::JsonArrayModel::create({}, move(pid_vm_fields)); - m_table_view->set_model(GUI::SortingProxyModel::create(*m_json_model)); - - m_table_view->set_column_painting_delegate(7, make<PagemapPaintingDelegate>()); - - m_table_view->set_key_column_and_sort_order(0, GUI::SortOrder::Ascending); - m_timer = add<Core::Timer>(1000, [this] { refresh(); }); -} - -ProcessMemoryMapWidget::~ProcessMemoryMapWidget() -{ -} - -void ProcessMemoryMapWidget::set_pid(pid_t pid) -{ - if (m_pid == pid) - return; - m_pid = pid; - m_json_model->set_json_path(String::formatted("/proc/{}/vm", pid)); -} - -void ProcessMemoryMapWidget::refresh() -{ - if (m_pid != -1) - m_json_model->update(); -} diff --git a/Applications/SystemMonitor/ProcessMemoryMapWidget.h b/Applications/SystemMonitor/ProcessMemoryMapWidget.h deleted file mode 100644 index 71a554fe51..0000000000 --- a/Applications/SystemMonitor/ProcessMemoryMapWidget.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibGUI/Widget.h> - -class ProcessMemoryMapWidget final : public GUI::Widget { - C_OBJECT(ProcessMemoryMapWidget); - -public: - virtual ~ProcessMemoryMapWidget() override; - - void set_pid(pid_t); - void refresh(); - -private: - ProcessMemoryMapWidget(); - RefPtr<GUI::TableView> m_table_view; - RefPtr<GUI::JsonArrayModel> m_json_model; - pid_t m_pid { -1 }; - RefPtr<Core::Timer> m_timer; -}; diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp deleted file mode 100644 index c12a5503ab..0000000000 --- a/Applications/SystemMonitor/ProcessModel.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ProcessModel.h" -#include "GraphWidget.h" -#include <AK/JsonArray.h> -#include <AK/JsonObject.h> -#include <AK/JsonValue.h> -#include <AK/SharedBuffer.h> -#include <LibCore/File.h> -#include <LibCore/ProcessStatisticsReader.h> -#include <LibGUI/FileIconProvider.h> -#include <fcntl.h> -#include <stdio.h> - -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 = Gfx::Bitmap::load_from_file("/res/icons/16x16/gear.png"); - m_high_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/highpriority.png"); - m_low_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/lowpriority.png"); - m_normal_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/normalpriority.png"); - - auto file = Core::File::construct("/proc/cpuinfo"); - if (file->open(Core::IODevice::ReadOnly)) { - auto json = JsonValue::from_string({ file->read_all() }); - auto cpuinfo_array = json.value().as_array(); - cpuinfo_array.for_each([&](auto& value) { - auto& cpu_object = value.as_object(); - auto cpu_id = cpu_object.get("processor").as_u32(); - m_cpus.append(make<CpuInfo>(cpu_id)); - }); - } - - if (m_cpus.is_empty()) - m_cpus.append(make<CpuInfo>(0)); -} - -ProcessModel::~ProcessModel() -{ -} - -int ProcessModel::row_count(const GUI::ModelIndex&) const -{ - return m_pids.size(); -} - -int ProcessModel::column_count(const GUI::ModelIndex&) const -{ - return Column::__Count; -} - -String ProcessModel::column_name(int column) const -{ - switch (column) { - case Column::Icon: - return ""; - case Column::PID: - return "PID"; - case Column::TID: - return "TID"; - case Column::PPID: - return "PPID"; - case Column::PGID: - return "PGID"; - case Column::SID: - return "SID"; - case Column::State: - return "State"; - case Column::User: - return "User"; - case Column::Priority: - return "Pr"; - case Column::EffectivePriority: - return "EPr"; - case Column::Virtual: - return "Virtual"; - case Column::Physical: - return "Physical"; - case Column::DirtyPrivate: - return "DirtyP"; - case Column::CleanInode: - return "CleanI"; - case Column::PurgeableVolatile: - return "Purg:V"; - case Column::PurgeableNonvolatile: - return "Purg:N"; - case Column::CPU: - return "CPU"; - case Column::Processor: - return "Processor"; - case Column::Name: - return "Name"; - case Column::Syscalls: - return "Syscalls"; - case Column::InodeFaults: - return "F:Inode"; - case Column::ZeroFaults: - return "F:Zero"; - case Column::CowFaults: - return "F:CoW"; - case Column::IPv4SocketReadBytes: - return "IPv4 In"; - case Column::IPv4SocketWriteBytes: - return "IPv4 Out"; - case Column::UnixSocketReadBytes: - return "Unix In"; - case Column::UnixSocketWriteBytes: - return "Unix Out"; - case Column::FileReadBytes: - return "File In"; - case Column::FileWriteBytes: - return "File Out"; - case Column::Pledge: - return "Pledge"; - case Column::Veil: - return "Veil"; - default: - ASSERT_NOT_REACHED(); - } -} - -static String pretty_byte_size(size_t size) -{ - return String::formatted("{}K", size / 1024); -} - -GUI::Variant ProcessModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const -{ - ASSERT(is_valid(index)); - - if (role == GUI::ModelRole::TextAlignment) { - switch (index.column()) { - case Column::Icon: - case Column::Name: - case Column::State: - case Column::User: - case Column::Pledge: - case Column::Veil: - return Gfx::TextAlignment::CenterLeft; - case Column::PID: - case Column::TID: - case Column::PPID: - case Column::PGID: - case Column::SID: - case Column::Priority: - case Column::EffectivePriority: - case Column::Virtual: - case Column::Physical: - case Column::DirtyPrivate: - case Column::CleanInode: - case Column::PurgeableVolatile: - case Column::PurgeableNonvolatile: - case Column::CPU: - case Column::Processor: - case Column::Syscalls: - case Column::InodeFaults: - case Column::ZeroFaults: - case Column::CowFaults: - case Column::FileReadBytes: - case Column::FileWriteBytes: - case Column::UnixSocketReadBytes: - case Column::UnixSocketWriteBytes: - case Column::IPv4SocketReadBytes: - case Column::IPv4SocketWriteBytes: - return Gfx::TextAlignment::CenterRight; - default: - ASSERT_NOT_REACHED(); - } - } - - auto it = m_threads.find(m_pids[index.row()]); - auto& thread = *(*it).value; - - if (role == GUI::ModelRole::Sort) { - switch (index.column()) { - case Column::Icon: - return 0; - case Column::PID: - return thread.current_state.pid; - case Column::TID: - return thread.current_state.tid; - case Column::PPID: - return thread.current_state.ppid; - case Column::PGID: - return thread.current_state.pgid; - case Column::SID: - return thread.current_state.sid; - case Column::State: - return thread.current_state.state; - case Column::User: - return thread.current_state.user; - case Column::Priority: - return thread.current_state.priority; - case Column::EffectivePriority: - return thread.current_state.effective_priority; - case Column::Virtual: - return (int)thread.current_state.amount_virtual; - case Column::Physical: - return (int)thread.current_state.amount_resident; - case Column::DirtyPrivate: - return (int)thread.current_state.amount_dirty_private; - case Column::CleanInode: - return (int)thread.current_state.amount_clean_inode; - case Column::PurgeableVolatile: - return (int)thread.current_state.amount_purgeable_volatile; - case Column::PurgeableNonvolatile: - return (int)thread.current_state.amount_purgeable_nonvolatile; - case Column::CPU: - return thread.current_state.cpu_percent; - case Column::Processor: - return thread.current_state.cpu; - case Column::Name: - return thread.current_state.name; - case Column::Syscalls: - return thread.current_state.syscall_count; - case Column::InodeFaults: - return thread.current_state.inode_faults; - case Column::ZeroFaults: - return thread.current_state.zero_faults; - case Column::CowFaults: - return thread.current_state.cow_faults; - case Column::IPv4SocketReadBytes: - return thread.current_state.ipv4_socket_read_bytes; - case Column::IPv4SocketWriteBytes: - return thread.current_state.ipv4_socket_write_bytes; - case Column::UnixSocketReadBytes: - return thread.current_state.unix_socket_read_bytes; - case Column::UnixSocketWriteBytes: - return thread.current_state.unix_socket_write_bytes; - case Column::FileReadBytes: - return thread.current_state.file_read_bytes; - case Column::FileWriteBytes: - return thread.current_state.file_write_bytes; - case Column::Pledge: - return thread.current_state.pledge; - case Column::Veil: - return thread.current_state.veil; - } - ASSERT_NOT_REACHED(); - return {}; - } - - if (role == GUI::ModelRole::Display) { - switch (index.column()) { - case Column::Icon: { - auto icon = GUI::FileIconProvider::icon_for_executable(thread.current_state.executable); - if (auto* bitmap = icon.bitmap_for_size(16)) - return *bitmap; - return *m_generic_process_icon; - } - case Column::PID: - return thread.current_state.pid; - case Column::TID: - return thread.current_state.tid; - case Column::PPID: - return thread.current_state.ppid; - case Column::PGID: - return thread.current_state.pgid; - case Column::SID: - return thread.current_state.sid; - case Column::State: - return thread.current_state.state; - case Column::User: - return thread.current_state.user; - case Column::Priority: - return thread.current_state.priority; - case Column::EffectivePriority: - return thread.current_state.effective_priority; - case Column::Virtual: - return pretty_byte_size(thread.current_state.amount_virtual); - case Column::Physical: - return pretty_byte_size(thread.current_state.amount_resident); - case Column::DirtyPrivate: - return pretty_byte_size(thread.current_state.amount_dirty_private); - case Column::CleanInode: - return pretty_byte_size(thread.current_state.amount_clean_inode); - case Column::PurgeableVolatile: - return pretty_byte_size(thread.current_state.amount_purgeable_volatile); - case Column::PurgeableNonvolatile: - return pretty_byte_size(thread.current_state.amount_purgeable_nonvolatile); - case Column::CPU: - return thread.current_state.cpu_percent; - case Column::Processor: - return thread.current_state.cpu; - case Column::Name: - return thread.current_state.name; - case Column::Syscalls: - return thread.current_state.syscall_count; - case Column::InodeFaults: - return thread.current_state.inode_faults; - case Column::ZeroFaults: - return thread.current_state.zero_faults; - case Column::CowFaults: - return thread.current_state.cow_faults; - case Column::IPv4SocketReadBytes: - return thread.current_state.ipv4_socket_read_bytes; - case Column::IPv4SocketWriteBytes: - return thread.current_state.ipv4_socket_write_bytes; - case Column::UnixSocketReadBytes: - return thread.current_state.unix_socket_read_bytes; - case Column::UnixSocketWriteBytes: - return thread.current_state.unix_socket_write_bytes; - case Column::FileReadBytes: - return thread.current_state.file_read_bytes; - case Column::FileWriteBytes: - return thread.current_state.file_write_bytes; - case Column::Pledge: - return thread.current_state.pledge; - case Column::Veil: - return thread.current_state.veil; - } - } - - return {}; -} - -void ProcessModel::update() -{ - auto previous_pid_count = m_pids.size(); - auto all_processes = Core::ProcessStatisticsReader::get_all(m_proc_all); - - u64 last_sum_ticks_scheduled = 0, last_sum_ticks_scheduled_kernel = 0; - for (auto& it : m_threads) { - auto& current_state = it.value->current_state; - last_sum_ticks_scheduled += current_state.ticks_user + current_state.ticks_kernel; - last_sum_ticks_scheduled_kernel += current_state.ticks_kernel; - } - - HashTable<PidAndTid> live_pids; - u64 sum_ticks_scheduled = 0, sum_ticks_scheduled_kernel = 0; - if (all_processes.has_value()) { - for (auto& it : all_processes.value()) { - for (auto& thread : it.value.threads) { - ThreadState state; - state.pid = it.value.pid; - state.user = it.value.username; - state.pledge = it.value.pledge; - state.veil = it.value.veil; - state.syscall_count = thread.syscall_count; - state.inode_faults = thread.inode_faults; - state.zero_faults = thread.zero_faults; - state.cow_faults = thread.cow_faults; - state.unix_socket_read_bytes = thread.unix_socket_read_bytes; - state.unix_socket_write_bytes = thread.unix_socket_write_bytes; - state.ipv4_socket_read_bytes = thread.ipv4_socket_read_bytes; - state.ipv4_socket_write_bytes = thread.ipv4_socket_write_bytes; - state.file_read_bytes = thread.file_read_bytes; - state.file_write_bytes = thread.file_write_bytes; - state.amount_virtual = it.value.amount_virtual; - state.amount_resident = it.value.amount_resident; - state.amount_dirty_private = it.value.amount_dirty_private; - state.amount_clean_inode = it.value.amount_clean_inode; - state.amount_purgeable_volatile = it.value.amount_purgeable_volatile; - state.amount_purgeable_nonvolatile = it.value.amount_purgeable_nonvolatile; - - state.name = thread.name; - state.executable = it.value.executable; - - state.ppid = it.value.ppid; - state.tid = thread.tid; - state.pgid = it.value.pgid; - state.sid = it.value.sid; - state.times_scheduled = thread.times_scheduled; - state.ticks_user = thread.ticks_user; - state.ticks_kernel = thread.ticks_kernel; - state.cpu = thread.cpu; - state.cpu_percent = 0; - state.priority = thread.priority; - state.effective_priority = thread.effective_priority; - state.state = thread.state; - sum_ticks_scheduled += thread.ticks_user + thread.ticks_kernel; - sum_ticks_scheduled_kernel += thread.ticks_kernel; - { - auto pit = m_threads.find({ it.value.pid, thread.tid }); - if (pit == m_threads.end()) - m_threads.set({ it.value.pid, thread.tid }, make<Thread>()); - } - auto pit = m_threads.find({ it.value.pid, thread.tid }); - ASSERT(pit != m_threads.end()); - (*pit).value->previous_state = (*pit).value->current_state; - (*pit).value->current_state = state; - - live_pids.set({ it.value.pid, thread.tid }); - } - } - } - - m_pids.clear(); - for (auto& c : m_cpus) { - c.total_cpu_percent = 0.0; - c.total_cpu_percent_kernel = 0.0; - } - Vector<PidAndTid, 16> pids_to_remove; - for (auto& it : m_threads) { - if (!live_pids.contains(it.key)) { - pids_to_remove.append(it.key); - continue; - } - auto& process = *it.value; - u32 ticks_scheduled_diff = (process.current_state.ticks_user + process.current_state.ticks_kernel) - - (process.previous_state.ticks_user + process.previous_state.ticks_kernel); - u32 ticks_scheduled_diff_kernel = process.current_state.ticks_kernel - process.previous_state.ticks_kernel; - process.current_state.cpu_percent = ((float)ticks_scheduled_diff * 100) / (float)(sum_ticks_scheduled - last_sum_ticks_scheduled); - process.current_state.cpu_percent_kernel = ((float)ticks_scheduled_diff_kernel * 100) / (float)(sum_ticks_scheduled - last_sum_ticks_scheduled); - if (it.key.pid != 0) { - auto& cpu_info = m_cpus[process.current_state.cpu]; - cpu_info.total_cpu_percent += process.current_state.cpu_percent; - cpu_info.total_cpu_percent_kernel += process.current_state.cpu_percent_kernel; - m_pids.append(it.key); - } - } - for (auto pid : pids_to_remove) - m_threads.remove(pid); - - if (on_cpu_info_change) - on_cpu_info_change(m_cpus); - - // FIXME: This is a rather hackish way of invalidating indexes. - // It would be good if GUI::Model had a way to orchestrate removal/insertion while preserving indexes. - did_update(previous_pid_count == m_pids.size() ? GUI::Model::UpdateFlag::DontInvalidateIndexes : GUI::Model::UpdateFlag::InvalidateAllIndexes); -} diff --git a/Applications/SystemMonitor/ProcessModel.h b/Applications/SystemMonitor/ProcessModel.h deleted file mode 100644 index 11f39cac76..0000000000 --- a/Applications/SystemMonitor/ProcessModel.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/HashMap.h> -#include <AK/NonnullOwnPtrVector.h> -#include <AK/String.h> -#include <AK/Vector.h> -#include <LibGUI/Model.h> -#include <unistd.h> - -class GraphWidget; - -struct PidAndTid { - bool operator==(const PidAndTid& other) const - { - return pid == other.pid && tid == other.tid; - } - pid_t pid; - int tid; -}; - -class ProcessModel final : public GUI::Model { -public: - enum Column { - Icon = 0, - Name, - CPU, - Processor, - State, - Priority, - EffectivePriority, - User, - PID, - TID, - PPID, - PGID, - SID, - Virtual, - Physical, - DirtyPrivate, - CleanInode, - PurgeableVolatile, - PurgeableNonvolatile, - Veil, - Pledge, - Syscalls, - InodeFaults, - ZeroFaults, - CowFaults, - FileReadBytes, - FileWriteBytes, - UnixSocketReadBytes, - UnixSocketWriteBytes, - IPv4SocketReadBytes, - IPv4SocketWriteBytes, - __Count - }; - - static ProcessModel& the(); - - static NonnullRefPtr<ProcessModel> create() { return adopt(*new ProcessModel); } - virtual ~ProcessModel() override; - - virtual int row_count(const GUI::ModelIndex&) const override; - virtual int column_count(const GUI::ModelIndex&) const override; - virtual String column_name(int column) const override; - virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override; - virtual void update() override; - - struct CpuInfo { - u32 id; - float total_cpu_percent { 0.0 }; - float total_cpu_percent_kernel { 0.0 }; - - CpuInfo(u32 id) - : id(id) - { - } - }; - - Function<void(const NonnullOwnPtrVector<CpuInfo>&)> on_cpu_info_change; - - const NonnullOwnPtrVector<CpuInfo>& cpus() const { return m_cpus; } - -private: - ProcessModel(); - - struct ThreadState { - pid_t tid; - pid_t pid; - pid_t ppid; - pid_t pgid; - pid_t sid; - unsigned times_scheduled; - unsigned ticks_user; - unsigned ticks_kernel; - String executable; - String name; - String state; - String user; - String pledge; - String veil; - u32 cpu; - u32 priority; - u32 effective_priority; - size_t amount_virtual; - size_t amount_resident; - size_t amount_dirty_private; - size_t amount_clean_inode; - size_t amount_purgeable_volatile; - size_t amount_purgeable_nonvolatile; - unsigned syscall_count; - unsigned inode_faults; - unsigned zero_faults; - unsigned cow_faults; - unsigned unix_socket_read_bytes; - unsigned unix_socket_write_bytes; - unsigned ipv4_socket_read_bytes; - unsigned ipv4_socket_write_bytes; - unsigned file_read_bytes; - unsigned file_write_bytes; - float cpu_percent; - float cpu_percent_kernel; - }; - - struct Thread { - ThreadState current_state; - ThreadState previous_state; - }; - - HashMap<uid_t, String> m_usernames; - HashMap<PidAndTid, NonnullOwnPtr<Thread>> m_threads; - NonnullOwnPtrVector<CpuInfo> m_cpus; - Vector<PidAndTid> m_pids; - RefPtr<Gfx::Bitmap> m_generic_process_icon; - RefPtr<Gfx::Bitmap> m_high_priority_icon; - RefPtr<Gfx::Bitmap> m_low_priority_icon; - RefPtr<Gfx::Bitmap> m_normal_priority_icon; - RefPtr<Core::File> m_proc_all; -}; - -namespace AK { -template<> -struct Traits<PidAndTid> : public GenericTraits<PidAndTid> { - static unsigned hash(const PidAndTid& value) { return pair_int_hash(value.pid, value.tid); } -}; -} diff --git a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp b/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp deleted file mode 100644 index 9e2d22443c..0000000000 --- a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ProcessUnveiledPathsWidget.h" -#include <LibGUI/BoxLayout.h> -#include <LibGUI/JsonArrayModel.h> -#include <LibGUI/SortingProxyModel.h> -#include <LibGUI/TableView.h> - -ProcessUnveiledPathsWidget::ProcessUnveiledPathsWidget() -{ - set_layout<GUI::VerticalBoxLayout>(); - layout()->set_margins({ 4, 4, 4, 4 }); - m_table_view = add<GUI::TableView>(); - - Vector<GUI::JsonArrayModel::FieldSpec> pid_unveil_fields; - pid_unveil_fields.empend("path", "Path", Gfx::TextAlignment::CenterLeft); - pid_unveil_fields.empend("permissions", "Permissions", Gfx::TextAlignment::CenterLeft); - - m_model = GUI::JsonArrayModel::create({}, move(pid_unveil_fields)); - m_table_view->set_model(GUI::SortingProxyModel::create(*m_model)); -} - -ProcessUnveiledPathsWidget::~ProcessUnveiledPathsWidget() -{ -} - -void ProcessUnveiledPathsWidget::set_pid(pid_t pid) -{ - if (m_pid == pid) - return; - m_pid = pid; - m_model->set_json_path(String::formatted("/proc/{}/unveil", m_pid)); -} diff --git a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h b/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h deleted file mode 100644 index d1eac898b2..0000000000 --- a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibGUI/Widget.h> - -class ProcessUnveiledPathsWidget final : public GUI::Widget { - C_OBJECT(ProcessUnveiledPathsWidget); - -public: - virtual ~ProcessUnveiledPathsWidget() override; - - void set_pid(pid_t); - -private: - ProcessUnveiledPathsWidget(); - - RefPtr<GUI::TableView> m_table_view; - RefPtr<GUI::JsonArrayModel> m_model; - pid_t m_pid { -1 }; -}; diff --git a/Applications/SystemMonitor/ThreadStackWidget.cpp b/Applications/SystemMonitor/ThreadStackWidget.cpp deleted file mode 100644 index 01e37791a0..0000000000 --- a/Applications/SystemMonitor/ThreadStackWidget.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ThreadStackWidget.h" -#include <AK/ByteBuffer.h> -#include <LibCore/File.h> -#include <LibCore/Timer.h> -#include <LibGUI/BoxLayout.h> - -ThreadStackWidget::ThreadStackWidget() -{ - set_layout<GUI::VerticalBoxLayout>(); - layout()->set_margins({ 4, 4, 4, 4 }); - m_stack_editor = add<GUI::TextEditor>(); - m_stack_editor->set_mode(GUI::TextEditor::ReadOnly); - - m_timer = add<Core::Timer>(1000, [this] { refresh(); }); -} - -ThreadStackWidget::~ThreadStackWidget() -{ -} - -void ThreadStackWidget::set_ids(pid_t pid, pid_t tid) -{ - if (m_pid == pid && m_tid == tid) - return; - m_pid = pid; - m_tid = tid; - refresh(); -} - -void ThreadStackWidget::refresh() -{ - auto file = Core::File::construct(String::formatted("/proc/{}/stacks/{}", m_pid, m_tid)); - if (!file->open(Core::IODevice::ReadOnly)) { - m_stack_editor->set_text(String::formatted("Unable to open {}", file->filename())); - return; - } - - auto new_text = file->read_all(); - if (m_stack_editor->text() != new_text) { - m_stack_editor->set_text(new_text); - } -} diff --git a/Applications/SystemMonitor/ThreadStackWidget.h b/Applications/SystemMonitor/ThreadStackWidget.h deleted file mode 100644 index 5a10e93b0a..0000000000 --- a/Applications/SystemMonitor/ThreadStackWidget.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibGUI/TextEditor.h> -#include <LibGUI/Widget.h> - -class ThreadStackWidget final : public GUI::Widget { - C_OBJECT(ThreadStackWidget) -public: - virtual ~ThreadStackWidget() override; - - void set_ids(pid_t pid, pid_t tid); - void refresh(); - -private: - ThreadStackWidget(); - - pid_t m_pid { -1 }; - pid_t m_tid { -1 }; - RefPtr<GUI::TextEditor> m_stack_editor; - RefPtr<Core::Timer> m_timer; -}; diff --git a/Applications/SystemMonitor/main.cpp b/Applications/SystemMonitor/main.cpp deleted file mode 100644 index bdf88e44d1..0000000000 --- a/Applications/SystemMonitor/main.cpp +++ /dev/null @@ -1,670 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "DevicesModel.h" -#include "GraphWidget.h" -#include "InterruptsWidget.h" -#include "MemoryStatsWidget.h" -#include "NetworkStatisticsWidget.h" -#include "ProcessFileDescriptorMapWidget.h" -#include "ProcessMemoryMapWidget.h" -#include "ProcessModel.h" -#include "ProcessUnveiledPathsWidget.h" -#include "ThreadStackWidget.h" -#include <AK/NumberFormat.h> -#include <LibCore/ArgsParser.h> -#include <LibCore/Timer.h> -#include <LibGUI/Action.h> -#include <LibGUI/ActionGroup.h> -#include <LibGUI/Application.h> -#include <LibGUI/BoxLayout.h> -#include <LibGUI/GroupBox.h> -#include <LibGUI/Icon.h> -#include <LibGUI/JsonArrayModel.h> -#include <LibGUI/Label.h> -#include <LibGUI/LazyWidget.h> -#include <LibGUI/Menu.h> -#include <LibGUI/MenuBar.h> -#include <LibGUI/Painter.h> -#include <LibGUI/SortingProxyModel.h> -#include <LibGUI/Splitter.h> -#include <LibGUI/TabWidget.h> -#include <LibGUI/TableView.h> -#include <LibGUI/ToolBar.h> -#include <LibGUI/Widget.h> -#include <LibGUI/Window.h> -#include <LibGfx/Palette.h> -#include <LibPCIDB/Database.h> -#include <serenity.h> -#include <signal.h> -#include <spawn.h> -#include <stdio.h> -#include <unistd.h> - -static NonnullRefPtr<GUI::Widget> build_file_systems_tab(); -static NonnullRefPtr<GUI::Widget> build_pci_devices_tab(); -static NonnullRefPtr<GUI::Widget> build_devices_tab(); -static NonnullRefPtr<GUI::Widget> build_graphs_tab(); -static NonnullRefPtr<GUI::Widget> build_processors_tab(); - -class UnavailableProcessWidget final : public GUI::Frame { - C_OBJECT(UnavailableProcessWidget) -public: - virtual ~UnavailableProcessWidget() override { } - - const String& text() const { return m_text; } - void set_text(String text) { m_text = move(text); } - -private: - UnavailableProcessWidget(String text) - : m_text(move(text)) - { - } - - virtual void paint_event(GUI::PaintEvent& event) override - { - Frame::paint_event(event); - if (text().is_empty()) - return; - GUI::Painter painter(*this); - painter.add_clip_rect(event.rect()); - painter.draw_text(frame_inner_rect(), text(), Gfx::TextAlignment::Center, palette().window_text(), Gfx::TextElision::Right); - } - - String m_text; -}; - -static bool can_access_pid(pid_t pid) -{ - auto path = String::formatted("/proc/{}", pid); - return access(path.characters(), X_OK) == 0; -} - -int main(int argc, char** argv) -{ - if (pledge("stdio proc shared_buffer accept rpath exec unix cpath fattr", nullptr) < 0) { - perror("pledge"); - return 1; - } - - auto app = GUI::Application::construct(argc, argv); - - if (pledge("stdio proc shared_buffer accept rpath exec", nullptr) < 0) { - perror("pledge"); - return 1; - } - - if (unveil("/etc/passwd", "r") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/res", "r") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/proc", "r") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/dev", "r") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/bin", "r") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/bin/Profiler", "rx") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/bin/Inspector", "rx") < 0) { - perror("unveil"); - return 1; - } - - unveil(nullptr, nullptr); - - const char* args_tab = "processes"; - Core::ArgsParser parser; - parser.add_option(args_tab, "Tab, one of 'processes', 'graphs', 'fs', 'pci', 'devices', 'network', 'processors' or 'interrupts'", "open-tab", 't', "tab"); - parser.parse(argc, argv); - StringView args_tab_view = args_tab; - - auto app_icon = GUI::Icon::default_icon("app-system-monitor"); - - auto window = GUI::Window::construct(); - window->set_title("System Monitor"); - window->resize(680, 400); - - auto& keeper = window->set_main_widget<GUI::Widget>(); - keeper.set_layout<GUI::VerticalBoxLayout>(); - keeper.set_fill_with_background_color(true); - keeper.layout()->set_margins({ 2, 2, 2, 2 }); - - auto& tabwidget = keeper.add<GUI::TabWidget>(); - - auto process_container_splitter = GUI::VerticalSplitter::construct(); - tabwidget.add_widget("Processes", process_container_splitter); - process_container_splitter->layout()->set_margins({ 4, 4, 4, 4 }); - - auto& process_table_container = process_container_splitter->add<GUI::Widget>(); - - auto graphs_widget = build_graphs_tab(); - tabwidget.add_widget("Graphs", graphs_widget); - - auto file_systems_widget = build_file_systems_tab(); - tabwidget.add_widget("File systems", file_systems_widget); - - auto pci_devices_widget = build_pci_devices_tab(); - tabwidget.add_widget("PCI devices", pci_devices_widget); - - auto devices_widget = build_devices_tab(); - tabwidget.add_widget("Devices", devices_widget); - - auto network_stats_widget = NetworkStatisticsWidget::construct(); - tabwidget.add_widget("Network", network_stats_widget); - - auto processors_widget = build_processors_tab(); - tabwidget.add_widget("Processors", processors_widget); - - auto interrupts_widget = InterruptsWidget::construct(); - tabwidget.add_widget("Interrupts", interrupts_widget); - - process_table_container.set_layout<GUI::VerticalBoxLayout>(); - process_table_container.layout()->set_spacing(0); - - auto& process_table_view = process_table_container.add<GUI::TableView>(); - process_table_view.set_column_headers_visible(true); - process_table_view.set_model(GUI::SortingProxyModel::create(ProcessModel::create())); - process_table_view.set_key_column_and_sort_order(ProcessModel::Column::CPU, GUI::SortOrder::Descending); - process_table_view.model()->update(); - - auto& refresh_timer = window->add<Core::Timer>( - 3000, [&] { - process_table_view.model()->update(); - if (auto* memory_stats_widget = MemoryStatsWidget::the()) - memory_stats_widget->refresh(); - }); - - auto selected_id = [&](ProcessModel::Column column) -> pid_t { - if (process_table_view.selection().is_empty()) - return -1; - auto pid_index = process_table_view.model()->index(process_table_view.selection().first().row(), column); - return pid_index.data().to_i32(); - }; - - auto kill_action = GUI::Action::create("Kill process", { Mod_Ctrl, Key_K }, Gfx::Bitmap::load_from_file("/res/icons/16x16/kill.png"), [&](const GUI::Action&) { - pid_t pid = selected_id(ProcessModel::Column::PID); - if (pid != -1) - kill(pid, SIGKILL); - }); - - auto stop_action = GUI::Action::create("Stop process", { Mod_Ctrl, Key_S }, Gfx::Bitmap::load_from_file("/res/icons/16x16/stop-hand.png"), [&](const GUI::Action&) { - pid_t pid = selected_id(ProcessModel::Column::PID); - if (pid != -1) - kill(pid, SIGSTOP); - }); - - auto continue_action = GUI::Action::create("Continue process", { Mod_Ctrl, Key_C }, Gfx::Bitmap::load_from_file("/res/icons/16x16/continue.png"), [&](const GUI::Action&) { - pid_t pid = selected_id(ProcessModel::Column::PID); - if (pid != -1) - kill(pid, SIGCONT); - }); - - auto profile_action = GUI::Action::create("Profile process", { Mod_Ctrl, Key_P }, - Gfx::Bitmap::load_from_file("/res/icons/16x16/app-profiler.png"), [&](auto&) { - pid_t pid = selected_id(ProcessModel::Column::PID); - if (pid != -1) { - auto pid_string = String::format("%d", pid); - pid_t child; - const char* argv[] = { "/bin/Profiler", "--pid", pid_string.characters(), nullptr }; - if ((errno = posix_spawn(&child, "/bin/Profiler", nullptr, nullptr, const_cast<char**>(argv), environ))) { - perror("posix_spawn"); - } else { - if (disown(child) < 0) - perror("disown"); - } - } - }); - - auto inspect_action = GUI::Action::create("Inspect process", { Mod_Ctrl, Key_I }, - Gfx::Bitmap::load_from_file("/res/icons/16x16/app-inspector.png"), [&](auto&) { - pid_t pid = selected_id(ProcessModel::Column::PID); - if (pid != -1) { - auto pid_string = String::format("%d", pid); - pid_t child; - const char* argv[] = { "/bin/Inspector", pid_string.characters(), nullptr }; - if ((errno = posix_spawn(&child, "/bin/Inspector", nullptr, nullptr, const_cast<char**>(argv), environ))) { - perror("posix_spawn"); - } else { - if (disown(child) < 0) - perror("disown"); - } - } - }); - - auto menubar = GUI::MenuBar::construct(); - auto& app_menu = menubar->add_menu("System Monitor"); - app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) { - GUI::Application::the()->quit(); - return; - })); - - auto& process_menu = menubar->add_menu("Process"); - process_menu.add_action(kill_action); - process_menu.add_action(stop_action); - process_menu.add_action(continue_action); - process_menu.add_separator(); - process_menu.add_action(profile_action); - process_menu.add_action(inspect_action); - - auto process_context_menu = GUI::Menu::construct(); - process_context_menu->add_action(kill_action); - process_context_menu->add_action(stop_action); - process_context_menu->add_action(continue_action); - process_context_menu->add_separator(); - process_context_menu->add_action(profile_action); - process_context_menu->add_action(inspect_action); - process_table_view.on_context_menu_request = [&]([[maybe_unused]] const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) { - process_context_menu->popup(event.screen_position()); - }; - - auto& frequency_menu = menubar->add_menu("Frequency"); - GUI::ActionGroup frequency_action_group; - frequency_action_group.set_exclusive(true); - - auto make_frequency_action = [&](auto& title, int interval, bool checked = false) { - auto action = GUI::Action::create_checkable(title, [&refresh_timer, interval](auto&) { - refresh_timer.restart(interval); - }); - action->set_checked(checked); - frequency_action_group.add_action(*action); - frequency_menu.add_action(*action); - }; - - make_frequency_action("1 sec", 1000); - make_frequency_action("3 sec", 3000, true); - make_frequency_action("5 sec", 5000); - - auto& help_menu = menubar->add_menu("Help"); - help_menu.add_action(GUI::CommonActions::make_about_action("System Monitor", app_icon, window)); - - app->set_menubar(move(menubar)); - - auto& process_tab_unused_widget = process_container_splitter->add<UnavailableProcessWidget>("No process selected"); - process_tab_unused_widget.set_visible(true); - - auto& process_tab_widget = process_container_splitter->add<GUI::TabWidget>(); - process_tab_widget.set_tab_position(GUI::TabWidget::TabPosition::Bottom); - process_tab_widget.set_visible(false); - - auto& memory_map_widget = process_tab_widget.add_tab<ProcessMemoryMapWidget>("Memory map"); - auto& open_files_widget = process_tab_widget.add_tab<ProcessFileDescriptorMapWidget>("Open files"); - auto& unveiled_paths_widget = process_tab_widget.add_tab<ProcessUnveiledPathsWidget>("Unveiled paths"); - auto& stack_widget = process_tab_widget.add_tab<ThreadStackWidget>("Stack"); - - process_table_view.on_selection = [&](auto&) { - auto pid = selected_id(ProcessModel::Column::PID); - auto tid = selected_id(ProcessModel::Column::TID); - if (!can_access_pid(pid)) { - process_tab_widget.set_visible(false); - process_tab_unused_widget.set_text("Process cannot be accessed"); - process_tab_unused_widget.set_visible(true); - return; - } - - process_tab_widget.set_visible(true); - process_tab_unused_widget.set_visible(false); - open_files_widget.set_pid(pid); - stack_widget.set_ids(pid, tid); - memory_map_widget.set_pid(pid); - unveiled_paths_widget.set_pid(pid); - }; - - window->show(); - - window->set_icon(app_icon.bitmap_for_size(16)); - - if (args_tab_view == "processes") - tabwidget.set_active_widget(process_container_splitter); - else if (args_tab_view == "graphs") - tabwidget.set_active_widget(graphs_widget); - else if (args_tab_view == "fs") - tabwidget.set_active_widget(file_systems_widget); - else if (args_tab_view == "pci") - tabwidget.set_active_widget(pci_devices_widget); - else if (args_tab_view == "devices") - tabwidget.set_active_widget(devices_widget); - else if (args_tab_view == "network") - tabwidget.set_active_widget(network_stats_widget); - else if (args_tab_view == "processors") - tabwidget.set_active_widget(processors_widget); - else if (args_tab_view == "interrupts") - tabwidget.set_active_widget(interrupts_widget); - - return app->exec(); -} - -class ProgressBarPaintingDelegate final : public GUI::TableCellPaintingDelegate { -public: - virtual ~ProgressBarPaintingDelegate() override { } - - virtual void paint(GUI::Painter& painter, const Gfx::IntRect& a_rect, const Palette& 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_progress_bar(painter, rect, palette, 0, 100, percentage, text); - painter.draw_rect(rect, Color::Black); - } -}; - -NonnullRefPtr<GUI::Widget> build_file_systems_tab() -{ - auto fs_widget = GUI::LazyWidget::construct(); - - fs_widget->on_first_show = [](GUI::LazyWidget& self) { - self.set_layout<GUI::VerticalBoxLayout>(); - self.layout()->set_margins({ 4, 4, 4, 4 }); - auto& fs_table_view = self.add<GUI::TableView>(); - - Vector<GUI::JsonArrayModel::FieldSpec> df_fields; - df_fields.empend("mount_point", "Mount point", Gfx::TextAlignment::CenterLeft); - df_fields.empend("class_name", "Class", Gfx::TextAlignment::CenterLeft); - df_fields.empend("source", "Source", Gfx::TextAlignment::CenterLeft); - df_fields.empend( - "Size", Gfx::TextAlignment::CenterRight, - [](const JsonObject& object) { - StringBuilder size_builder; - size_builder.append(" "); - size_builder.append(human_readable_size(object.get("total_block_count").to_u32() * object.get("block_size").to_u32())); - size_builder.append(" "); - return size_builder.to_string(); - }, - [](const JsonObject& object) { - return object.get("total_block_count").to_u32() * 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( - "Used", Gfx::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(); - }); - df_fields.empend( - "Available", Gfx::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", Gfx::TextAlignment::CenterLeft, [](const JsonObject& object) { - bool readonly = object.get("readonly").to_bool(); - int mount_flags = object.get("mount_flags").to_int(); - return readonly || (mount_flags & MS_RDONLY) ? "Read-only" : "Read/Write"; - }); - df_fields.empend("Mount flags", Gfx::TextAlignment::CenterLeft, [](const JsonObject& object) { - int mount_flags = object.get("mount_flags").to_int(); - StringBuilder builder; - bool first = true; - auto check = [&](int flag, const char* name) { - if (!(mount_flags & flag)) - return; - if (!first) - builder.append(','); - builder.append(name); - first = false; - }; - check(MS_NODEV, "nodev"); - check(MS_NOEXEC, "noexec"); - check(MS_NOSUID, "nosuid"); - check(MS_BIND, "bind"); - check(MS_RDONLY, "ro"); - if (builder.string_view().is_empty()) - return String("defaults"); - return builder.to_string(); - }); - df_fields.empend("free_block_count", "Free blocks", Gfx::TextAlignment::CenterRight); - df_fields.empend("total_block_count", "Total blocks", Gfx::TextAlignment::CenterRight); - df_fields.empend("free_inode_count", "Free inodes", Gfx::TextAlignment::CenterRight); - df_fields.empend("total_inode_count", "Total inodes", Gfx::TextAlignment::CenterRight); - df_fields.empend("block_size", "Block size", Gfx::TextAlignment::CenterRight); - fs_table_view.set_model(GUI::SortingProxyModel::create(GUI::JsonArrayModel::create("/proc/df", move(df_fields)))); - - fs_table_view.set_column_painting_delegate(3, make<ProgressBarPaintingDelegate>()); - - fs_table_view.model()->update(); - }; - return fs_widget; -} - -NonnullRefPtr<GUI::Widget> build_pci_devices_tab() -{ - auto pci_widget = GUI::LazyWidget::construct(); - - pci_widget->on_first_show = [](GUI::LazyWidget& self) { - self.set_layout<GUI::VerticalBoxLayout>(); - self.layout()->set_margins({ 4, 4, 4, 4 }); - auto& pci_table_view = self.add<GUI::TableView>(); - - auto db = PCIDB::Database::open(); - - Vector<GUI::JsonArrayModel::FieldSpec> pci_fields; - pci_fields.empend( - "Address", Gfx::TextAlignment::CenterLeft, - [](const JsonObject& object) { - auto seg = object.get("seg").to_u32(); - auto bus = object.get("bus").to_u32(); - auto slot = object.get("slot").to_u32(); - auto function = object.get("function").to_u32(); - return String::formatted("{:04x}:{:02x}:{:02x}.{}", seg, bus, slot, function); - }); - pci_fields.empend( - "Class", Gfx::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::formatted("{:04x}", class_id) : class_name; - }); - pci_fields.empend( - "Vendor", Gfx::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::formatted("{:02x}", vendor_id) : vendor_name; - }); - pci_fields.empend( - "Device", Gfx::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::formatted("{:02x}", device_id) : device_name; - }); - pci_fields.empend( - "Revision", Gfx::TextAlignment::CenterRight, - [](const JsonObject& object) { - auto revision_id = object.get("revision_id").to_u32(); - return String::formatted("{:02x}", revision_id); - }); - - pci_table_view.set_model(GUI::SortingProxyModel::create(GUI::JsonArrayModel::create("/proc/pci", move(pci_fields)))); - pci_table_view.model()->update(); - }; - - return pci_widget; -} - -NonnullRefPtr<GUI::Widget> build_devices_tab() -{ - auto devices_widget = GUI::LazyWidget::construct(); - - devices_widget->on_first_show = [](GUI::LazyWidget& self) { - self.set_layout<GUI::VerticalBoxLayout>(); - self.layout()->set_margins({ 4, 4, 4, 4 }); - - auto& devices_table_view = self.add<GUI::TableView>(); - devices_table_view.set_model(GUI::SortingProxyModel::create(DevicesModel::create())); - devices_table_view.model()->update(); - }; - - return devices_widget; -} - -NonnullRefPtr<GUI::Widget> build_graphs_tab() -{ - auto graphs_container = GUI::LazyWidget::construct(); - - graphs_container->on_first_show = [](GUI::LazyWidget& self) { - self.set_fill_with_background_color(true); - self.set_background_role(ColorRole::Button); - self.set_layout<GUI::VerticalBoxLayout>(); - self.layout()->set_margins({ 4, 4, 4, 4 }); - - auto& cpu_graph_group_box = self.add<GUI::GroupBox>("CPU usage"); - cpu_graph_group_box.set_layout<GUI::HorizontalBoxLayout>(); - cpu_graph_group_box.layout()->set_margins({ 6, 16, 6, 6 }); - cpu_graph_group_box.set_fixed_height(120); - Vector<GraphWidget*> cpu_graphs; - for (size_t i = 0; i < ProcessModel::the().cpus().size(); i++) { - auto& cpu_graph = cpu_graph_group_box.add<GraphWidget>(); - cpu_graph.set_max(100); - cpu_graph.set_background_color(Color::White); - cpu_graph.set_value_format(0, { - .line_color = Color::Blue, - .background_color = Color::from_rgb(0xaaaaff), - .text_formatter = [](int value) { - return String::formatted("Total: {}%", value); - }, - }); - cpu_graph.set_value_format(1, { - .line_color = Color::Red, - .background_color = Color::from_rgb(0xffaaaa), - .text_formatter = [](int value) { - return String::formatted("Kernel: {}%", value); - }, - }); - cpu_graphs.append(&cpu_graph); - } - ProcessModel::the().on_cpu_info_change = [cpu_graphs](const NonnullOwnPtrVector<ProcessModel::CpuInfo>& cpus) { - for (size_t i = 0; i < cpus.size(); i++) - cpu_graphs[i]->add_value({ (int)cpus[i].total_cpu_percent, (int)cpus[i].total_cpu_percent_kernel }); - }; - - auto& memory_graph_group_box = self.add<GUI::GroupBox>("Memory usage"); - memory_graph_group_box.set_layout<GUI::VerticalBoxLayout>(); - memory_graph_group_box.layout()->set_margins({ 6, 16, 6, 6 }); - memory_graph_group_box.set_fixed_height(120); - auto& memory_graph = memory_graph_group_box.add<GraphWidget>(); - memory_graph.set_background_color(Color::White); - memory_graph.set_stack_values(true); - memory_graph.set_value_format(0, { - .line_color = Color::from_rgb(0x619910), - .background_color = Color::from_rgb(0xbbffbb), - .text_formatter = [&memory_graph](int value) { - return String::formatted("Committed: {} KiB", value); - }, - }); - memory_graph.set_value_format(1, { - .line_color = Color::Blue, - .background_color = Color::from_rgb(0xaaaaff), - .text_formatter = [&memory_graph](int value) { - return String::formatted("Allocated: {} KiB", value); - }, - }); - memory_graph.set_value_format(2, { - .line_color = Color::Red, - .background_color = Color::from_rgb(0xffaaaa), - .text_formatter = [&memory_graph](int value) { - return String::formatted("Kernel heap: {} KiB", value); - }, - }); - - self.add<MemoryStatsWidget>(memory_graph); - }; - return graphs_container; -} - -NonnullRefPtr<GUI::Widget> build_processors_tab() -{ - auto processors_widget = GUI::LazyWidget::construct(); - - processors_widget->on_first_show = [](GUI::LazyWidget& self) { - self.set_layout<GUI::VerticalBoxLayout>(); - self.layout()->set_margins({ 4, 4, 4, 4 }); - - Vector<GUI::JsonArrayModel::FieldSpec> processors_field; - processors_field.empend("processor", "Processor", Gfx::TextAlignment::CenterRight); - processors_field.empend("cpuid", "CPUID", Gfx::TextAlignment::CenterLeft); - processors_field.empend("brandstr", "Brand", Gfx::TextAlignment::CenterLeft); - processors_field.empend("Features", Gfx::TextAlignment::CenterLeft, [](auto& object) { - StringBuilder builder; - auto features = object.get("features").as_array(); - for (auto& feature : features.values()) { - builder.append(feature.to_string()); - builder.append(' '); - } - return GUI::Variant(builder.to_string()); - }); - processors_field.empend("family", "Family", Gfx::TextAlignment::CenterRight); - processors_field.empend("model", "Model", Gfx::TextAlignment::CenterRight); - processors_field.empend("stepping", "Stepping", Gfx::TextAlignment::CenterRight); - processors_field.empend("type", "Type", Gfx::TextAlignment::CenterRight); - - auto& processors_table_view = self.add<GUI::TableView>(); - processors_table_view.set_model(GUI::JsonArrayModel::create("/proc/cpuinfo", move(processors_field))); - processors_table_view.model()->update(); - }; - - return processors_widget; -} |