feat: port ProcMgr to new toolkit
This commit is contained in:
@@ -39,6 +39,7 @@ CXXFLAGS := \
|
||||
-msse2 \
|
||||
-mno-red-zone \
|
||||
-mcmodel=small \
|
||||
-MMD -MP \
|
||||
-I $(PROG_INC) \
|
||||
-isystem $(PROG_INC)/libc \
|
||||
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
|
||||
@@ -70,5 +71,7 @@ $(OBJDIR)/%.o: %.cpp Makefile
|
||||
mkdir -p $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
|
||||
+237
-205
@@ -7,10 +7,7 @@
|
||||
#include <montauk/syscall.h>
|
||||
#include <montauk/string.h>
|
||||
#include <montauk/heap.h>
|
||||
#include <gui/gui.hpp>
|
||||
#include <gui/canvas.hpp>
|
||||
#include <gui/standalone.hpp>
|
||||
#include <gui/truetype.hpp>
|
||||
#include <gui/mtk.hpp>
|
||||
|
||||
extern "C" {
|
||||
#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_MAX_PROCS = 256;
|
||||
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_HEADER_BG = Color::from_rgb(0xF0, 0xF0, 0xF0);
|
||||
@@ -59,12 +55,27 @@ struct ProcMgrState {
|
||||
int proc_scroll;
|
||||
int win_scroll;
|
||||
int active_tab;
|
||||
int mouse_x;
|
||||
int mouse_y;
|
||||
uint64_t last_poll_ms;
|
||||
};
|
||||
|
||||
static WsWindow g_win;
|
||||
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) {
|
||||
if (size < 1024ULL) {
|
||||
snprintf(buf, 24, "%llu B", (unsigned long long)size);
|
||||
@@ -120,24 +131,32 @@ static int content_top() {
|
||||
return PM_TOOLBAR_H + PM_TAB_H;
|
||||
}
|
||||
|
||||
static int process_list_y() {
|
||||
return content_top() + PM_HEADER_H;
|
||||
static mtk::TableLayout process_table_layout() {
|
||||
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() {
|
||||
return content_top() + PM_HEADER_H;
|
||||
static mtk::TableLayout window_table_layout() {
|
||||
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() {
|
||||
int avail = g_win.height - process_list_y();
|
||||
if (avail <= 0) return 0;
|
||||
return avail / PM_ITEM_H;
|
||||
return mtk::table_visible_rows(process_table_layout());
|
||||
}
|
||||
|
||||
static int window_visible_rows() {
|
||||
int avail = g_win.height - window_list_y();
|
||||
if (avail <= 0) return 0;
|
||||
return avail / PM_ITEM_H;
|
||||
return mtk::table_visible_rows(window_table_layout());
|
||||
}
|
||||
|
||||
static int live_process_count() {
|
||||
@@ -167,39 +186,18 @@ static int find_window_index_by_id(int id) {
|
||||
}
|
||||
|
||||
static void clamp_scrolls() {
|
||||
int proc_vis = process_visible_rows();
|
||||
int max_proc_scroll = 0;
|
||||
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);
|
||||
mtk::clamp_table_scroll(&g_pm.proc_scroll, process_table_layout(), g_pm.proc_count);
|
||||
mtk::clamp_table_scroll(&g_pm.win_scroll, window_table_layout(), g_pm.win_count);
|
||||
}
|
||||
|
||||
static void ensure_process_selection_visible() {
|
||||
if (g_pm.selected < 0) return;
|
||||
int visible = process_visible_rows();
|
||||
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();
|
||||
mtk::ensure_table_row_visible(&g_pm.proc_scroll, process_table_layout(),
|
||||
g_pm.proc_count, g_pm.selected);
|
||||
}
|
||||
|
||||
static void ensure_window_selection_visible() {
|
||||
if (g_pm.selected_window < 0) return;
|
||||
int visible = window_visible_rows();
|
||||
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();
|
||||
mtk::ensure_table_row_visible(&g_pm.win_scroll, window_table_layout(),
|
||||
g_pm.win_count, g_pm.selected_window);
|
||||
}
|
||||
|
||||
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);
|
||||
if (g_pm.proc_count < 0) g_pm.proc_count = 0;
|
||||
|
||||
g_pm.selected = find_process_index_by_pid(prev_pid);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
static void draw_text_fit(Canvas& c, TrueTypeFont* font, int x, int y,
|
||||
const char* text, int max_w, Color color, int size) {
|
||||
static Rect toolbar_rect() {
|
||||
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_width(font, text, size) <= max_w) {
|
||||
draw_text(c, font, x, y, text, color, size);
|
||||
if (text_width(text) <= max_w) {
|
||||
c.text(x, y, text, color);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* ellipsis = "...";
|
||||
int ell_w = text_width(font, ellipsis, size);
|
||||
int ell_w = text_width(ellipsis);
|
||||
if (ell_w >= max_w) return;
|
||||
|
||||
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) {
|
||||
buf[out] = text[out];
|
||||
buf[out + 1] = '\0';
|
||||
if (text_width(font, buf, size) + ell_w > max_w)
|
||||
if (text_width(buf) + ell_w > max_w)
|
||||
break;
|
||||
out++;
|
||||
}
|
||||
@@ -283,21 +342,20 @@ static void draw_text_fit(Canvas& c, TrueTypeFont* font, int x, int y,
|
||||
buf[out + 1] = '.';
|
||||
buf[out + 2] = '.';
|
||||
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) {
|
||||
c.fill_rect(0, 0, g_win.width, PM_TOOLBAR_H, PM_TOOLBAR_BG);
|
||||
c.hline(0, PM_TOOLBAR_H - 1, g_win.width, PM_BORDER);
|
||||
static void render_toolbar(Canvas& c, const mtk::Theme& theme, int fh) {
|
||||
Rect bar = toolbar_rect();
|
||||
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;
|
||||
int btn_y = (PM_TOOLBAR_H - btn_h) / 2;
|
||||
draw_button(c, font, 8, btn_y, 82, btn_h, "Refresh",
|
||||
Color::from_rgb(0xE3, 0xE8, 0xEF), colors::TEXT_COLOR, 4, FONT_SIZE);
|
||||
|
||||
Color kill_bg = can_kill_selected() ? PM_DANGER : Color::from_rgb(0xAA, 0xAA, 0xAA);
|
||||
draw_button(c, font, 98, btn_y, 110, btn_h, "End Process",
|
||||
kill_bg, colors::WHITE, 4, FONT_SIZE);
|
||||
Rect refresh_rect = refresh_button_rect();
|
||||
Rect kill_rect = kill_button_rect();
|
||||
mtk::draw_button(c, refresh_rect, "Refresh", mtk::BUTTON_TONAL,
|
||||
mtk::widget_state(false, mouse_in_rect(refresh_rect)), theme);
|
||||
mtk::draw_button(c, kill_rect, "End Process", mtk::BUTTON_DANGER,
|
||||
mtk::widget_state(false, mouse_in_rect(kill_rect), can_kill_selected()), theme);
|
||||
|
||||
char status[96];
|
||||
if (g_pm.active_tab == PM_TAB_PROCESSES) {
|
||||
@@ -306,206 +364,177 @@ static void render_toolbar(Canvas& c, TrueTypeFont* font, int fh) {
|
||||
} else {
|
||||
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,
|
||||
status, colors::TEXT_COLOR, FONT_SIZE);
|
||||
|
||||
int status_w = text_width(status);
|
||||
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) {
|
||||
int y = PM_TOOLBAR_H;
|
||||
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_tabs(Canvas& c, const mtk::Theme& theme) {
|
||||
mtk::draw_tab_bar(c, tab_bar_rect(), g_tab_labels, PM_TAB_COUNT, g_pm.active_tab, theme);
|
||||
}
|
||||
|
||||
static void render_processes(Canvas& c, TrueTypeFont* font, int fh) {
|
||||
int header_y = content_top();
|
||||
c.fill_rect(0, header_y, g_win.width, PM_HEADER_H, PM_HEADER_BG);
|
||||
c.hline(0, header_y + PM_HEADER_H - 1, g_win.width, PM_BORDER);
|
||||
static void draw_process_row(Canvas& c, void* userdata, int row_index,
|
||||
const Rect& row_rect, int text_y,
|
||||
const mtk::TableColumn* cols, int col_count,
|
||||
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];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", (int)g_pm.procs[index].pid);
|
||||
draw_text(c, font, col_pid, text_y, buf, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect pid_cell = mtk::table_cell_rect(row_rect, cols[0]);
|
||||
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);
|
||||
draw_text(c, font, col_ppid, text_y, buf, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect ppid_cell = mtk::table_cell_rect(row_rect, cols[1]);
|
||||
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,
|
||||
col_heap - col_name - 10, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect name_cell = mtk::table_cell_rect(row_rect, cols[2]);
|
||||
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);
|
||||
draw_text(c, font, col_heap, text_y, buf, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect heap_cell = mtk::table_cell_rect(row_rect, cols[3]);
|
||||
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;
|
||||
const char* state = proc_state_label(g_pm.procs[index].state, &state_color);
|
||||
draw_text(c, font, col_state, text_y, state, state_color, FONT_SIZE);
|
||||
}
|
||||
const char* state = proc_state_label(g_pm.procs[row_index].state, &state_color);
|
||||
c.text(state_cell.x, text_y, state, state_color);
|
||||
}
|
||||
|
||||
static void render_windows(Canvas& c, TrueTypeFont* font, int fh) {
|
||||
int header_y = content_top();
|
||||
c.fill_rect(0, header_y, g_win.width, PM_HEADER_H, PM_HEADER_BG);
|
||||
c.hline(0, header_y + PM_HEADER_H - 1, g_win.width, PM_BORDER);
|
||||
static void render_processes(Canvas& c, const mtk::Theme& theme, int fh) {
|
||||
(void)fh;
|
||||
mtk::TableLayout layout = process_table_layout();
|
||||
mtk::TableColumn cols[5];
|
||||
build_process_columns(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;
|
||||
int header_text_y = header_y + (PM_HEADER_H - fh) / 2;
|
||||
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);
|
||||
|
||||
draw_text(c, font, col_id, header_text_y, "ID", PM_DIM_TEXT, FONT_SIZE);
|
||||
draw_text(c, font, col_pid, header_text_y, "PID", PM_DIM_TEXT, FONT_SIZE);
|
||||
draw_text(c, font, col_title, header_text_y, "Title", PM_DIM_TEXT, FONT_SIZE);
|
||||
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);
|
||||
mtk::draw_table(c, layout, cols, 5, g_pm.proc_count, g_pm.proc_scroll,
|
||||
g_pm.selected, hovered_process_row(),
|
||||
theme, style, draw_process_row, nullptr);
|
||||
}
|
||||
|
||||
int list_y = window_list_y();
|
||||
int visible = window_visible_rows();
|
||||
for (int row = 0; row < visible; row++) {
|
||||
int index = g_pm.win_scroll + row;
|
||||
if (index >= g_pm.win_count) break;
|
||||
static void draw_window_row(Canvas& c, void* userdata, int row_index,
|
||||
const Rect& row_rect, int text_y,
|
||||
const mtk::TableColumn* cols, int col_count,
|
||||
const mtk::Theme& theme, const mtk::TableStyle& style) {
|
||||
(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];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", (int)g_pm.windows[index].id);
|
||||
draw_text(c, font, col_id, text_y, buf, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect id_cell = mtk::table_cell_rect(row_rect, cols[0]);
|
||||
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);
|
||||
draw_text(c, font, col_pid, text_y, buf, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect pid_cell = mtk::table_cell_rect(row_rect, cols[1]);
|
||||
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,
|
||||
col_size - col_title - 10, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect title_cell = mtk::table_cell_rect(row_rect, cols[2]);
|
||||
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);
|
||||
draw_text(c, font, col_size, text_y, buf, colors::TEXT_COLOR, FONT_SIZE);
|
||||
Rect size_cell = mtk::table_cell_rect(row_rect, cols[3]);
|
||||
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",
|
||||
g_pm.windows[index].dirty ? PM_WARNING : PM_DIM_TEXT, FONT_SIZE);
|
||||
Rect dirty_cell = mtk::table_cell_rect(row_rect, cols[4]);
|
||||
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() {
|
||||
TrueTypeFont* font = fonts::system_font;
|
||||
Canvas c = g_win.canvas();
|
||||
c.fill(colors::WINDOW_BG);
|
||||
mtk::StandaloneHost host(&g_win);
|
||||
Canvas c = host.canvas();
|
||||
mtk::Theme theme = pm_theme();
|
||||
c.fill(theme.window_bg);
|
||||
|
||||
int fh = text_height(font, FONT_SIZE);
|
||||
render_toolbar(c, font, fh);
|
||||
render_tabs(c, font, fh);
|
||||
int fh = system_font_height();
|
||||
render_toolbar(c, theme, fh);
|
||||
render_tabs(c, theme);
|
||||
|
||||
switch (g_pm.active_tab) {
|
||||
case PM_TAB_PROCESSES:
|
||||
render_processes(c, font, fh);
|
||||
render_processes(c, theme, fh);
|
||||
break;
|
||||
case PM_TAB_WINDOWS:
|
||||
render_windows(c, font, fh);
|
||||
render_windows(c, theme, fh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool handle_toolbar_click(int mx, int my) {
|
||||
int btn_h = 26;
|
||||
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)) {
|
||||
if (refresh_button_rect().contains(mx, my)) {
|
||||
refresh_state(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (kill_rect.contains(mx, my)) {
|
||||
if (kill_button_rect().contains(mx, my)) {
|
||||
kill_selected();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_tab_click(int mx, int my) {
|
||||
if (my < PM_TOOLBAR_H || my >= PM_TOOLBAR_H + PM_TAB_H)
|
||||
return false;
|
||||
|
||||
int tab_w = g_win.width / PM_TAB_COUNT;
|
||||
int tab = mx / tab_w;
|
||||
if (tab >= 0 && tab < PM_TAB_COUNT) {
|
||||
int tab = mtk::hit_tab_bar(tab_bar_rect(), PM_TAB_COUNT, mx, my);
|
||||
if (tab >= 0) {
|
||||
g_pm.active_tab = tab;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_process_click(int my) {
|
||||
if (my < process_list_y())
|
||||
return false;
|
||||
|
||||
int row = (my - process_list_y()) / PM_ITEM_H;
|
||||
int index = g_pm.proc_scroll + row;
|
||||
if (index >= 0 && index < g_pm.proc_count)
|
||||
static bool handle_process_click(int mx, int my) {
|
||||
int index = mtk::table_hit_row(process_table_layout(), g_pm.proc_scroll,
|
||||
g_pm.proc_count, mx, my);
|
||||
g_pm.selected = index;
|
||||
else
|
||||
g_pm.selected = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_window_click(int my) {
|
||||
if (my < window_list_y())
|
||||
return false;
|
||||
|
||||
int row = (my - window_list_y()) / PM_ITEM_H;
|
||||
int index = g_pm.win_scroll + row;
|
||||
if (index >= 0 && index < g_pm.win_count)
|
||||
static bool handle_window_click(int mx, int my) {
|
||||
int index = mtk::table_hit_row(window_table_layout(), g_pm.win_scroll,
|
||||
g_pm.win_count, mx, my);
|
||||
g_pm.selected_window = index;
|
||||
else
|
||||
g_pm.selected_window = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
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 (g_pm.active_tab == PM_TAB_PROCESSES) {
|
||||
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);
|
||||
if (!left_pressed)
|
||||
return false;
|
||||
return redraw;
|
||||
|
||||
int mx = ev.mouse.x;
|
||||
int my = ev.mouse.y;
|
||||
|
||||
if (my < PM_TOOLBAR_H)
|
||||
return handle_toolbar_click(mx, my);
|
||||
if (my < PM_TOOLBAR_H + PM_TAB_H)
|
||||
return handle_tab_click(mx, my);
|
||||
if (toolbar_rect().contains(mx, my))
|
||||
return handle_toolbar_click(mx, my) || redraw;
|
||||
if (tab_bar_rect().contains(mx, my))
|
||||
return handle_tab_click(mx, my) || redraw;
|
||||
|
||||
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)
|
||||
return handle_window_click(my);
|
||||
return false;
|
||||
return handle_window_click(mx, my) || redraw;
|
||||
return redraw;
|
||||
}
|
||||
|
||||
static bool handle_key(const Montauk::KeyEvent& key) {
|
||||
@@ -608,6 +637,9 @@ extern "C" void _start() {
|
||||
g_pm.selected = -1;
|
||||
g_pm.selected_window = -1;
|
||||
g_pm.active_tab = PM_TAB_PROCESSES;
|
||||
g_pm.mouse_x = -1;
|
||||
g_pm.mouse_y = -1;
|
||||
|
||||
refresh_state(true);
|
||||
render();
|
||||
g_win.present();
|
||||
|
||||
Reference in New Issue
Block a user