feat: port ProcMgr to new toolkit

This commit is contained in:
2026-04-10 22:55:51 +02:00
parent 91b09e8194
commit 0433274244
2 changed files with 254 additions and 219 deletions
+3
View File
@@ -39,6 +39,7 @@ CXXFLAGS := \
-msse2 \ -msse2 \
-mno-red-zone \ -mno-red-zone \
-mcmodel=small \ -mcmodel=small \
-MMD -MP \
-I $(PROG_INC) \ -I $(PROG_INC) \
-isystem $(PROG_INC)/libc \ -isystem $(PROG_INC)/libc \
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \ -isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
@@ -70,5 +71,7 @@ $(OBJDIR)/%.o: %.cpp Makefile
mkdir -p $(OBJDIR) mkdir -p $(OBJDIR)
$(CXX) $(CXXFLAGS) -c $< -o $@ $(CXX) $(CXXFLAGS) -c $< -o $@
-include $(OBJS:.o=.d)
clean: clean:
rm -rf $(OBJDIR) $(TARGET) rm -rf $(OBJDIR) $(TARGET)
+237 -205
View File
@@ -7,10 +7,7 @@
#include <montauk/syscall.h> #include <montauk/syscall.h>
#include <montauk/string.h> #include <montauk/string.h>
#include <montauk/heap.h> #include <montauk/heap.h>
#include <gui/gui.hpp> #include <gui/mtk.hpp>
#include <gui/canvas.hpp>
#include <gui/standalone.hpp>
#include <gui/truetype.hpp>
extern "C" { extern "C" {
#include <stdio.h> #include <stdio.h>
@@ -27,7 +24,6 @@ static constexpr int PM_ITEM_H = 28;
static constexpr int PM_POLL_MS = 1000; static constexpr int PM_POLL_MS = 1000;
static constexpr int PM_MAX_PROCS = 256; static constexpr int PM_MAX_PROCS = 256;
static constexpr int PM_MAX_WINDOWS = 64; static constexpr int PM_MAX_WINDOWS = 64;
static constexpr int FONT_SIZE = 18;
static constexpr Color PM_TOOLBAR_BG = Color::from_rgb(0xF5, 0xF5, 0xF5); static constexpr Color PM_TOOLBAR_BG = Color::from_rgb(0xF5, 0xF5, 0xF5);
static constexpr Color PM_HEADER_BG = Color::from_rgb(0xF0, 0xF0, 0xF0); static constexpr Color PM_HEADER_BG = Color::from_rgb(0xF0, 0xF0, 0xF0);
@@ -59,12 +55,27 @@ struct ProcMgrState {
int proc_scroll; int proc_scroll;
int win_scroll; int win_scroll;
int active_tab; int active_tab;
int mouse_x;
int mouse_y;
uint64_t last_poll_ms; uint64_t last_poll_ms;
}; };
static WsWindow g_win; static WsWindow g_win;
static ProcMgrState g_pm = {}; static ProcMgrState g_pm = {};
static mtk::Theme pm_theme() {
mtk::Theme theme = mtk::make_theme();
theme.surface = PM_TOOLBAR_BG;
theme.surface_alt = PM_HEADER_BG;
theme.border = PM_BORDER;
theme.text_muted = PM_DIM_TEXT;
theme.text_subtle = PM_DIM_TEXT;
theme.danger = PM_DANGER;
theme.danger_hover = mtk::darken(PM_DANGER, 18);
theme.disabled_bg = Color::from_rgb(0xAA, 0xAA, 0xAA);
return theme;
}
static void format_size(char* buf, uint64_t size) { static void format_size(char* buf, uint64_t size) {
if (size < 1024ULL) { if (size < 1024ULL) {
snprintf(buf, 24, "%llu B", (unsigned long long)size); snprintf(buf, 24, "%llu B", (unsigned long long)size);
@@ -120,24 +131,32 @@ static int content_top() {
return PM_TOOLBAR_H + PM_TAB_H; return PM_TOOLBAR_H + PM_TAB_H;
} }
static int process_list_y() { static mtk::TableLayout process_table_layout() {
return content_top() + PM_HEADER_H; int top = content_top();
int body_y = top + PM_HEADER_H;
return {
{0, top, g_win.width, PM_HEADER_H},
{0, body_y, g_win.width, gui_max(g_win.height - body_y, 0)},
PM_ITEM_H
};
} }
static int window_list_y() { static mtk::TableLayout window_table_layout() {
return content_top() + PM_HEADER_H; int top = content_top();
int body_y = top + PM_HEADER_H;
return {
{0, top, g_win.width, PM_HEADER_H},
{0, body_y, g_win.width, gui_max(g_win.height - body_y, 0)},
PM_ITEM_H
};
} }
static int process_visible_rows() { static int process_visible_rows() {
int avail = g_win.height - process_list_y(); return mtk::table_visible_rows(process_table_layout());
if (avail <= 0) return 0;
return avail / PM_ITEM_H;
} }
static int window_visible_rows() { static int window_visible_rows() {
int avail = g_win.height - window_list_y(); return mtk::table_visible_rows(window_table_layout());
if (avail <= 0) return 0;
return avail / PM_ITEM_H;
} }
static int live_process_count() { static int live_process_count() {
@@ -167,39 +186,18 @@ static int find_window_index_by_id(int id) {
} }
static void clamp_scrolls() { static void clamp_scrolls() {
int proc_vis = process_visible_rows(); mtk::clamp_table_scroll(&g_pm.proc_scroll, process_table_layout(), g_pm.proc_count);
int max_proc_scroll = 0; mtk::clamp_table_scroll(&g_pm.win_scroll, window_table_layout(), g_pm.win_count);
if (g_pm.proc_count > proc_vis && proc_vis > 0)
max_proc_scroll = g_pm.proc_count - proc_vis;
g_pm.proc_scroll = gui_clamp(g_pm.proc_scroll, 0, max_proc_scroll);
int win_vis = window_visible_rows();
int max_win_scroll = 0;
if (g_pm.win_count > win_vis && win_vis > 0)
max_win_scroll = g_pm.win_count - win_vis;
g_pm.win_scroll = gui_clamp(g_pm.win_scroll, 0, max_win_scroll);
} }
static void ensure_process_selection_visible() { static void ensure_process_selection_visible() {
if (g_pm.selected < 0) return; mtk::ensure_table_row_visible(&g_pm.proc_scroll, process_table_layout(),
int visible = process_visible_rows(); g_pm.proc_count, g_pm.selected);
if (visible <= 0) return;
if (g_pm.selected < g_pm.proc_scroll)
g_pm.proc_scroll = g_pm.selected;
else if (g_pm.selected >= g_pm.proc_scroll + visible)
g_pm.proc_scroll = g_pm.selected - visible + 1;
clamp_scrolls();
} }
static void ensure_window_selection_visible() { static void ensure_window_selection_visible() {
if (g_pm.selected_window < 0) return; mtk::ensure_table_row_visible(&g_pm.win_scroll, window_table_layout(),
int visible = window_visible_rows(); g_pm.win_count, g_pm.selected_window);
if (visible <= 0) return;
if (g_pm.selected_window < g_pm.win_scroll)
g_pm.win_scroll = g_pm.selected_window;
else if (g_pm.selected_window >= g_pm.win_scroll + visible)
g_pm.win_scroll = g_pm.selected_window - visible + 1;
clamp_scrolls();
} }
static bool refresh_state(bool force) { static bool refresh_state(bool force) {
@@ -219,7 +217,6 @@ static bool refresh_state(bool force) {
g_pm.proc_count = montauk::proclist(g_pm.procs, PM_MAX_PROCS); g_pm.proc_count = montauk::proclist(g_pm.procs, PM_MAX_PROCS);
if (g_pm.proc_count < 0) g_pm.proc_count = 0; if (g_pm.proc_count < 0) g_pm.proc_count = 0;
g_pm.selected = find_process_index_by_pid(prev_pid); g_pm.selected = find_process_index_by_pid(prev_pid);
g_pm.win_count = montauk::win_enumerate(g_pm.windows, PM_MAX_WINDOWS); g_pm.win_count = montauk::win_enumerate(g_pm.windows, PM_MAX_WINDOWS);
@@ -256,16 +253,78 @@ static void cycle_tab(int delta) {
clamp_scrolls(); clamp_scrolls();
} }
static void draw_text_fit(Canvas& c, TrueTypeFont* font, int x, int y, static Rect toolbar_rect() {
const char* text, int max_w, Color color, int size) { return {0, 0, g_win.width, PM_TOOLBAR_H};
}
static Rect refresh_button_rect() {
int btn_h = 26;
int btn_y = (PM_TOOLBAR_H - btn_h) / 2;
return {8, btn_y, 82, btn_h};
}
static Rect kill_button_rect() {
int btn_h = 26;
int btn_y = (PM_TOOLBAR_H - btn_h) / 2;
return {98, btn_y, 110, btn_h};
}
static Rect tab_bar_rect() {
return {0, PM_TOOLBAR_H, g_win.width, PM_TAB_H};
}
static bool mouse_in_rect(const Rect& rect) {
return rect.contains(g_pm.mouse_x, g_pm.mouse_y);
}
static void build_process_columns(mtk::TableColumn* cols) {
int col_pid = 12;
int col_ppid = 64;
int col_name = 124;
int col_heap = g_win.width - 150;
int col_state = g_win.width - 70;
cols[0] = {"PID", col_pid, gui_max(col_ppid - col_pid - 8, 0)};
cols[1] = {"PPID", col_ppid, gui_max(col_name - col_ppid - 10, 0)};
cols[2] = {"Name", col_name, gui_max(col_heap - col_name - 10, 0)};
cols[3] = {"Heap", col_heap, gui_max(col_state - col_heap - 8, 0)};
cols[4] = {"State", col_state, gui_max(g_win.width - col_state - 8, 0)};
}
static void build_window_columns(mtk::TableColumn* cols) {
int col_id = 12;
int col_pid = 60;
int col_title = 118;
int col_size = g_win.width - 130;
int col_dirty = g_win.width - 52;
cols[0] = {"ID", col_id, gui_max(col_pid - col_id - 8, 0)};
cols[1] = {"PID", col_pid, gui_max(col_title - col_pid - 10, 0)};
cols[2] = {"Title", col_title, gui_max(col_size - col_title - 10, 0)};
cols[3] = {"Size", col_size, gui_max(col_dirty - col_size - 8, 0)};
cols[4] = {"D", col_dirty, gui_max(g_win.width - col_dirty - 8, 0)};
}
static int hovered_process_row() {
if (g_pm.active_tab != PM_TAB_PROCESSES) return -1;
return mtk::table_hit_row(process_table_layout(), g_pm.proc_scroll,
g_pm.proc_count, g_pm.mouse_x, g_pm.mouse_y);
}
static int hovered_window_row() {
if (g_pm.active_tab != PM_TAB_WINDOWS) return -1;
return mtk::table_hit_row(window_table_layout(), g_pm.win_scroll,
g_pm.win_count, g_pm.mouse_x, g_pm.mouse_y);
}
static void draw_text_fit(Canvas& c, int x, int y,
const char* text, int max_w, Color color) {
if (!text || !text[0] || max_w <= 4) return; if (!text || !text[0] || max_w <= 4) return;
if (text_width(font, text, size) <= max_w) { if (text_width(text) <= max_w) {
draw_text(c, font, x, y, text, color, size); c.text(x, y, text, color);
return; return;
} }
const char* ellipsis = "..."; const char* ellipsis = "...";
int ell_w = text_width(font, ellipsis, size); int ell_w = text_width(ellipsis);
if (ell_w >= max_w) return; if (ell_w >= max_w) return;
char buf[96]; char buf[96];
@@ -273,7 +332,7 @@ static void draw_text_fit(Canvas& c, TrueTypeFont* font, int x, int y,
while (text[out] && out < (int)sizeof(buf) - 4) { while (text[out] && out < (int)sizeof(buf) - 4) {
buf[out] = text[out]; buf[out] = text[out];
buf[out + 1] = '\0'; buf[out + 1] = '\0';
if (text_width(font, buf, size) + ell_w > max_w) if (text_width(buf) + ell_w > max_w)
break; break;
out++; out++;
} }
@@ -283,21 +342,20 @@ static void draw_text_fit(Canvas& c, TrueTypeFont* font, int x, int y,
buf[out + 1] = '.'; buf[out + 1] = '.';
buf[out + 2] = '.'; buf[out + 2] = '.';
buf[out + 3] = '\0'; buf[out + 3] = '\0';
draw_text(c, font, x, y, buf, color, size); c.text(x, y, buf, color);
} }
static void render_toolbar(Canvas& c, TrueTypeFont* font, int fh) { static void render_toolbar(Canvas& c, const mtk::Theme& theme, int fh) {
c.fill_rect(0, 0, g_win.width, PM_TOOLBAR_H, PM_TOOLBAR_BG); Rect bar = toolbar_rect();
c.hline(0, PM_TOOLBAR_H - 1, g_win.width, PM_BORDER); c.fill_rect(bar.x, bar.y, bar.w, bar.h, theme.surface);
c.hline(bar.x, bar.y + bar.h - 1, bar.w, theme.border);
int btn_h = 26; Rect refresh_rect = refresh_button_rect();
int btn_y = (PM_TOOLBAR_H - btn_h) / 2; Rect kill_rect = kill_button_rect();
draw_button(c, font, 8, btn_y, 82, btn_h, "Refresh", mtk::draw_button(c, refresh_rect, "Refresh", mtk::BUTTON_TONAL,
Color::from_rgb(0xE3, 0xE8, 0xEF), colors::TEXT_COLOR, 4, FONT_SIZE); mtk::widget_state(false, mouse_in_rect(refresh_rect)), theme);
mtk::draw_button(c, kill_rect, "End Process", mtk::BUTTON_DANGER,
Color kill_bg = can_kill_selected() ? PM_DANGER : Color::from_rgb(0xAA, 0xAA, 0xAA); mtk::widget_state(false, mouse_in_rect(kill_rect), can_kill_selected()), theme);
draw_button(c, font, 98, btn_y, 110, btn_h, "End Process",
kill_bg, colors::WHITE, 4, FONT_SIZE);
char status[96]; char status[96];
if (g_pm.active_tab == PM_TAB_PROCESSES) { if (g_pm.active_tab == PM_TAB_PROCESSES) {
@@ -306,206 +364,177 @@ static void render_toolbar(Canvas& c, TrueTypeFont* font, int fh) {
} else { } else {
snprintf(status, sizeof(status), "%d windows", g_pm.win_count); snprintf(status, sizeof(status), "%d windows", g_pm.win_count);
} }
int status_w = text_width(font, status, FONT_SIZE);
draw_text(c, font, g_win.width - status_w - 12, (PM_TOOLBAR_H - fh) / 2, int status_w = text_width(status);
status, colors::TEXT_COLOR, FONT_SIZE); c.text(g_win.width - status_w - 12, (PM_TOOLBAR_H - fh) / 2, status, theme.text);
} }
static void render_tabs(Canvas& c, TrueTypeFont* font, int fh) { static void render_tabs(Canvas& c, const mtk::Theme& theme) {
int y = PM_TOOLBAR_H; mtk::draw_tab_bar(c, tab_bar_rect(), g_tab_labels, PM_TAB_COUNT, g_pm.active_tab, theme);
c.fill_rect(0, y, g_win.width, PM_TAB_H, PM_TOOLBAR_BG);
c.hline(0, y + PM_TAB_H - 1, g_win.width, PM_BORDER);
int tab_w = g_win.width / PM_TAB_COUNT;
for (int i = 0; i < PM_TAB_COUNT; i++) {
int tx = i * tab_w;
bool active = (i == g_pm.active_tab);
if (active) {
c.fill_rect(tx, y, tab_w, PM_TAB_H, colors::WINDOW_BG);
c.fill_rect(tx + 4, y + PM_TAB_H - 3, tab_w - 8, 3, colors::ACCENT);
}
int tw = text_width(font, g_tab_labels[i], FONT_SIZE);
Color color = active ? colors::ACCENT : PM_DIM_TEXT;
draw_text(c, font, tx + (tab_w - tw) / 2, y + (PM_TAB_H - fh) / 2,
g_tab_labels[i], color, FONT_SIZE);
}
} }
static void render_processes(Canvas& c, TrueTypeFont* font, int fh) { static void draw_process_row(Canvas& c, void* userdata, int row_index,
int header_y = content_top(); const Rect& row_rect, int text_y,
c.fill_rect(0, header_y, g_win.width, PM_HEADER_H, PM_HEADER_BG); const mtk::TableColumn* cols, int col_count,
c.hline(0, header_y + PM_HEADER_H - 1, g_win.width, PM_BORDER); const mtk::Theme& theme, const mtk::TableStyle& style) {
(void)userdata;
(void)col_count;
(void)style;
int col_pid = 12;
int col_ppid = 64;
int col_name = 124;
int col_heap = g_win.width - 150;
int col_state = g_win.width - 70;
int header_text_y = header_y + (PM_HEADER_H - fh) / 2;
draw_text(c, font, col_pid, header_text_y, "PID", PM_DIM_TEXT, FONT_SIZE);
draw_text(c, font, col_ppid, header_text_y, "PPID", PM_DIM_TEXT, FONT_SIZE);
draw_text(c, font, col_name, header_text_y, "Name", PM_DIM_TEXT, FONT_SIZE);
draw_text(c, font, col_heap, header_text_y, "Heap", PM_DIM_TEXT, FONT_SIZE);
draw_text(c, font, col_state, header_text_y, "State", PM_DIM_TEXT, FONT_SIZE);
int list_y = process_list_y();
int visible = process_visible_rows();
for (int row = 0; row < visible; row++) {
int index = g_pm.proc_scroll + row;
if (index >= g_pm.proc_count) break;
int row_y = list_y + row * PM_ITEM_H;
if (index == g_pm.selected)
c.fill_rect(0, row_y, g_win.width, PM_ITEM_H, colors::MENU_HOVER);
int text_y = row_y + (PM_ITEM_H - fh) / 2;
char buf[32]; char buf[32];
snprintf(buf, sizeof(buf), "%d", (int)g_pm.procs[index].pid); Rect pid_cell = mtk::table_cell_rect(row_rect, cols[0]);
draw_text(c, font, col_pid, text_y, buf, colors::TEXT_COLOR, FONT_SIZE); snprintf(buf, sizeof(buf), "%d", (int)g_pm.procs[row_index].pid);
c.text(pid_cell.x, text_y, buf, theme.text);
snprintf(buf, sizeof(buf), "%d", (int)g_pm.procs[index].parentPid); Rect ppid_cell = mtk::table_cell_rect(row_rect, cols[1]);
draw_text(c, font, col_ppid, text_y, buf, colors::TEXT_COLOR, FONT_SIZE); snprintf(buf, sizeof(buf), "%d", (int)g_pm.procs[row_index].parentPid);
c.text(ppid_cell.x, text_y, buf, theme.text);
draw_text_fit(c, font, col_name, text_y, g_pm.procs[index].name, Rect name_cell = mtk::table_cell_rect(row_rect, cols[2]);
col_heap - col_name - 10, colors::TEXT_COLOR, FONT_SIZE); draw_text_fit(c, name_cell.x, text_y, g_pm.procs[row_index].name,
name_cell.w, theme.text);
format_size(buf, g_pm.procs[index].heapUsed); Rect heap_cell = mtk::table_cell_rect(row_rect, cols[3]);
draw_text(c, font, col_heap, text_y, buf, colors::TEXT_COLOR, FONT_SIZE); format_size(buf, g_pm.procs[row_index].heapUsed);
c.text(heap_cell.x, text_y, buf, theme.text);
Rect state_cell = mtk::table_cell_rect(row_rect, cols[4]);
Color state_color; Color state_color;
const char* state = proc_state_label(g_pm.procs[index].state, &state_color); const char* state = proc_state_label(g_pm.procs[row_index].state, &state_color);
draw_text(c, font, col_state, text_y, state, state_color, FONT_SIZE); c.text(state_cell.x, text_y, state, state_color);
}
} }
static void render_windows(Canvas& c, TrueTypeFont* font, int fh) { static void render_processes(Canvas& c, const mtk::Theme& theme, int fh) {
int header_y = content_top(); (void)fh;
c.fill_rect(0, header_y, g_win.width, PM_HEADER_H, PM_HEADER_BG); mtk::TableLayout layout = process_table_layout();
c.hline(0, header_y + PM_HEADER_H - 1, g_win.width, PM_BORDER); mtk::TableColumn cols[5];
build_process_columns(cols);
int col_id = 12; mtk::TableStyle style = mtk::make_table_style(theme);
int col_pid = 60; style.row_selected_bg = colors::MENU_HOVER;
int col_title = 118; style.row_hover_bg = mtk::mix(theme.window_bg, theme.accent, 12);
int col_size = g_win.width - 130;
int col_dirty = g_win.width - 52;
int header_text_y = header_y + (PM_HEADER_H - fh) / 2;
draw_text(c, font, col_id, header_text_y, "ID", PM_DIM_TEXT, FONT_SIZE); mtk::draw_table(c, layout, cols, 5, g_pm.proc_count, g_pm.proc_scroll,
draw_text(c, font, col_pid, header_text_y, "PID", PM_DIM_TEXT, FONT_SIZE); g_pm.selected, hovered_process_row(),
draw_text(c, font, col_title, header_text_y, "Title", PM_DIM_TEXT, FONT_SIZE); theme, style, draw_process_row, nullptr);
draw_text(c, font, col_size, header_text_y, "Size", PM_DIM_TEXT, FONT_SIZE); }
draw_text(c, font, col_dirty, header_text_y, "D", PM_DIM_TEXT, FONT_SIZE);
int list_y = window_list_y(); static void draw_window_row(Canvas& c, void* userdata, int row_index,
int visible = window_visible_rows(); const Rect& row_rect, int text_y,
for (int row = 0; row < visible; row++) { const mtk::TableColumn* cols, int col_count,
int index = g_pm.win_scroll + row; const mtk::Theme& theme, const mtk::TableStyle& style) {
if (index >= g_pm.win_count) break; (void)userdata;
(void)col_count;
(void)style;
int row_y = list_y + row * PM_ITEM_H;
if (index == g_pm.selected_window)
c.fill_rect(0, row_y, g_win.width, PM_ITEM_H, colors::MENU_HOVER);
int text_y = row_y + (PM_ITEM_H - fh) / 2;
char buf[64]; char buf[64];
snprintf(buf, sizeof(buf), "%d", (int)g_pm.windows[index].id); Rect id_cell = mtk::table_cell_rect(row_rect, cols[0]);
draw_text(c, font, col_id, text_y, buf, colors::TEXT_COLOR, FONT_SIZE); snprintf(buf, sizeof(buf), "%d", (int)g_pm.windows[row_index].id);
c.text(id_cell.x, text_y, buf, theme.text);
snprintf(buf, sizeof(buf), "%d", (int)g_pm.windows[index].ownerPid); Rect pid_cell = mtk::table_cell_rect(row_rect, cols[1]);
draw_text(c, font, col_pid, text_y, buf, colors::TEXT_COLOR, FONT_SIZE); snprintf(buf, sizeof(buf), "%d", (int)g_pm.windows[row_index].ownerPid);
c.text(pid_cell.x, text_y, buf, theme.text);
draw_text_fit(c, font, col_title, text_y, g_pm.windows[index].title, Rect title_cell = mtk::table_cell_rect(row_rect, cols[2]);
col_size - col_title - 10, colors::TEXT_COLOR, FONT_SIZE); draw_text_fit(c, title_cell.x, text_y, g_pm.windows[row_index].title,
title_cell.w, theme.text);
snprintf(buf, sizeof(buf), "%dx%d", (int)g_pm.windows[index].width, (int)g_pm.windows[index].height); Rect size_cell = mtk::table_cell_rect(row_rect, cols[3]);
draw_text(c, font, col_size, text_y, buf, colors::TEXT_COLOR, FONT_SIZE); snprintf(buf, sizeof(buf), "%dx%d",
(int)g_pm.windows[row_index].width, (int)g_pm.windows[row_index].height);
c.text(size_cell.x, text_y, buf, theme.text);
draw_text(c, font, col_dirty, text_y, g_pm.windows[index].dirty ? "Y" : "N", Rect dirty_cell = mtk::table_cell_rect(row_rect, cols[4]);
g_pm.windows[index].dirty ? PM_WARNING : PM_DIM_TEXT, FONT_SIZE); c.text(dirty_cell.x, text_y, g_pm.windows[row_index].dirty ? "Y" : "N",
g_pm.windows[row_index].dirty ? PM_WARNING : theme.text_subtle);
} }
static void render_windows(Canvas& c, const mtk::Theme& theme, int fh) {
(void)fh;
mtk::TableLayout layout = window_table_layout();
mtk::TableColumn cols[5];
build_window_columns(cols);
mtk::TableStyle style = mtk::make_table_style(theme);
style.row_selected_bg = colors::MENU_HOVER;
style.row_hover_bg = mtk::mix(theme.window_bg, theme.accent, 12);
mtk::draw_table(c, layout, cols, 5, g_pm.win_count, g_pm.win_scroll,
g_pm.selected_window, hovered_window_row(),
theme, style, draw_window_row, nullptr);
} }
static void render() { static void render() {
TrueTypeFont* font = fonts::system_font; mtk::StandaloneHost host(&g_win);
Canvas c = g_win.canvas(); Canvas c = host.canvas();
c.fill(colors::WINDOW_BG); mtk::Theme theme = pm_theme();
c.fill(theme.window_bg);
int fh = text_height(font, FONT_SIZE); int fh = system_font_height();
render_toolbar(c, font, fh); render_toolbar(c, theme, fh);
render_tabs(c, font, fh); render_tabs(c, theme);
switch (g_pm.active_tab) { switch (g_pm.active_tab) {
case PM_TAB_PROCESSES: case PM_TAB_PROCESSES:
render_processes(c, font, fh); render_processes(c, theme, fh);
break; break;
case PM_TAB_WINDOWS: case PM_TAB_WINDOWS:
render_windows(c, font, fh); render_windows(c, theme, fh);
break; break;
} }
} }
static bool handle_toolbar_click(int mx, int my) { static bool handle_toolbar_click(int mx, int my) {
int btn_h = 26; if (refresh_button_rect().contains(mx, my)) {
int btn_y = (PM_TOOLBAR_H - btn_h) / 2;
Rect refresh_rect = {8, btn_y, 82, btn_h};
Rect kill_rect = {98, btn_y, 110, btn_h};
if (refresh_rect.contains(mx, my)) {
refresh_state(true); refresh_state(true);
return true; return true;
} }
if (kill_button_rect().contains(mx, my)) {
if (kill_rect.contains(mx, my)) {
kill_selected(); kill_selected();
return true; return true;
} }
return false; return false;
} }
static bool handle_tab_click(int mx, int my) { static bool handle_tab_click(int mx, int my) {
if (my < PM_TOOLBAR_H || my >= PM_TOOLBAR_H + PM_TAB_H) int tab = mtk::hit_tab_bar(tab_bar_rect(), PM_TAB_COUNT, mx, my);
return false; if (tab >= 0) {
int tab_w = g_win.width / PM_TAB_COUNT;
int tab = mx / tab_w;
if (tab >= 0 && tab < PM_TAB_COUNT) {
g_pm.active_tab = tab; g_pm.active_tab = tab;
return true; return true;
} }
return false; return false;
} }
static bool handle_process_click(int my) { static bool handle_process_click(int mx, int my) {
if (my < process_list_y()) int index = mtk::table_hit_row(process_table_layout(), g_pm.proc_scroll,
return false; g_pm.proc_count, mx, my);
int row = (my - process_list_y()) / PM_ITEM_H;
int index = g_pm.proc_scroll + row;
if (index >= 0 && index < g_pm.proc_count)
g_pm.selected = index; g_pm.selected = index;
else
g_pm.selected = -1;
return true; return true;
} }
static bool handle_window_click(int my) { static bool handle_window_click(int mx, int my) {
if (my < window_list_y()) int index = mtk::table_hit_row(window_table_layout(), g_pm.win_scroll,
return false; g_pm.win_count, mx, my);
int row = (my - window_list_y()) / PM_ITEM_H;
int index = g_pm.win_scroll + row;
if (index >= 0 && index < g_pm.win_count)
g_pm.selected_window = index; g_pm.selected_window = index;
else
g_pm.selected_window = -1;
return true; return true;
} }
static bool handle_mouse(const Montauk::WinEvent& ev) { static bool handle_mouse(const Montauk::WinEvent& ev) {
bool refresh_hover_before = mouse_in_rect(refresh_button_rect());
bool kill_hover_before = mouse_in_rect(kill_button_rect());
g_pm.mouse_x = ev.mouse.x;
g_pm.mouse_y = ev.mouse.y;
bool redraw = false;
if (refresh_hover_before != mouse_in_rect(refresh_button_rect()) ||
kill_hover_before != mouse_in_rect(kill_button_rect())) {
redraw = true;
}
if (ev.mouse.scroll != 0) { if (ev.mouse.scroll != 0) {
if (g_pm.active_tab == PM_TAB_PROCESSES) { if (g_pm.active_tab == PM_TAB_PROCESSES) {
g_pm.proc_scroll -= ev.mouse.scroll * 3; g_pm.proc_scroll -= ev.mouse.scroll * 3;
@@ -521,21 +550,21 @@ static bool handle_mouse(const Montauk::WinEvent& ev) {
bool left_pressed = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1); bool left_pressed = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1);
if (!left_pressed) if (!left_pressed)
return false; return redraw;
int mx = ev.mouse.x; int mx = ev.mouse.x;
int my = ev.mouse.y; int my = ev.mouse.y;
if (my < PM_TOOLBAR_H) if (toolbar_rect().contains(mx, my))
return handle_toolbar_click(mx, my); return handle_toolbar_click(mx, my) || redraw;
if (my < PM_TOOLBAR_H + PM_TAB_H) if (tab_bar_rect().contains(mx, my))
return handle_tab_click(mx, my); return handle_tab_click(mx, my) || redraw;
if (g_pm.active_tab == PM_TAB_PROCESSES) if (g_pm.active_tab == PM_TAB_PROCESSES)
return handle_process_click(my); return handle_process_click(mx, my) || redraw;
if (g_pm.active_tab == PM_TAB_WINDOWS) if (g_pm.active_tab == PM_TAB_WINDOWS)
return handle_window_click(my); return handle_window_click(mx, my) || redraw;
return false; return redraw;
} }
static bool handle_key(const Montauk::KeyEvent& key) { static bool handle_key(const Montauk::KeyEvent& key) {
@@ -608,6 +637,9 @@ extern "C" void _start() {
g_pm.selected = -1; g_pm.selected = -1;
g_pm.selected_window = -1; g_pm.selected_window = -1;
g_pm.active_tab = PM_TAB_PROCESSES; g_pm.active_tab = PM_TAB_PROCESSES;
g_pm.mouse_x = -1;
g_pm.mouse_y = -1;
refresh_state(true); refresh_state(true);
render(); render();
g_win.present(); g_win.present();