commit f6d2f18

uint  ·  2026-05-13 22:46:16 +0000 UTC
parent 86883e9
add window resizing

resizing windows also updates the pty viewarea
3 files changed,  +188, -37
+126, -37
  1@@ -19,23 +19,21 @@
  2 #include "term.h"
  3 #include "utils.h"
  4 
  5-#define WIDTH  800
  6-#define HEIGHT 600
  7-
  8-#define COLS   80
  9-#define ROWS   24
 10+#define START_COLS   80
 11+#define START_ROWS   24
 12 
 13 static Fontface font;
 14 static Caret car;
 15 static RGFW_window* win = NULL;
 16 static RGFW_surface* surf = NULL;
 17 static uint32_t* pixels = NULL;
 18+static int winw;
 19+static int winh;
 20 
 21-static Rune runes[COLS*ROWS]; /* TODO: dynamic */
 22 static Term term = {
 23-	.runes = runes,
 24-	.cols = COLS,
 25-	.rows = ROWS,
 26+	.runes = NULL,
 27+	.cols = 0,
 28+	.rows = 0,
 29 	.ptyfd = -1,
 30 	.ptypid = -1,
 31 	.fg = 0xffffffff,
 32@@ -47,6 +45,9 @@ static void handle_key(RGFW_event ev);
 33 static void init(void);
 34 static void ptyread(void);
 35 static void ptywrite(const char* s, size_t n);
 36+static void resize_pty(void);
 37+static int resize_surface(int w, int h);
 38+static void resize_terminal(int w, int h);
 39 static void run(void);
 40 
 41 /**
 42@@ -54,6 +55,7 @@ static void run(void);
 43  */
 44 static void cleanup(void)
 45 {
 46+	free(term.runes);
 47 	font_free(&font);
 48 
 49 	if (surf)
 50@@ -104,12 +106,38 @@ static void handle_key(RGFW_event ev)
 51  */
 52 static void init(void)
 53 {
 54+	/* font */
 55+	/* TODO: paths */
 56+	if (font_load(&font, "./Xanh.ttf", 24.0) < 0)
 57+		die(1, "failed to load font");
 58+	font.aa = true;
 59+
 60+	winw = START_COLS*font.cellw;
 61+	winh = START_ROWS*font.cellh;
 62+
 63+	if (term_resize(&term, &car, START_COLS, START_ROWS) < 0)
 64+		die(1, "failed to resize terminal");
 65+
 66+	/* window */
 67+	if (!(win = RGFW_createWindow("cterm", 0, 0, winw, winh, 0)))
 68+		die(1, "failed to create window");
 69+
 70+	pixels = calloc(winw*winh, sizeof(*pixels));
 71+	if (!pixels)
 72+		die(1, "failed to alloc pixel buffer");
 73+
 74+	surf = RGFW_window_createSurface(
 75+		win, (u8*)pixels, winw, winh, RGFW_formatRGBA8
 76+	);
 77+	if (!surf)
 78+		die(1, "failed to create window surface");
 79+
 80 	/* pty */
 81 	struct winsize ws = {
 82-		.ws_col = COLS,
 83-		.ws_row = ROWS,
 84-		.ws_xpixel = WIDTH,
 85-		.ws_ypixel = HEIGHT
 86+		.ws_col = term.cols,
 87+		.ws_row = term.rows,
 88+		.ws_xpixel = winw,
 89+		.ws_ypixel = winh
 90 	};
 91 	term.ptypid = forkpty(&term.ptyfd, NULL, NULL, &ws);
 92 	if (term.ptypid < 0)
 93@@ -125,25 +153,6 @@ static void init(void)
 94 	if (flags >= 0) /* append to existing flags */
 95 		fcntl(term.ptyfd, F_SETFL, flags|O_NONBLOCK);
 96 
 97-	/* window */
 98-	if (!(win = RGFW_createWindow("cterm", 0, 0, 800, 600, 0)))
 99-		die(1, "failed to create window");
100-
101-	pixels = calloc(WIDTH*HEIGHT, sizeof(*pixels));
102-	if (!pixels)
103-		die(1, "failed to alloc pixel buffer");
104-
105-	surf = RGFW_window_createSurface(
106-		win, (u8*)pixels, WIDTH, HEIGHT, RGFW_formatRGBA8
107-	);
108-	if (!surf)
109-		die(1, "failed to create window surface");
110-
111-	/* font */
112-	/* TODO: paths */
113-	if (font_load(&font, "./Xanh.ttf", 24.0) < 0)
114-		die(1, "failed to load font");
115-	font.aa = true;
116 	term_clear(&term, &car);
117 }
118 
119@@ -192,6 +201,78 @@ static void ptywrite(const char* s, size_t n)
120 	}
121 }
122 
123+/** TODO
124+ */
125+static void resize_pty(void)
126+{
127+	struct winsize ws = {
128+		.ws_col = term.cols,
129+		.ws_row = term.rows,
130+		.ws_xpixel = winw,
131+		.ws_ypixel = winh,
132+	};
133+
134+	if (term.ptyfd >= 0)
135+		ioctl(term.ptyfd, TIOCSWINSZ, &ws);
136+}
137+
138+/** TODO
139+ */
140+static int resize_surface(int w, int h)
141+{
142+	uint32_t* npixels;
143+	RGFW_surface* nsurf;
144+
145+	if (w < 1)
146+		w = 1;
147+	if (h < 1)
148+		h = 1;
149+
150+	npixels = calloc(w*h, sizeof(*npixels));
151+	if (!npixels)
152+		return -1;
153+
154+	nsurf = RGFW_window_createSurface(
155+		win, (u8*)npixels, w, h, RGFW_formatRGBA8
156+	);
157+	if (!nsurf) {
158+		free(npixels);
159+		return -1;
160+	}
161+
162+	if (surf)
163+		RGFW_surface_free(surf);
164+	free(pixels);
165+
166+	pixels = npixels;
167+	surf = nsurf;
168+	winw = w;
169+	winh = h;
170+
171+	return 0;
172+}
173+
174+/** TODO
175+ */
176+static void resize_terminal(int w, int h)
177+{
178+	int cols = w / font.cellw;
179+	int rows = h / font.cellh;
180+
181+	if (cols < 1)
182+		cols = 1;
183+	if (rows < 1)
184+		rows = 1;
185+
186+	if (cols == term.cols && rows == term.rows)
187+		return;
188+
189+	if (term_resize(&term, &car, cols, rows) < 0)
190+		die(1, "failed to resize terminal");
191+
192+	resize_pty();
193+}
194+
195 /**
196  * @brief program event loop (TODO)
197  */
198@@ -200,25 +281,33 @@ static void run(void)
199 	RGFW_event ev;
200 
201 	while (!RGFW_window_shouldClose(win)) {
202-		while (RGFW_window_checkEvent(win, &ev))
203+		while (RGFW_window_checkEvent(win, &ev)) {
204+			if (ev.type == RGFW_windowResized) {
205+				if (resize_surface(ev.update.w, ev.update.h) < 0)
206+					die(EXIT_FAILURE, "failed to resize surface");
207+				resize_terminal(ev.update.w, ev.update.h);
208+				continue;
209+			}
210+
211 			handle_key(ev);
212+		}
213 
214 		ptyread();
215 
216 		/* drawing */
217-		draw_clear(pixels, WIDTH, HEIGHT, rgba(0, 0, 0, 255));
218+		draw_clear(pixels, winw, winh, rgba(0, 0, 0, 255));
219 		for (int y = 0; y < term.rows; y++) {
220 			for (int x = 0; x < term.cols; x++) {
221 				Rune* rune  = &RUNE(&term, x, y);
222 
223 				draw_rune(
224-					pixels, WIDTH, HEIGHT, x, y,
225+					pixels, winw, winh, x, y,
226 					font.cellw, font.cellh, rune->bg
227 				);
228 
229 				if (rune->cp != ' ') {
230 					draw_codepoint(
231-						&font, pixels, WIDTH, HEIGHT,
232+						&font, pixels, winw, winh,
233 						x * font.cellw,
234 						y * font.cellh + (int)font.asc,
235 						rune->cp, rune->fg
236@@ -228,7 +317,7 @@ static void run(void)
237 		}
238 
239 		draw_caret(
240-			pixels, WIDTH, HEIGHT,
241+			pixels, winw, winh,
242 			car.x, car.y,
243 			font.cellw, font.cellh,
244 			rgba(255, 255, 255, 255)
+4, -0
 1@@ -61,6 +61,10 @@ void term_clear(Term* t, Caret* c);
 2  */
 3 void term_putc(Term* t, Caret* c, uint32_t cp);
 4 
 5+/** TODO
 6+ */
 7+int term_resize(Term* t, Caret* c, int cols, int rows);
 8+
 9 /**
10  * @brief scroll viewport up by one
11  *
+58, -0
 1@@ -1,4 +1,5 @@
 2 #include <stdbool.h>
 3+#include <stdlib.h>
 4 #include <string.h>
 5 
 6 #include <grapheme.h>
 7@@ -251,6 +252,63 @@ void term_putc(Term* t, Caret* c, uint32_t cp)
 8 	}
 9 }
10 
11+int term_resize(Term* t, Caret* c, int cols, int rows)
12+{
13+	/* old */
14+	Rune* or = t->runes;
15+	int ocols = t->cols;
16+	int orows = t->rows;
17+
18+	if (cols < 1)
19+		cols = 1;
20+	if (rows < 1)
21+		rows = 1;
22+
23+	/* new */
24+	Rune* nr = calloc(cols*rows, sizeof(*nr));
25+	if (!nr)
26+		return -1;
27+
28+	for (int y = 0; y < rows; y++) {
29+		for (int x = 0; x < cols; x++) {
30+			Rune* r = &nr[y * cols + x];
31+			r->cp = ' ';
32+			r->fg = t->fg;
33+			r->bg = t->bg;
34+			r->dmg = true;
35+		}
36+	}
37+
38+	if (or) {
39+		int copyrows = orows < rows ? orows : rows;
40+		int copycols = ocols < cols ? ocols : cols;
41+
42+		for (int y = 0; y < copyrows; y++) {
43+			memcpy(
44+				&nr[y * cols], &or[y * ocols],
45+				sizeof(Rune) * copycols
46+			);
47+		}
48+	}
49+
50+	free(or);
51+
52+	t->runes = nr;
53+	t->cols = cols;
54+	t->rows = rows;
55+
56+	if (c->x >= cols)
57+		c->x = cols - 1;
58+	if (c->y >= rows)
59+		c->y = rows - 1;
60+	if (c->x < 0)
61+		c->x = 0;
62+	if (c->y < 0)
63+		c->y = 0;
64+
65+	return 0;
66+}
67+
68 void term_scroll(Term* t)
69 {
70 	Rune* runes = t->runes;