From 043327424457841edd52dc889f948b8355a7118a Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Fri, 10 Apr 2026 22:55:51 +0200 Subject: [PATCH] feat: port ProcMgr to new toolkit --- programs/src/procmgr/Makefile | 3 + programs/src/procmgr/main.cpp | 470 ++++++++++++++++++---------------- 2 files changed, 254 insertions(+), 219 deletions(-) diff --git a/programs/src/procmgr/Makefile b/programs/src/procmgr/Makefile index f08f4e8..f0db480 100644 --- a/programs/src/procmgr/Makefile +++ b/programs/src/procmgr/Makefile @@ -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) diff --git a/programs/src/procmgr/main.cpp b/programs/src/procmgr/main.cpp index 67cb91c..e1527cc 100644 --- a/programs/src/procmgr/main.cpp +++ b/programs/src/procmgr/main.cpp @@ -7,10 +7,7 @@ #include #include #include -#include -#include -#include -#include +#include extern "C" { #include @@ -18,16 +15,15 @@ extern "C" { using namespace gui; -static constexpr int INIT_W = 620; -static constexpr int INIT_H = 420; -static constexpr int PM_TOOLBAR_H = 36; -static constexpr int PM_TAB_H = 32; -static constexpr int PM_HEADER_H = 24; -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 int INIT_W = 620; +static constexpr int INIT_H = 420; +static constexpr int PM_TOOLBAR_H = 36; +static constexpr int PM_TAB_H = 32; +static constexpr int PM_HEADER_H = 24; +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 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; + char buf[32]; - 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); + 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); - 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; + 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); - 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); + 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); - int text_y = row_y + (PM_ITEM_H - fh) / 2; - char buf[32]; + 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); - 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); - - 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); - - draw_text_fit(c, font, col_name, text_y, g_pm.procs[index].name, - col_heap - col_name - 10, colors::TEXT_COLOR, FONT_SIZE); - - format_size(buf, g_pm.procs[index].heapUsed); - draw_text(c, font, col_heap, text_y, buf, colors::TEXT_COLOR, FONT_SIZE); - - 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); - } + Rect state_cell = mtk::table_cell_rect(row_rect, cols[4]); + Color state_color; + 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); + char buf[64]; - int text_y = row_y + (PM_ITEM_H - fh) / 2; - char buf[64]; + 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].id); - draw_text(c, font, col_id, 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); - 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 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); - 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 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); - 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 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); +} - 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); - } +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) - g_pm.selected = index; - else - g_pm.selected = -1; +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; 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) - g_pm.selected_window = index; - else - g_pm.selected_window = -1; +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; 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();