소스 검색

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. :^)
Andreas Kling 6 년 전
부모
커밋
5ded77df39

+ 10 - 0
Applications/ProcessManager/ProcessModel.cpp

@@ -3,6 +3,7 @@
 #include <AK/JsonArray.h>
 #include <AK/JsonObject.h>
 #include <AK/JsonValue.h>
+#include <LibC/SharedBuffer.h>
 #include <LibCore/CProcessStatisticsReader.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -138,6 +139,14 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
     if (role == Role::Display) {
         switch (index.column()) {
         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;
         case Column::PID:
             return process.current_state.pid;
@@ -193,6 +202,7 @@ void ProcessModel::update()
         state.name = it.value.name;
         state.amount_virtual = it.value.amount_virtual;
         state.amount_resident = it.value.amount_resident;
+        state.icon_id = it.value.icon_id;
         sum_times_scheduled += it.value.times_scheduled;
         {
             auto pit = m_processes.find(it.value.pid);

+ 1 - 0
Applications/ProcessManager/ProcessModel.h

@@ -50,6 +50,7 @@ private:
         size_t amount_resident;
         unsigned syscall_count;
         float cpu_percent;
+        int icon_id;
     };
 
     struct Process {

+ 1 - 0
Kernel/FileSystem/ProcFS.cpp

@@ -548,6 +548,7 @@ ByteBuffer procfs$all(InodeIdentifier)
         process_object.set("ticks", process.main_thread().ticks());
         process_object.set("priority", to_string(process.priority()));
         process_object.set("syscall_count", process.syscall_count());
+        process_object.set("icon_id", process.icon_id());
         array.append(process_object);
     };
     build_process(*Scheduler::colonel());

+ 26 - 0
Kernel/Process.cpp

@@ -2452,6 +2452,19 @@ int Process::sys$share_buffer_with(int shared_buffer_id, pid_t peer_pid)
     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)
 {
     LOCKER(shared_buffers().lock());
@@ -2773,3 +2786,16 @@ String Process::backtrace(ProcessInspectionHandle& handle) const
     });
     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;
+}

+ 7 - 0
Kernel/Process.h

@@ -22,6 +22,7 @@ class PageDirectory;
 class Region;
 class VMObject;
 class ProcessTracer;
+class SharedBuffer;
 
 timeval kgettimeofday();
 void kgettimeofday(timeval&);
@@ -208,12 +209,14 @@ public:
     int sys$mknod(const char* pathname, mode_t, dev_t);
     int sys$create_shared_buffer(int, void** buffer);
     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);
     int sys$release_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$halt();
     int sys$reboot();
+    int sys$set_process_icon(int icon_id);
 
     static void initialize();
 
@@ -281,6 +284,8 @@ public:
 
     const ELFLoader* elf_loader() const { return m_elf_loader.ptr(); }
 
+    int icon_id() const { return m_icon_id; }
+
 private:
     friend class MemoryManager;
     friend class Scheduler;
@@ -359,6 +364,8 @@ private:
     Lock m_big_lock { "Process" };
 
     u64 m_alarm_deadline { 0 };
+
+    int m_icon_id { -1 };
 };
 
 class ProcessInspectionHandle {

+ 16 - 1
Kernel/SharedBuffer.cpp

@@ -1,5 +1,5 @@
-#include <Kernel/SharedBuffer.h>
 #include <Kernel/Process.h>
+#include <Kernel/SharedBuffer.h>
 
 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)
 {
     LOCKER(shared_buffers().lock());
+    if (m_global)
+        return true;
     for (auto& ref : m_refs) {
         if (ref.pid == peer_pid) {
             return true;
@@ -42,6 +44,18 @@ void* SharedBuffer::ref_for_process_and_get_address(Process& process)
 {
     LOCKER(shared_buffers().lock());
     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) {
         if (ref.pid == process.pid()) {
             ref.count++;
@@ -93,6 +107,7 @@ void SharedBuffer::deref_for_process(Process& process)
                 destroy_if_unused();
                 return;
             }
+            return;
         }
     }
 

+ 3 - 0
Kernel/SharedBuffer.h

@@ -36,14 +36,17 @@ public:
     bool is_shared_with(pid_t peer_pid);
     void* ref_for_process_and_get_address(Process& process);
     void share_with(pid_t peer_pid);
+    void share_globally() { m_global = true; }
     void deref_for_process(Process& process);
     void disown(pid_t pid);
     size_t size() const { return m_vmo->size(); }
     void destroy_if_unused();
     void seal();
+    int id() const { return m_shared_buffer_id; }
 
     int m_shared_buffer_id { -1 };
     bool m_writable { true };
+    bool m_global { false };
     NonnullRefPtr<VMObject> m_vmo;
     Vector<Reference, 2> m_refs;
     unsigned m_total_refs { 0 };

+ 4 - 0
Kernel/Syscall.cpp

@@ -299,6 +299,10 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3
         return current->process().sys$dump_backtrace();
     case Syscall::SC_watch_file:
         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:
         kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
         return -ENOSYS;

+ 3 - 1
Kernel/Syscall.h

@@ -119,7 +119,9 @@ struct timeval;
     __ENUMERATE_SYSCALL(dump_backtrace)         \
     __ENUMERATE_SYSCALL(dbgputch)               \
     __ENUMERATE_SYSCALL(dbgputstr)              \
-    __ENUMERATE_SYSCALL(watch_file)
+    __ENUMERATE_SYSCALL(watch_file)             \
+    __ENUMERATE_SYSCALL(share_buffer_globally)  \
+    __ENUMERATE_SYSCALL(set_process_icon)
 
 namespace Syscall {
 

+ 12 - 0
Libraries/LibC/unistd.cpp

@@ -442,6 +442,18 @@ int share_buffer_with(int shared_buffer_id, pid_t peer_pid)
     __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)
 {
     int rc = syscall(SC_get_shared_buffer, shared_buffer_id);

+ 2 - 0
Libraries/LibC/unistd.h

@@ -24,10 +24,12 @@ int create_thread(int (*)(void*), void*);
 void exit_thread(int);
 int create_shared_buffer(int, void** buffer);
 int share_buffer_with(int, pid_t peer_pid);
+int share_buffer_globally(int);
 void* get_shared_buffer(int shared_buffer_id);
 int release_shared_buffer(int shared_buffer_id);
 int seal_shared_buffer(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);
 inline int getpagesize() { return 4096; }
 pid_t fork();

+ 1 - 0
Libraries/LibCore/CProcessStatisticsReader.cpp

@@ -43,6 +43,7 @@ HashMap<pid_t, CProcessStatistics> CProcessStatisticsReader::get_all()
         process.ticks = process_object.get("ticks").to_u32();
         process.priority = process_object.get("priority").to_string();
         process.syscall_count = process_object.get("syscall_count").to_u32();
+        process.icon_id = process_object.get("icon_id").to_int();
 
         // and synthetic data last
         process.username = username_from_uid(process.uid);

+ 1 - 0
Libraries/LibCore/CProcessStatisticsReader.h

@@ -24,6 +24,7 @@ struct CProcessStatistics {
     unsigned ticks;
     String priority;
     unsigned syscall_count;
+    int icon_id;
 
     // synthetic
     String username;

+ 10 - 0
Libraries/LibGUI/GWindow.cpp

@@ -635,6 +635,16 @@ void GWindow::set_icon(const GraphicsBitmap* icon)
         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;
     message.type = WSAPI_ClientMessage::Type::SetWindowIconBitmap;
     message.window_id = m_window_id;