mirror of
https://github.com/fergalmoran/ladybird.git
synced 2025-12-30 13:19:47 +00:00
Ladybird: Add a simple TaskManager window for tracking child processes
This implementation uses a really basic WebView to update stats once a second. In the future it might make more sense to both move the details into LibWebView, and to create a native widget for each platform to remove the overhead of having an extra WebView.
This commit is contained in:
committed by
Andrew Kaster
parent
096feaaeb8
commit
31c0d00ab1
@@ -124,6 +124,7 @@ if (ENABLE_QT)
|
|||||||
Qt/Settings.cpp
|
Qt/Settings.cpp
|
||||||
Qt/SettingsDialog.cpp
|
Qt/SettingsDialog.cpp
|
||||||
Qt/Tab.cpp
|
Qt/Tab.cpp
|
||||||
|
Qt/TaskManagerWindow.cpp
|
||||||
Qt/TVGIconEngine.cpp
|
Qt/TVGIconEngine.cpp
|
||||||
Qt/StringUtils.cpp
|
Qt/StringUtils.cpp
|
||||||
Qt/WebContentView.cpp
|
Qt/WebContentView.cpp
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SettingsDialog.h"
|
#include "SettingsDialog.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
#include "TaskManagerWindow.h"
|
||||||
#include "WebContentView.h"
|
#include "WebContentView.h"
|
||||||
#include <AK/TypeCasts.h>
|
#include <AK/TypeCasts.h>
|
||||||
#include <Ladybird/Utilities.h>
|
#include <Ladybird/Utilities.h>
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
#include <LibWebView/UserAgent.h>
|
#include <LibWebView/UserAgent.h>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
|
#include <QApplication>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
@@ -213,6 +215,14 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, WebView::Cook
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto* task_manager_action = new QAction("Open Task &Manager", this);
|
||||||
|
task_manager_action->setIcon(load_icon_from_uri("resource://icons/16x16/app-system-monitor.png"sv));
|
||||||
|
task_manager_action->setShortcuts({ QKeySequence("Ctrl+Shift+M") });
|
||||||
|
inspect_menu->addAction(task_manager_action);
|
||||||
|
QObject::connect(task_manager_action, &QAction::triggered, this, [this] {
|
||||||
|
show_task_manager_window();
|
||||||
|
});
|
||||||
|
|
||||||
auto* debug_menu = menuBar()->addMenu("&Debug");
|
auto* debug_menu = menuBar()->addMenu("&Debug");
|
||||||
|
|
||||||
auto* dump_session_history_tree_action = new QAction("Dump Session History Tree", this);
|
auto* dump_session_history_tree_action = new QAction("Dump Session History Tree", this);
|
||||||
@@ -890,4 +900,20 @@ void BrowserWindow::closeEvent(QCloseEvent* event)
|
|||||||
QMainWindow::closeEvent(event);
|
QMainWindow::closeEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BrowserWindow::show_task_manager_window()
|
||||||
|
{
|
||||||
|
if (!m_task_manager_window) {
|
||||||
|
m_task_manager_window = new TaskManagerWindow(this);
|
||||||
|
}
|
||||||
|
m_task_manager_window->show();
|
||||||
|
m_task_manager_window->activateWindow();
|
||||||
|
m_task_manager_window->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrowserWindow::close_task_manager_window()
|
||||||
|
{
|
||||||
|
if (m_task_manager_window)
|
||||||
|
m_task_manager_window->close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace Ladybird {
|
|||||||
|
|
||||||
class SettingsDialog;
|
class SettingsDialog;
|
||||||
class WebContentView;
|
class WebContentView;
|
||||||
|
class TaskManagerWindow;
|
||||||
|
|
||||||
class BrowserWindow : public QMainWindow {
|
class BrowserWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -132,6 +133,9 @@ private:
|
|||||||
QString tool_tip_for_page_mute_state(Tab&) const;
|
QString tool_tip_for_page_mute_state(Tab&) const;
|
||||||
QTabBar::ButtonPosition audio_button_position_for_tab(int tab_index) const;
|
QTabBar::ButtonPosition audio_button_position_for_tab(int tab_index) const;
|
||||||
|
|
||||||
|
void show_task_manager_window();
|
||||||
|
void close_task_manager_window();
|
||||||
|
|
||||||
QScreen* m_current_screen;
|
QScreen* m_current_screen;
|
||||||
double m_device_pixel_ratio { 0 };
|
double m_device_pixel_ratio { 0 };
|
||||||
|
|
||||||
@@ -150,6 +154,9 @@ private:
|
|||||||
|
|
||||||
SettingsDialog* m_settings_dialog { nullptr };
|
SettingsDialog* m_settings_dialog { nullptr };
|
||||||
|
|
||||||
|
// FIXME: This should be owned at a higher level in case we have multiple browser windows
|
||||||
|
TaskManagerWindow* m_task_manager_window { nullptr };
|
||||||
|
|
||||||
WebView::CookieJar& m_cookie_jar;
|
WebView::CookieJar& m_cookie_jar;
|
||||||
|
|
||||||
WebContentOptions m_web_content_options;
|
WebContentOptions m_web_content_options;
|
||||||
|
|||||||
49
Ladybird/Qt/TaskManagerWindow.cpp
Normal file
49
Ladybird/Qt/TaskManagerWindow.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TaskManagerWindow.h"
|
||||||
|
#include <LibWebView/ProcessManager.h>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace Ladybird {
|
||||||
|
|
||||||
|
TaskManagerWindow::TaskManagerWindow(QWidget* parent)
|
||||||
|
: QWidget(parent, Qt::WindowFlags(Qt::WindowType::Window))
|
||||||
|
, m_web_view(new WebContentView(this, {}, {}))
|
||||||
|
{
|
||||||
|
setLayout(new QVBoxLayout);
|
||||||
|
layout()->addWidget(m_web_view);
|
||||||
|
|
||||||
|
setWindowTitle("Task Manager");
|
||||||
|
resize(400, 300);
|
||||||
|
|
||||||
|
m_update_timer.setInterval(1000);
|
||||||
|
|
||||||
|
QObject::connect(&m_update_timer, &QTimer::timeout, [this] {
|
||||||
|
this->update_statistics();
|
||||||
|
});
|
||||||
|
|
||||||
|
update_statistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskManagerWindow::showEvent(QShowEvent*)
|
||||||
|
{
|
||||||
|
m_update_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskManagerWindow::hideEvent(QHideEvent*)
|
||||||
|
{
|
||||||
|
m_update_timer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskManagerWindow::update_statistics()
|
||||||
|
{
|
||||||
|
|
||||||
|
WebView::ProcessManager::the().update_all_processes();
|
||||||
|
m_web_view->load_html(WebView::ProcessManager::the().generate_html());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
31
Ladybird/Qt/TaskManagerWindow.h
Normal file
31
Ladybird/Qt/TaskManagerWindow.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WebContentView.h"
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace Ladybird {
|
||||||
|
|
||||||
|
class TaskManagerWindow : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TaskManagerWindow(QWidget* parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void showEvent(QShowEvent*) override;
|
||||||
|
virtual void hideEvent(QHideEvent*) override;
|
||||||
|
|
||||||
|
void update_statistics();
|
||||||
|
|
||||||
|
WebContentView* m_web_view { nullptr };
|
||||||
|
QTimer m_update_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ list(TRANSFORM FONTS PREPEND "${SERENITY_SOURCE_DIR}/Base/res/fonts/")
|
|||||||
|
|
||||||
set(16x16_ICONS
|
set(16x16_ICONS
|
||||||
app-browser.png
|
app-browser.png
|
||||||
|
app-system-monitor.png
|
||||||
audio-volume-high.png
|
audio-volume-high.png
|
||||||
audio-volume-muted.png
|
audio-volume-muted.png
|
||||||
close-tab.png
|
close-tab.png
|
||||||
@@ -48,6 +49,7 @@ set(16x16_ICONS
|
|||||||
)
|
)
|
||||||
set(32x32_ICONS
|
set(32x32_ICONS
|
||||||
app-browser.png
|
app-browser.png
|
||||||
|
app-system-monitor.png
|
||||||
filetype-folder.png
|
filetype-folder.png
|
||||||
filetype-unknown.png
|
filetype-unknown.png
|
||||||
msgbox-warning.png
|
msgbox-warning.png
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/String.h>
|
||||||
#include <LibCore/EventLoop.h>
|
#include <LibCore/EventLoop.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <LibWebView/ProcessManager.h>
|
#include <LibWebView/ProcessManager.h>
|
||||||
@@ -114,4 +115,70 @@ void ProcessManager::update_all_processes()
|
|||||||
// FIXME: Actually gather stats in a platform-specific way
|
// FIXME: Actually gather stats in a platform-specific way
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ProcessManager::generate_html()
|
||||||
|
{
|
||||||
|
StringBuilder builder;
|
||||||
|
auto processes = m_processes;
|
||||||
|
|
||||||
|
builder.append(R"(
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
td, th {
|
||||||
|
padding: 4px;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
tr:nth-child(odd) {
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>PID</th>
|
||||||
|
<th>Memory Usage</th>
|
||||||
|
<th>CPU %</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
)"sv);
|
||||||
|
|
||||||
|
for (auto& process : processes) {
|
||||||
|
builder.append("<tr>"sv);
|
||||||
|
builder.append("<td>"sv);
|
||||||
|
builder.append(WebView::process_name_from_type(process.type));
|
||||||
|
builder.append("</td>"sv);
|
||||||
|
builder.append("<td>"sv);
|
||||||
|
builder.append(MUST(String::number(process.pid)));
|
||||||
|
builder.append("</td>"sv);
|
||||||
|
builder.append("<td>"sv);
|
||||||
|
builder.append(MUST(String::formatted("{} KB", process.memory_usage_kib)));
|
||||||
|
builder.append("</td>"sv);
|
||||||
|
builder.append("<td>"sv);
|
||||||
|
builder.append(MUST(String::formatted("{:.1f}", process.cpu_percent)));
|
||||||
|
builder.append("</td>"sv);
|
||||||
|
builder.append("</tr>"sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append(R"(
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)"sv);
|
||||||
|
|
||||||
|
return builder.to_string_without_validation();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ public:
|
|||||||
void update_all_processes();
|
void update_all_processes();
|
||||||
Vector<ProcessInfo> processes() const { return m_processes; }
|
Vector<ProcessInfo> processes() const { return m_processes; }
|
||||||
|
|
||||||
|
String generate_html();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProcessManager();
|
ProcessManager();
|
||||||
~ProcessManager();
|
~ProcessManager();
|
||||||
|
|||||||
Reference in New Issue
Block a user