Serenity Operating System
1/*
2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, the SerenityOS developers.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include "ProcessStateWidget.h"
9#include "ProcessModel.h"
10#include <LibCore/Timer.h>
11#include <LibGUI/BoxLayout.h>
12#include <LibGUI/HeaderView.h>
13#include <LibGUI/Painter.h>
14#include <LibGUI/TableView.h>
15#include <LibGUI/Widget.h>
16#include <LibGfx/Font/FontDatabase.h>
17#include <LibGfx/Palette.h>
18
19REGISTER_WIDGET(SystemMonitor, ProcessStateWidget)
20
21namespace SystemMonitor {
22
23class ProcessStateModel final
24 : public GUI::Model
25 , public GUI::ModelClient {
26public:
27 explicit ProcessStateModel(ProcessModel& target, pid_t pid)
28 : m_target(target)
29 , m_pid(pid)
30 {
31 m_target.register_client(*this);
32 refresh();
33 }
34
35 virtual ~ProcessStateModel() override
36 {
37 m_target.unregister_client(*this);
38 }
39
40 virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return m_target.column_count({}); }
41 virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return 2; }
42
43 virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role = GUI::ModelRole::Display) const override
44 {
45 if (role == GUI::ModelRole::Display) {
46 if (index.column() == 0) {
47 if (index.row() == ProcessModel::Column::Icon) {
48 // NOTE: The icon column is nameless in ProcessModel, but we want it to have a name here.
49 return "Icon";
50 }
51 return m_target.column_name(index.row());
52 }
53 return m_target_index.sibling_at_column(index.row()).data();
54 }
55
56 if (role == GUI::ModelRole::Font) {
57 if (index.column() == 0) {
58 return Gfx::FontDatabase::default_font().bold_variant();
59 }
60 }
61
62 return {};
63 }
64
65 virtual void model_did_update([[maybe_unused]] unsigned flags) override
66 {
67 refresh();
68 }
69
70 void refresh()
71 {
72 m_target_index = {};
73 for (int row = 0; row < m_target.row_count({}); ++row) {
74 auto index = m_target.index(row, ProcessModel::Column::PID);
75 if (index.data().to_i32() == m_pid) {
76 m_target_index = index;
77 break;
78 }
79 }
80 did_update(GUI::Model::UpdateFlag::DontInvalidateIndices);
81 }
82
83 void set_pid(pid_t pid)
84 {
85 m_pid = pid;
86 refresh();
87 }
88 pid_t pid() const { return m_pid; }
89
90private:
91 ProcessModel& m_target;
92 GUI::ModelIndex m_target_index;
93 pid_t m_pid { -1 };
94};
95
96ProcessStateWidget::ProcessStateWidget()
97{
98 set_layout<GUI::VerticalBoxLayout>(4);
99 m_table_view = add<GUI::TableView>();
100 m_table_view->set_model(adopt_ref(*new ProcessStateModel(ProcessModel::the(), 0)));
101 m_table_view->column_header().set_visible(false);
102 m_table_view->column_header().set_section_size(0, 90);
103}
104
105void ProcessStateWidget::set_pid(pid_t pid)
106{
107 static_cast<ProcessStateModel*>(m_table_view->model())->set_pid(pid);
108 update();
109}
110
111}