Blame SOURCES/0012-irqbalance-ui-support-scroll-under-tui-mode-of-irqba.patch

8dca8a
From db7dc03388a20ba2d873a81c3e14b933e2b09551 Mon Sep 17 00:00:00 2001
8dca8a
From: Liu Chao <liuchao173@huawei.com>
8dca8a
Date: Mon, 4 Jul 2022 16:25:14 +0800
8dca8a
Subject: [PATCH 12/14] irqbalance-ui: support scroll under tui mode of
8dca8a
 irqbalance-ui
8dca8a
8dca8a
support using Up, Down, PageUp, PageDown to scroll in view mode
8dca8a
support using Up and Down in edit mode
8dca8a
8dca8a
Signed-off-by: Liu Chao <liuchao173@huawei.com>
8dca8a
---
8dca8a
 ui/helpers.c       |   2 +
8dca8a
 ui/irqbalance-ui.c | 138 ++++++++++++++++++++++++---------
8dca8a
 ui/irqbalance-ui.h |   2 +
8dca8a
 ui/ui.c            | 187 ++++++++++++++++++++++++++++++++++++---------
8dca8a
 ui/ui.h            |   3 +
8dca8a
 5 files changed, 262 insertions(+), 70 deletions(-)
8dca8a
8dca8a
diff --git a/ui/helpers.c b/ui/helpers.c
8dca8a
index 5d71275..0e9f76c 100644
8dca8a
--- a/ui/helpers.c
8dca8a
+++ b/ui/helpers.c
8dca8a
@@ -89,6 +89,7 @@ gpointer copy_cpu_ban(gconstpointer src, gpointer data __attribute__((unused)))
8dca8a
 	cpu_ban_t *new = malloc(sizeof(cpu_ban_t));
8dca8a
 	new->number = old->number;
8dca8a
 	new->is_banned = old->is_banned;
8dca8a
+	new->is_changed = 0;
8dca8a
 	return new;
8dca8a
 }
8dca8a
 
8dca8a
@@ -100,6 +101,7 @@ gpointer copy_irq(gconstpointer src, gpointer data __attribute__((unused)))
8dca8a
 	new->load = old->load;
8dca8a
 	new->diff = old->diff;
8dca8a
 	new->is_banned = old->is_banned;
8dca8a
+	new->is_changed = 0;
8dca8a
 	new->class = old->class;
8dca8a
 	new->assigned_to = g_list_copy(old->assigned_to);
8dca8a
 	return new;
8dca8a
diff --git a/ui/irqbalance-ui.c b/ui/irqbalance-ui.c
8dca8a
index 89ed94a..47b6c88 100644
8dca8a
--- a/ui/irqbalance-ui.c
8dca8a
+++ b/ui/irqbalance-ui.c
8dca8a
@@ -371,48 +371,116 @@ gboolean rescan_tree(gpointer data __attribute__((unused)))
8dca8a
 	free(irqbalance_data);
8dca8a
 	return TRUE;
8dca8a
 }
8dca8a
-
8dca8a
-gboolean key_loop(gpointer data __attribute__((unused)))
8dca8a
-{
8dca8a
-	int c = getch();
8dca8a
-	switch(c) {
8dca8a
-	case 'q':
8dca8a
-		close_window(0);
8dca8a
-		break;
8dca8a
-	case KEY_F(3):
8dca8a
-		if (state == STATE_SETTINGS || state == STATE_SETUP_IRQS) {
8dca8a
-			state = STATE_TREE;
8dca8a
-			display_tree();
8dca8a
-		}
8dca8a
+void scroll_window() {
8dca8a
+	switch(state) {
8dca8a
+	case STATE_TREE:
8dca8a
+		display_tree();
8dca8a
 		break;
8dca8a
-	case KEY_F(4):
8dca8a
-		if (state == STATE_TREE || state == STATE_SETUP_IRQS) {
8dca8a
-			state = STATE_SETTINGS;
8dca8a
-			settings();
8dca8a
-		}
8dca8a
+	case STATE_SETTINGS:
8dca8a
 		settings();
8dca8a
 		break;
8dca8a
-	case KEY_F(5):
8dca8a
-		if (state == STATE_TREE || state == STATE_SETTINGS) {
8dca8a
-			state = STATE_SETUP_IRQS;
8dca8a
-			setup_irqs();
8dca8a
-		}
8dca8a
-		break;
8dca8a
-	case 'c':
8dca8a
-		if (state == STATE_SETTINGS)
8dca8a
-			handle_cpu_banning();
8dca8a
-		break;
8dca8a
-	case 'i':
8dca8a
-		if (state == STATE_SETUP_IRQS)
8dca8a
-			handle_irq_banning();
8dca8a
-		break;
8dca8a
-	case 's':
8dca8a
-		if (state == STATE_SETTINGS)
8dca8a
-			handle_sleep_setting();
8dca8a
+	case STATE_SETUP_IRQS:
8dca8a
+		setup_irqs();
8dca8a
 		break;
8dca8a
 	default:
8dca8a
 		break;
8dca8a
 	}
8dca8a
+}
8dca8a
+
8dca8a
+gboolean key_loop(gpointer data __attribute__((unused)))
8dca8a
+{
8dca8a
+	while(1) {
8dca8a
+		int c = getch();
8dca8a
+		switch(c) {
8dca8a
+		case 'q':
8dca8a
+			close_window(0);
8dca8a
+			break;
8dca8a
+		case KEY_UP:
8dca8a
+			if (offset > 0) {
8dca8a
+				offset--;
8dca8a
+				scroll_window();
8dca8a
+			}
8dca8a
+			break;
8dca8a
+		case KEY_DOWN:
8dca8a
+			if (offset < max_offset) {
8dca8a
+				offset++;
8dca8a
+				scroll_window();
8dca8a
+			}
8dca8a
+			break;
8dca8a
+		case KEY_NPAGE:
8dca8a
+			switch (state) {
8dca8a
+			case STATE_TREE:
8dca8a
+				offset += LINES - 5;
8dca8a
+				break;
8dca8a
+			case STATE_SETTINGS:
8dca8a
+				offset += LINES - 8;
8dca8a
+				break;
8dca8a
+			case STATE_SETUP_IRQS:
8dca8a
+				offset += LINES - 6;
8dca8a
+				break;
8dca8a
+			default:
8dca8a
+				break;
8dca8a
+			}
8dca8a
+			if (offset > max_offset)
8dca8a
+				offset = max_offset;
8dca8a
+			scroll_window();
8dca8a
+			break;
8dca8a
+		case KEY_PPAGE:
8dca8a
+			switch (state) {
8dca8a
+			case STATE_TREE:
8dca8a
+				offset -= LINES - 5;
8dca8a
+				break;
8dca8a
+			case STATE_SETTINGS:
8dca8a
+				offset -= LINES - 8;
8dca8a
+				break;
8dca8a
+			case STATE_SETUP_IRQS:
8dca8a
+				offset -= LINES - 6;
8dca8a
+				break;
8dca8a
+			default:
8dca8a
+				break;
8dca8a
+			}
8dca8a
+			if (offset < 0)
8dca8a
+				offset = 0;
8dca8a
+			scroll_window();
8dca8a
+			break;
8dca8a
+		case KEY_F(3):
8dca8a
+			if (state == STATE_SETTINGS || state == STATE_SETUP_IRQS) {
8dca8a
+				state = STATE_TREE;
8dca8a
+				offset = 0;
8dca8a
+				display_tree();
8dca8a
+			}
8dca8a
+			break;
8dca8a
+		case KEY_F(4):
8dca8a
+			if (state == STATE_TREE || state == STATE_SETUP_IRQS) {
8dca8a
+				state = STATE_SETTINGS;
8dca8a
+				offset = 0;
8dca8a
+				settings();
8dca8a
+			}
8dca8a
+			settings();
8dca8a
+			break;
8dca8a
+		case KEY_F(5):
8dca8a
+			if (state == STATE_TREE || state == STATE_SETTINGS) {
8dca8a
+				state = STATE_SETUP_IRQS;
8dca8a
+				offset = 0;
8dca8a
+				setup_irqs();
8dca8a
+			}
8dca8a
+			break;
8dca8a
+		case 'c':
8dca8a
+			if (state == STATE_SETTINGS)
8dca8a
+				handle_cpu_banning();
8dca8a
+			break;
8dca8a
+		case 'i':
8dca8a
+			if (state == STATE_SETUP_IRQS)
8dca8a
+				handle_irq_banning();
8dca8a
+			break;
8dca8a
+		case 's':
8dca8a
+			if (state == STATE_SETTINGS)
8dca8a
+				handle_sleep_setting();
8dca8a
+			break;
8dca8a
+		default:
8dca8a
+			break;
8dca8a
+		}
8dca8a
+	}
8dca8a
 	return TRUE;
8dca8a
 }
8dca8a
 
8dca8a
diff --git a/ui/irqbalance-ui.h b/ui/irqbalance-ui.h
8dca8a
index fba7e7c..dc24083 100644
8dca8a
--- a/ui/irqbalance-ui.h
8dca8a
+++ b/ui/irqbalance-ui.h
8dca8a
@@ -41,6 +41,7 @@ typedef struct irq {
8dca8a
 	uint64_t load;
8dca8a
 	uint64_t diff;
8dca8a
 	char is_banned;
8dca8a
+	char is_changed;
8dca8a
 	GList *assigned_to;
8dca8a
 	int class;
8dca8a
 } irq_t;
8dca8a
@@ -60,6 +61,7 @@ typedef struct cpu_node {
8dca8a
 typedef struct cpu_ban {
8dca8a
 	int number;
8dca8a
 	char is_banned;
8dca8a
+	char is_changed;
8dca8a
 } cpu_ban_t;
8dca8a
 
8dca8a
 typedef struct setup {
8dca8a
diff --git a/ui/ui.c b/ui/ui.c
8dca8a
index 6b1c689..2dad442 100644
8dca8a
--- a/ui/ui.c
8dca8a
+++ b/ui/ui.c
8dca8a
@@ -3,6 +3,8 @@
8dca8a
 #include <string.h>
8dca8a
 #include "ui.h"
8dca8a
 
8dca8a
+int offset;
8dca8a
+int max_offset;
8dca8a
 
8dca8a
 GList *all_cpus = NULL;
8dca8a
 GList *all_irqs = NULL;
8dca8a
@@ -134,32 +136,54 @@ void get_banned_cpu(int *cpu, void *data __attribute__((unused)))
8dca8a
 	all_cpus = g_list_append(all_cpus, new);
8dca8a
 }
8dca8a
 
8dca8a
-void print_cpu_line(cpu_ban_t *cpu, void *data)
8dca8a
+void print_tmp_cpu_line(cpu_ban_t *cpu, void *data __attribute__((unused)))
8dca8a
 {
8dca8a
-	int *line_offset = data;
8dca8a
-	if(cpu->is_banned) {
8dca8a
-		attrset(COLOR_PAIR(10));
8dca8a
-	} else {
8dca8a
-		attrset(COLOR_PAIR(9));
8dca8a
+	int line = max_offset - offset + 6;
8dca8a
+	if (max_offset >= offset && line < LINES - 3) {
8dca8a
+		if (cpu->is_changed)
8dca8a
+			attrset(COLOR_PAIR(3));
8dca8a
+		else if(cpu->is_banned)
8dca8a
+			attrset(COLOR_PAIR(10));
8dca8a
+		else
8dca8a
+			attrset(COLOR_PAIR(9));
8dca8a
+		mvprintw(line, 3, "CPU %d     ", cpu->number);
8dca8a
+		mvprintw(line, 19, "%s", cpu->is_banned ?
8dca8a
+				"YES	" :
8dca8a
+				"NO	 ");
8dca8a
 	}
8dca8a
-	mvprintw(*line_offset, 3, "CPU %d", cpu->number);
8dca8a
-	mvprintw(*line_offset, 19, "%s", cpu->is_banned ?
8dca8a
-			"YES	" :
8dca8a
-			"NO	 ");
8dca8a
-	(*line_offset)++;
8dca8a
+	max_offset++;
8dca8a
+}
8dca8a
+
8dca8a
+void print_cpu_line(cpu_ban_t *cpu, void *data __attribute__((unused)))
8dca8a
+{
8dca8a
+	int line = max_offset - offset + 6;
8dca8a
+	if (max_offset >= offset && line < LINES - 2) {
8dca8a
+		if(cpu->is_banned)
8dca8a
+			attrset(COLOR_PAIR(10));
8dca8a
+		else
8dca8a
+			attrset(COLOR_PAIR(9));
8dca8a
+		mvprintw(line, 3, "CPU %d     ", cpu->number);
8dca8a
+		mvprintw(line, 19, "%s", cpu->is_banned ?
8dca8a
+				"YES	" :
8dca8a
+				"NO	 ");
8dca8a
+	}
8dca8a
+	max_offset++;
8dca8a
 }
8dca8a
 
8dca8a
 void print_all_cpus()
8dca8a
 {
8dca8a
+	max_offset = 0;
8dca8a
 	if(all_cpus == NULL) {
8dca8a
 		for_each_node(tree, get_cpu, NULL);
8dca8a
 		for_each_int(setup.banned_cpus, get_banned_cpu, NULL);
8dca8a
 		all_cpus = g_list_sort(all_cpus, sort_all_cpus);
8dca8a
 	}
8dca8a
-	int line = 6;
8dca8a
 	attrset(COLOR_PAIR(2));
8dca8a
 	mvprintw(4, 3, "NUMBER          IS BANNED");
8dca8a
-	for_each_cpu(all_cpus, print_cpu_line, &line);
8dca8a
+	for_each_cpu(all_cpus, print_cpu_line, NULL);
8dca8a
+	max_offset -= LINES - 8;
8dca8a
+	if (max_offset < 0)
8dca8a
+		max_offset = 0;
8dca8a
 }
8dca8a
 
8dca8a
 void add_banned_cpu(int *banned_cpu, void *data)
8dca8a
@@ -195,6 +219,7 @@ int toggle_cpu(GList *cpu_list, int cpu_number)
8dca8a
 	} else {
8dca8a
 		((cpu_ban_t *)(entry->data))->is_banned = 1;
8dca8a
 	}
8dca8a
+	((cpu_ban_t *)(entry->data))->is_changed = 1;
8dca8a
 	return ((cpu_ban_t *)(entry->data))->is_banned;
8dca8a
 }
8dca8a
 
8dca8a
@@ -239,18 +264,37 @@ void handle_cpu_banning()
8dca8a
 			if(position > 6) {
8dca8a
 				position--;
8dca8a
 				move(position, 19);
8dca8a
+			} else if (offset > 0) {
8dca8a
+				offset--;
8dca8a
+				max_offset = 0;
8dca8a
+				for_each_cpu(tmp, print_tmp_cpu_line, NULL);
8dca8a
+				max_offset -= LINES - 9;
8dca8a
+				if (max_offset < 0)
8dca8a
+					max_offset = 0;
8dca8a
+				move(position, 19);
8dca8a
 			}
8dca8a
 			break;
8dca8a
 		case KEY_DOWN:
8dca8a
-			if(position <= g_list_length(all_cpus) + 4) {
8dca8a
-				position++;
8dca8a
+			if(position < (size_t)(LINES - 4)) {
8dca8a
+				if (position <= g_list_length(all_cpus) + 4 - offset) {
8dca8a
+					position++;
8dca8a
+					move(position, 19);
8dca8a
+				}
8dca8a
+			} else if (offset < max_offset) {
8dca8a
+				offset++;
8dca8a
+				max_offset = 0;
8dca8a
+				for_each_cpu(tmp, print_tmp_cpu_line, NULL);
8dca8a
+				max_offset -= LINES - 9;
8dca8a
+				if (max_offset < 0)
8dca8a
+					max_offset = 0;
8dca8a
 				move(position, 19);
8dca8a
 			}
8dca8a
 			break;
8dca8a
 		case '\n':
8dca8a
 		case '\r': {
8dca8a
 			attrset(COLOR_PAIR(3));
8dca8a
-			int banned = toggle_cpu(tmp, position - 6);
8dca8a
+			int banned = toggle_cpu(tmp, position + offset - 6);
8dca8a
+			mvprintw(position, 3, "CPU %d     ", position + offset - 6);
8dca8a
 			if(banned) {
8dca8a
 				mvprintw(position, 19, "YES");
8dca8a
 			} else {
8dca8a
@@ -263,8 +307,7 @@ void handle_cpu_banning()
8dca8a
 		case 27:
8dca8a
 			processing = 0;
8dca8a
 			curs_set(0);
8dca8a
-			/* Forget the changes */
8dca8a
-			tmp = g_list_copy_deep(all_cpus, copy_cpu_ban, NULL);
8dca8a
+			g_list_free(tmp);
8dca8a
 			print_all_cpus();
8dca8a
 			attrset(COLOR_PAIR(0));
8dca8a
 			mvprintw(LINES - 3, 1, "			\
8dca8a
@@ -278,6 +321,7 @@ void handle_cpu_banning()
8dca8a
 			break;
8dca8a
 		case 's':
8dca8a
 			processing = 0;
8dca8a
+			g_list_free(all_cpus);
8dca8a
 			all_cpus = tmp;
8dca8a
 			curs_set(0);
8dca8a
 			print_all_cpus();
8dca8a
@@ -324,9 +368,12 @@ void print_assigned_objects_string(irq_t *irq, int *line_offset)
8dca8a
 	mvprintw(*line_offset, 68, "%s", assigned_to);
8dca8a
 }
8dca8a
 
8dca8a
-void print_irq_line(irq_t *irq, void *data)
8dca8a
+void print_tmp_irq_line(irq_t *irq, void *data __attribute__((unused)))
8dca8a
 {
8dca8a
-	int *line_offset = data;
8dca8a
+	int line = max_offset - offset + 4;
8dca8a
+	max_offset++;
8dca8a
+	if (line < 4 || line >= LINES - 3)
8dca8a
+		return;
8dca8a
 	switch(irq->class) {
8dca8a
 	case(IRQ_OTHER):
8dca8a
 		attrset(COLOR_PAIR(1));
8dca8a
@@ -352,23 +399,62 @@ void print_irq_line(irq_t *irq, void *data)
8dca8a
 		attrset(COLOR_PAIR(0));
8dca8a
 		break;
8dca8a
 	}
8dca8a
-	mvprintw(*line_offset, 3, "IRQ %d", irq->vector);
8dca8a
-	mvprintw(*line_offset, 19, "%s", irq->is_banned ? "YES" : "NO ");
8dca8a
-	mvprintw(*line_offset, 36, "%s",
8dca8a
+	mvprintw(line, 3, "IRQ %d      ", irq->vector);
8dca8a
+	mvprintw(line, 19, "%s", irq->is_banned ? "YES" : "NO ");
8dca8a
+	mvprintw(line, 36, "%s               ",
8dca8a
 			 irq->class < 0 ? "Unknown" : IRQ_CLASS_TO_STR[irq->class]);
8dca8a
-	print_assigned_objects_string(irq, line_offset);
8dca8a
-	(*line_offset)++;
8dca8a
+	print_assigned_objects_string(irq, &line);
8dca8a
+}
8dca8a
 
8dca8a
+void print_irq_line(irq_t *irq, void *data __attribute__((unused)))
8dca8a
+{
8dca8a
+	int line = max_offset - offset + 4;
8dca8a
+	max_offset++;
8dca8a
+	if (line < 4 || line >= LINES - 2)
8dca8a
+		return;
8dca8a
+	switch(irq->class) {
8dca8a
+	case(IRQ_OTHER):
8dca8a
+		attrset(COLOR_PAIR(1));
8dca8a
+		break;
8dca8a
+	case(IRQ_LEGACY):
8dca8a
+		attrset(COLOR_PAIR(2));
8dca8a
+		break;
8dca8a
+	case(IRQ_SCSI):
8dca8a
+		attrset(COLOR_PAIR(3));
8dca8a
+		break;
8dca8a
+	case(IRQ_VIDEO):
8dca8a
+		attrset(COLOR_PAIR(8));
8dca8a
+		break;
8dca8a
+	case(IRQ_ETH):
8dca8a
+	case(IRQ_GBETH):
8dca8a
+	case(IRQ_10GBETH):
8dca8a
+		attrset(COLOR_PAIR(9));
8dca8a
+		break;
8dca8a
+	case(IRQ_VIRT_EVENT):
8dca8a
+		attrset(COLOR_PAIR(10));
8dca8a
+		break;
8dca8a
+	default:
8dca8a
+		attrset(COLOR_PAIR(0));
8dca8a
+		break;
8dca8a
+	}
8dca8a
+	mvprintw(line, 3, "IRQ %d", irq->vector);
8dca8a
+	mvprintw(line, 19, "%s", irq->is_banned ? "YES" : "NO ");
8dca8a
+	mvprintw(line, 36, "%s               ",
8dca8a
+			 irq->class < 0 ? "Unknown" : IRQ_CLASS_TO_STR[irq->class]);
8dca8a
+	print_assigned_objects_string(irq, &line);
8dca8a
 }
8dca8a
 
8dca8a
 void print_all_irqs()
8dca8a
 {
8dca8a
-	int line = 4;
8dca8a
+	max_offset = 0;
8dca8a
 	attrset(COLOR_PAIR(0));
8dca8a
 	mvprintw(2, 3,
8dca8a
 			"NUMBER          IS BANNED        CLASS      \
8dca8a
 			    ASSIGNED TO CPUS");
8dca8a
-	for_each_irq(all_irqs, print_irq_line, &line);
8dca8a
+	for_each_irq(all_irqs, print_irq_line, NULL);
8dca8a
+	max_offset -= LINES - 6;
8dca8a
+	if (max_offset < 0)
8dca8a
+		max_offset = 0;
8dca8a
 }
8dca8a
 
8dca8a
 int toggle_irq(GList *irq_list, int position)
8dca8a
@@ -384,6 +470,7 @@ int toggle_irq(GList *irq_list, int position)
8dca8a
 	} else {
8dca8a
 		((irq_t *)(entry->data))->is_banned = 1;
8dca8a
 	}
8dca8a
+	((irq_t *)(entry->data))->is_changed = 1;
8dca8a
 	return ((irq_t *)(entry->data))->is_banned;
8dca8a
 }
8dca8a
 
8dca8a
@@ -431,18 +518,36 @@ void handle_irq_banning()
8dca8a
 			if(position > 4) {
8dca8a
 				position--;
8dca8a
 				move(position, 19);
8dca8a
+			} else if (offset > 0) {
8dca8a
+				offset--;
8dca8a
+				max_offset = 0;
8dca8a
+				for_each_irq(tmp, print_tmp_irq_line, NULL);
8dca8a
+				max_offset -= LINES - 7;
8dca8a
+				if (max_offset < 0)
8dca8a
+					max_offset = 0;
8dca8a
+				move(position, 19);
8dca8a
 			}
8dca8a
 			break;
8dca8a
 		case KEY_DOWN:
8dca8a
-			if(position < g_list_length(all_irqs) + 3) {
8dca8a
-				position++;
8dca8a
+			if (position < (size_t)(LINES  - 4)) {
8dca8a
+				if(position < g_list_length(all_irqs) + 3) {
8dca8a
+					position++;
8dca8a
+					move(position, 19);
8dca8a
+				}
8dca8a
+			} else if (offset < max_offset) {
8dca8a
+				offset++;
8dca8a
+				max_offset = 0;
8dca8a
+				for_each_irq(tmp, print_tmp_irq_line, NULL);
8dca8a
+				max_offset -= LINES - 7;
8dca8a
+				if (max_offset < 0)
8dca8a
+					max_offset = 0;
8dca8a
 				move(position, 19);
8dca8a
 			}
8dca8a
 			break;
8dca8a
 		case '\n':
8dca8a
 		case '\r': {
8dca8a
 			attrset(COLOR_PAIR(3));
8dca8a
-			int banned = toggle_irq(tmp, position - 4);
8dca8a
+			int banned = toggle_irq(tmp, position + offset - 4);
8dca8a
 			if(banned) {
8dca8a
 				mvprintw(position, 19, "YES");
8dca8a
 			} else {
8dca8a
@@ -456,7 +561,7 @@ void handle_irq_banning()
8dca8a
 			processing = 0;
8dca8a
 			curs_set(0);
8dca8a
 			/* Forget the changes */
8dca8a
-			tmp = g_list_copy_deep(all_irqs, copy_irq, NULL);
8dca8a
+			g_list_free(tmp);
8dca8a
 			print_all_irqs();
8dca8a
 			attrset(COLOR_PAIR(0));
8dca8a
 			mvprintw(LINES - 3, 1, "			\
8dca8a
@@ -470,6 +575,7 @@ void handle_irq_banning()
8dca8a
 			break;
8dca8a
 		case 's':
8dca8a
 			processing = 0;
8dca8a
+			g_list_free(all_irqs);
8dca8a
 			all_irqs = tmp;
8dca8a
 			curs_set(0);
8dca8a
 			print_all_irqs();
8dca8a
@@ -548,11 +654,13 @@ void init()
8dca8a
 		init_pair(10, COLOR_MAGENTA, COLOR_BLACK);
8dca8a
 	}
8dca8a
 
8dca8a
+	offset = 0;
8dca8a
 	display_tree();
8dca8a
 }
8dca8a
 
8dca8a
 void close_window(int sig __attribute__((unused)))
8dca8a
 {
8dca8a
+	g_list_free(all_cpus);
8dca8a
 	g_list_free(setup.banned_irqs);
8dca8a
 	g_list_free(setup.banned_cpus);
8dca8a
 	g_list_free_full(tree, free);
8dca8a
@@ -595,10 +703,13 @@ void setup_irqs()
8dca8a
 void display_tree_node_irqs(irq_t *irq, void *data)
8dca8a
 {
8dca8a
 	char indent[32] = "	   \0";
8dca8a
-	snprintf(indent + strlen(indent), 32 - strlen(indent), "%s", (char *)data);
8dca8a
-	attrset(COLOR_PAIR(3));
8dca8a
-	printw("%sIRQ %u, IRQs since last rebalance %lu\n",
8dca8a
+	if (max_offset >= offset && max_offset - offset < LINES - 5) {
8dca8a
+		snprintf(indent + strlen(indent), 32 - strlen(indent), "%s", (char *)data);
8dca8a
+		attrset(COLOR_PAIR(3));
8dca8a
+		printw("%sIRQ %u, IRQs since last rebalance %lu\n",
8dca8a
 			indent, irq->vector, irq->diff);
8dca8a
+	}
8dca8a
+	max_offset++;
8dca8a
 }
8dca8a
 
8dca8a
 void display_tree_node(cpu_node_t *node, void *data)
8dca8a
@@ -644,7 +755,9 @@ void display_tree_node(cpu_node_t *node, void *data)
8dca8a
 	default:
8dca8a
 		break;
8dca8a
 	}
8dca8a
-	printw("%s", copy_to);
8dca8a
+	if (max_offset >= offset)
8dca8a
+		printw("%s", copy_to);
8dca8a
+	max_offset++;
8dca8a
 	if(g_list_length(node->irqs) > 0) {
8dca8a
 		for_each_irq(node->irqs, display_tree_node_irqs, indent);
8dca8a
 	}
8dca8a
@@ -661,7 +774,11 @@ void display_tree()
8dca8a
 	char *irqbalance_data = get_data(STATS);
8dca8a
 	parse_into_tree(irqbalance_data);
8dca8a
 	display_banned_cpus();
8dca8a
+	max_offset = 0;
8dca8a
 	for_each_node(tree, display_tree_node, NULL);
8dca8a
+	max_offset -= LINES - 5;
8dca8a
+	if (max_offset < 0)
8dca8a
+		max_offset = 0;
8dca8a
 	show_frame();
8dca8a
 	show_footer();
8dca8a
 	refresh();
8dca8a
diff --git a/ui/ui.h b/ui/ui.h
8dca8a
index ca2a3a6..da5b4b9 100644
8dca8a
--- a/ui/ui.h
8dca8a
+++ b/ui/ui.h
8dca8a
@@ -14,6 +14,9 @@
8dca8a
 extern GList *tree;
8dca8a
 extern setup_t setup;
8dca8a
 
8dca8a
+extern int offset;
8dca8a
+extern int max_offset;
8dca8a
+
8dca8a
 void show_frame();
8dca8a
 void show_footer();
8dca8a
 
8dca8a
-- 
8dca8a
2.33.1
8dca8a