mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:08:10 +00:00
Kernel+ProcessManager: Let processes have an icon and show it in the table.
Processes can now have an icon assigned, which is essentially a 16x16 RGBA32 bitmap exposed as a shared buffer ID. You set the icon ID by calling set_process_icon(int) and the icon ID will be exposed through /proc/all. To make this work, I added a mechanism for making shared buffers globally accessible. For safety reasons, each app seals the icon buffer before making it global. Right now the first call to GWindow::set_icon() is what determines the process icon. We'll probably change this in the future. :^)
This commit is contained in:
parent
7356fd389f
commit
5ded77df39
14 changed files with 97 additions and 2 deletions
|
@ -3,6 +3,7 @@
|
||||||
#include <AK/JsonArray.h>
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
#include <AK/JsonValue.h>
|
#include <AK/JsonValue.h>
|
||||||
|
#include <LibC/SharedBuffer.h>
|
||||||
#include <LibCore/CProcessStatisticsReader.h>
|
#include <LibCore/CProcessStatisticsReader.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -138,6 +139,14 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
|
||||||
if (role == Role::Display) {
|
if (role == Role::Display) {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case Column::Icon:
|
case Column::Icon:
|
||||||
|
if (process.current_state.icon_id != -1) {
|
||||||
|
auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(process.current_state.icon_id);
|
||||||
|
if (icon_buffer) {
|
||||||
|
auto icon_bitmap = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *icon_buffer, { 16, 16 });
|
||||||
|
if (icon_bitmap)
|
||||||
|
return *icon_bitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
return *m_generic_process_icon;
|
return *m_generic_process_icon;
|
||||||
case Column::PID:
|
case Column::PID:
|
||||||
return process.current_state.pid;
|
return process.current_state.pid;
|
||||||
|
@ -193,6 +202,7 @@ void ProcessModel::update()
|
||||||
state.name = it.value.name;
|
state.name = it.value.name;
|
||||||
state.amount_virtual = it.value.amount_virtual;
|
state.amount_virtual = it.value.amount_virtual;
|
||||||
state.amount_resident = it.value.amount_resident;
|
state.amount_resident = it.value.amount_resident;
|
||||||
|
state.icon_id = it.value.icon_id;
|
||||||
sum_times_scheduled += it.value.times_scheduled;
|
sum_times_scheduled += it.value.times_scheduled;
|
||||||
{
|
{
|
||||||
auto pit = m_processes.find(it.value.pid);
|
auto pit = m_processes.find(it.value.pid);
|
||||||
|
|
|
@ -50,6 +50,7 @@ private:
|
||||||
size_t amount_resident;
|
size_t amount_resident;
|
||||||
unsigned syscall_count;
|
unsigned syscall_count;
|
||||||
float cpu_percent;
|
float cpu_percent;
|
||||||
|
int icon_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Process {
|
struct Process {
|
||||||
|
|
|
@ -548,6 +548,7 @@ ByteBuffer procfs$all(InodeIdentifier)
|
||||||
process_object.set("ticks", process.main_thread().ticks());
|
process_object.set("ticks", process.main_thread().ticks());
|
||||||
process_object.set("priority", to_string(process.priority()));
|
process_object.set("priority", to_string(process.priority()));
|
||||||
process_object.set("syscall_count", process.syscall_count());
|
process_object.set("syscall_count", process.syscall_count());
|
||||||
|
process_object.set("icon_id", process.icon_id());
|
||||||
array.append(process_object);
|
array.append(process_object);
|
||||||
};
|
};
|
||||||
build_process(*Scheduler::colonel());
|
build_process(*Scheduler::colonel());
|
||||||
|
|
|
@ -2452,6 +2452,19 @@ int Process::sys$share_buffer_with(int shared_buffer_id, pid_t peer_pid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Process::sys$share_buffer_globally(int shared_buffer_id)
|
||||||
|
{
|
||||||
|
LOCKER(shared_buffers().lock());
|
||||||
|
auto it = shared_buffers().resource().find(shared_buffer_id);
|
||||||
|
if (it == shared_buffers().resource().end())
|
||||||
|
return -EINVAL;
|
||||||
|
auto& shared_buffer = *(*it).value;
|
||||||
|
if (!shared_buffer.is_shared_with(m_pid))
|
||||||
|
return -EPERM;
|
||||||
|
shared_buffer.share_globally();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Process::sys$release_shared_buffer(int shared_buffer_id)
|
int Process::sys$release_shared_buffer(int shared_buffer_id)
|
||||||
{
|
{
|
||||||
LOCKER(shared_buffers().lock());
|
LOCKER(shared_buffers().lock());
|
||||||
|
@ -2773,3 +2786,16 @@ String Process::backtrace(ProcessInspectionHandle& handle) const
|
||||||
});
|
});
|
||||||
return builder.to_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Process::sys$set_process_icon(int icon_id)
|
||||||
|
{
|
||||||
|
LOCKER(shared_buffers().lock());
|
||||||
|
auto it = shared_buffers().resource().find(icon_id);
|
||||||
|
if (it == shared_buffers().resource().end())
|
||||||
|
return -EINVAL;
|
||||||
|
auto& shared_buffer = *(*it).value;
|
||||||
|
if (!shared_buffer.is_shared_with(m_pid))
|
||||||
|
return -EPERM;
|
||||||
|
m_icon_id = icon_id;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ class PageDirectory;
|
||||||
class Region;
|
class Region;
|
||||||
class VMObject;
|
class VMObject;
|
||||||
class ProcessTracer;
|
class ProcessTracer;
|
||||||
|
class SharedBuffer;
|
||||||
|
|
||||||
timeval kgettimeofday();
|
timeval kgettimeofday();
|
||||||
void kgettimeofday(timeval&);
|
void kgettimeofday(timeval&);
|
||||||
|
@ -208,12 +209,14 @@ public:
|
||||||
int sys$mknod(const char* pathname, mode_t, dev_t);
|
int sys$mknod(const char* pathname, mode_t, dev_t);
|
||||||
int sys$create_shared_buffer(int, void** buffer);
|
int sys$create_shared_buffer(int, void** buffer);
|
||||||
int sys$share_buffer_with(int, pid_t peer_pid);
|
int sys$share_buffer_with(int, pid_t peer_pid);
|
||||||
|
int sys$share_buffer_globally(int);
|
||||||
void* sys$get_shared_buffer(int shared_buffer_id);
|
void* sys$get_shared_buffer(int shared_buffer_id);
|
||||||
int sys$release_shared_buffer(int shared_buffer_id);
|
int sys$release_shared_buffer(int shared_buffer_id);
|
||||||
int sys$seal_shared_buffer(int shared_buffer_id);
|
int sys$seal_shared_buffer(int shared_buffer_id);
|
||||||
int sys$get_shared_buffer_size(int shared_buffer_id);
|
int sys$get_shared_buffer_size(int shared_buffer_id);
|
||||||
int sys$halt();
|
int sys$halt();
|
||||||
int sys$reboot();
|
int sys$reboot();
|
||||||
|
int sys$set_process_icon(int icon_id);
|
||||||
|
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
|
@ -281,6 +284,8 @@ public:
|
||||||
|
|
||||||
const ELFLoader* elf_loader() const { return m_elf_loader.ptr(); }
|
const ELFLoader* elf_loader() const { return m_elf_loader.ptr(); }
|
||||||
|
|
||||||
|
int icon_id() const { return m_icon_id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MemoryManager;
|
friend class MemoryManager;
|
||||||
friend class Scheduler;
|
friend class Scheduler;
|
||||||
|
@ -359,6 +364,8 @@ private:
|
||||||
Lock m_big_lock { "Process" };
|
Lock m_big_lock { "Process" };
|
||||||
|
|
||||||
u64 m_alarm_deadline { 0 };
|
u64 m_alarm_deadline { 0 };
|
||||||
|
|
||||||
|
int m_icon_id { -1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProcessInspectionHandle {
|
class ProcessInspectionHandle {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <Kernel/SharedBuffer.h>
|
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
|
#include <Kernel/SharedBuffer.h>
|
||||||
|
|
||||||
Lockable<HashMap<int, NonnullOwnPtr<SharedBuffer>>>& shared_buffers()
|
Lockable<HashMap<int, NonnullOwnPtr<SharedBuffer>>>& shared_buffers()
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,8 @@ void SharedBuffer::sanity_check(const char* what)
|
||||||
bool SharedBuffer::is_shared_with(pid_t peer_pid)
|
bool SharedBuffer::is_shared_with(pid_t peer_pid)
|
||||||
{
|
{
|
||||||
LOCKER(shared_buffers().lock());
|
LOCKER(shared_buffers().lock());
|
||||||
|
if (m_global)
|
||||||
|
return true;
|
||||||
for (auto& ref : m_refs) {
|
for (auto& ref : m_refs) {
|
||||||
if (ref.pid == peer_pid) {
|
if (ref.pid == peer_pid) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -42,6 +44,18 @@ void* SharedBuffer::ref_for_process_and_get_address(Process& process)
|
||||||
{
|
{
|
||||||
LOCKER(shared_buffers().lock());
|
LOCKER(shared_buffers().lock());
|
||||||
ASSERT(is_shared_with(process.pid()));
|
ASSERT(is_shared_with(process.pid()));
|
||||||
|
if (m_global) {
|
||||||
|
bool found = false;
|
||||||
|
for (auto& ref : m_refs) {
|
||||||
|
if (ref.pid == process.pid()) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
m_refs.append(Reference(process.pid()));
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& ref : m_refs) {
|
for (auto& ref : m_refs) {
|
||||||
if (ref.pid == process.pid()) {
|
if (ref.pid == process.pid()) {
|
||||||
ref.count++;
|
ref.count++;
|
||||||
|
@ -93,6 +107,7 @@ void SharedBuffer::deref_for_process(Process& process)
|
||||||
destroy_if_unused();
|
destroy_if_unused();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,14 +36,17 @@ public:
|
||||||
bool is_shared_with(pid_t peer_pid);
|
bool is_shared_with(pid_t peer_pid);
|
||||||
void* ref_for_process_and_get_address(Process& process);
|
void* ref_for_process_and_get_address(Process& process);
|
||||||
void share_with(pid_t peer_pid);
|
void share_with(pid_t peer_pid);
|
||||||
|
void share_globally() { m_global = true; }
|
||||||
void deref_for_process(Process& process);
|
void deref_for_process(Process& process);
|
||||||
void disown(pid_t pid);
|
void disown(pid_t pid);
|
||||||
size_t size() const { return m_vmo->size(); }
|
size_t size() const { return m_vmo->size(); }
|
||||||
void destroy_if_unused();
|
void destroy_if_unused();
|
||||||
void seal();
|
void seal();
|
||||||
|
int id() const { return m_shared_buffer_id; }
|
||||||
|
|
||||||
int m_shared_buffer_id { -1 };
|
int m_shared_buffer_id { -1 };
|
||||||
bool m_writable { true };
|
bool m_writable { true };
|
||||||
|
bool m_global { false };
|
||||||
NonnullRefPtr<VMObject> m_vmo;
|
NonnullRefPtr<VMObject> m_vmo;
|
||||||
Vector<Reference, 2> m_refs;
|
Vector<Reference, 2> m_refs;
|
||||||
unsigned m_total_refs { 0 };
|
unsigned m_total_refs { 0 };
|
||||||
|
|
|
@ -299,6 +299,10 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3
|
||||||
return current->process().sys$dump_backtrace();
|
return current->process().sys$dump_backtrace();
|
||||||
case Syscall::SC_watch_file:
|
case Syscall::SC_watch_file:
|
||||||
return current->process().sys$watch_file((const char*)arg1, (int)arg2);
|
return current->process().sys$watch_file((const char*)arg1, (int)arg2);
|
||||||
|
case Syscall::SC_share_buffer_globally:
|
||||||
|
return current->process().sys$share_buffer_globally((int)arg1);
|
||||||
|
case Syscall::SC_set_process_icon:
|
||||||
|
return current->process().sys$set_process_icon((int)arg1);
|
||||||
default:
|
default:
|
||||||
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
|
@ -119,7 +119,9 @@ struct timeval;
|
||||||
__ENUMERATE_SYSCALL(dump_backtrace) \
|
__ENUMERATE_SYSCALL(dump_backtrace) \
|
||||||
__ENUMERATE_SYSCALL(dbgputch) \
|
__ENUMERATE_SYSCALL(dbgputch) \
|
||||||
__ENUMERATE_SYSCALL(dbgputstr) \
|
__ENUMERATE_SYSCALL(dbgputstr) \
|
||||||
__ENUMERATE_SYSCALL(watch_file)
|
__ENUMERATE_SYSCALL(watch_file) \
|
||||||
|
__ENUMERATE_SYSCALL(share_buffer_globally) \
|
||||||
|
__ENUMERATE_SYSCALL(set_process_icon)
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
|
||||||
|
|
|
@ -442,6 +442,18 @@ int share_buffer_with(int shared_buffer_id, pid_t peer_pid)
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int share_buffer_globally(int shared_buffer_id)
|
||||||
|
{
|
||||||
|
int rc = syscall(SC_share_buffer_globally, shared_buffer_id);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_process_icon(int icon_id)
|
||||||
|
{
|
||||||
|
int rc = syscall(SC_set_process_icon, icon_id);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
void* get_shared_buffer(int shared_buffer_id)
|
void* get_shared_buffer(int shared_buffer_id)
|
||||||
{
|
{
|
||||||
int rc = syscall(SC_get_shared_buffer, shared_buffer_id);
|
int rc = syscall(SC_get_shared_buffer, shared_buffer_id);
|
||||||
|
|
|
@ -24,10 +24,12 @@ int create_thread(int (*)(void*), void*);
|
||||||
void exit_thread(int);
|
void exit_thread(int);
|
||||||
int create_shared_buffer(int, void** buffer);
|
int create_shared_buffer(int, void** buffer);
|
||||||
int share_buffer_with(int, pid_t peer_pid);
|
int share_buffer_with(int, pid_t peer_pid);
|
||||||
|
int share_buffer_globally(int);
|
||||||
void* get_shared_buffer(int shared_buffer_id);
|
void* get_shared_buffer(int shared_buffer_id);
|
||||||
int release_shared_buffer(int shared_buffer_id);
|
int release_shared_buffer(int shared_buffer_id);
|
||||||
int seal_shared_buffer(int shared_buffer_id);
|
int seal_shared_buffer(int shared_buffer_id);
|
||||||
int get_shared_buffer_size(int shared_buffer_id);
|
int get_shared_buffer_size(int shared_buffer_id);
|
||||||
|
int set_process_icon(int icon_id);
|
||||||
int read_tsc(unsigned* lsw, unsigned* msw);
|
int read_tsc(unsigned* lsw, unsigned* msw);
|
||||||
inline int getpagesize() { return 4096; }
|
inline int getpagesize() { return 4096; }
|
||||||
pid_t fork();
|
pid_t fork();
|
||||||
|
|
|
@ -43,6 +43,7 @@ HashMap<pid_t, CProcessStatistics> CProcessStatisticsReader::get_all()
|
||||||
process.ticks = process_object.get("ticks").to_u32();
|
process.ticks = process_object.get("ticks").to_u32();
|
||||||
process.priority = process_object.get("priority").to_string();
|
process.priority = process_object.get("priority").to_string();
|
||||||
process.syscall_count = process_object.get("syscall_count").to_u32();
|
process.syscall_count = process_object.get("syscall_count").to_u32();
|
||||||
|
process.icon_id = process_object.get("icon_id").to_int();
|
||||||
|
|
||||||
// and synthetic data last
|
// and synthetic data last
|
||||||
process.username = username_from_uid(process.uid);
|
process.username = username_from_uid(process.uid);
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct CProcessStatistics {
|
||||||
unsigned ticks;
|
unsigned ticks;
|
||||||
String priority;
|
String priority;
|
||||||
unsigned syscall_count;
|
unsigned syscall_count;
|
||||||
|
int icon_id;
|
||||||
|
|
||||||
// synthetic
|
// synthetic
|
||||||
String username;
|
String username;
|
||||||
|
|
|
@ -635,6 +635,16 @@ void GWindow::set_icon(const GraphicsBitmap* icon)
|
||||||
painter.blit({ 0, 0 }, *icon, icon->rect());
|
painter.blit({ 0, 0 }, *icon, icon->rect());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rc = seal_shared_buffer(m_icon->shared_buffer_id());
|
||||||
|
ASSERT(rc == 0);
|
||||||
|
|
||||||
|
rc = share_buffer_globally(m_icon->shared_buffer_id());
|
||||||
|
ASSERT(rc == 0);
|
||||||
|
|
||||||
|
static bool has_set_process_icon;
|
||||||
|
if (!has_set_process_icon)
|
||||||
|
set_process_icon(m_icon->shared_buffer_id());
|
||||||
|
|
||||||
WSAPI_ClientMessage message;
|
WSAPI_ClientMessage message;
|
||||||
message.type = WSAPI_ClientMessage::Type::SetWindowIconBitmap;
|
message.type = WSAPI_ClientMessage::Type::SetWindowIconBitmap;
|
||||||
message.window_id = m_window_id;
|
message.window_id = m_window_id;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue