From 7827edcba9a72f6cc4983992fe64930099424648 Mon Sep 17 00:00:00 2001
From: sbosse <sbosse@uni-bremen.de>
Date: Mon, 14 Oct 2024 23:10:02 +0200
Subject: [PATCH] Mon 14 Oct 23:09:15 CEST 2024

---
 user/manager.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 216 insertions(+)
 create mode 100644 user/manager.c

diff --git a/user/manager.c b/user/manager.c
new file mode 100644
index 0000000..14f67c0
--- /dev/null
+++ b/user/manager.c
@@ -0,0 +1,216 @@
+/*
+Copyright (C) 2016-2019 The University of Notre Dame
+This software is distributed under the GNU General Public License.
+See the file LICENSE for details.
+*/
+
+/*
+Simple window manager runs a list of programs and distributes
+events to each based on which one currently has the focus.
+*/
+
+#include "library/syscalls.h"
+#include "library/string.h"
+#include "library/stdio.h"
+#include "library/kernel_object_string.h"
+#include "library/nwindow.h"
+#include "library/errno.h"
+
+#define NWINDOWS 4
+
+#define WINDOW_TITLE_HEIGHT 14
+#define WINDOW_TITLE_ACTIVE_COLOR 100,100,255
+#define WINDOW_TITLE_INACTIVE_COLOR 25,25,50
+#define WINDOW_TITLE_TEXT_COLOR 255,255,255
+#define WINDOW_BORDER_COLOR 200,200,200
+#define WINDOW_BORDER 3
+#define WINDOW_TEXT_PADDING 3
+
+#define CLOSE_BOX_PADDING 3
+#define CLOSE_BOX_SIZE (WINDOW_TITLE_HEIGHT-CLOSE_BOX_PADDING*2)
+#define CLOSE_BOX_COLOR 100,100,100
+
+struct window {
+	int w,h,x,y;
+	int console_mode;
+	const char * exec;
+	const char * arg;
+	int argc;
+	int pid;
+	int fds[6];
+};
+
+struct nwindow *nw = 0;
+
+struct window windows[NWINDOWS] = {
+	{ .x=0, .y=0, .console_mode=1, .exec = "bin/shell.exe", .arg=0, .argc = 2 },
+	{ .x=0, .y=0, .console_mode=0, .exec = "bin/saver.exe", .arg=0, .argc = 2 },
+	{ .x=0, .y=0, .console_mode=0, .exec = "bin/snake.exe", .arg=0, .argc = 2 },
+	{ .x=0, .y=0, .console_mode=1, .exec = "bin/fractal.exe", .arg=0, .argc = 2 },
+};
+
+void draw_border( struct window *win, int isactive )
+{
+	int x=win->x;
+	int y=win->y;
+	int h=win->h;
+	int w=win->w;
+
+	// Title bar
+	if(isactive) {
+		nw_bgcolor(nw,WINDOW_TITLE_ACTIVE_COLOR);
+	} else {
+		nw_bgcolor(nw,WINDOW_TITLE_INACTIVE_COLOR);
+	}
+	nw_clear(nw,x,y,w,WINDOW_TITLE_HEIGHT);
+
+	// Close box
+	nw_fgcolor(nw,CLOSE_BOX_COLOR);
+	nw_rect(nw,x+CLOSE_BOX_PADDING,y+CLOSE_BOX_PADDING,CLOSE_BOX_SIZE,CLOSE_BOX_SIZE);
+	// Title text
+	nw_fgcolor(nw,WINDOW_TITLE_TEXT_COLOR);
+	nw_string(nw,x+CLOSE_BOX_SIZE+CLOSE_BOX_PADDING*2,y+WINDOW_TEXT_PADDING,win->exec);
+
+	// Border box
+	nw_fgcolor(nw,WINDOW_BORDER_COLOR);
+	nw_line(nw,x,y,w,0);
+	nw_line(nw,x,y+WINDOW_TITLE_HEIGHT-1,w,0);
+
+	nw_line(nw,x,y,0,h);
+	nw_line(nw,x+1,y,0,h);
+
+	nw_line(nw,x,y+h,w,0);
+	nw_line(nw,x+1,y+h,w,0);
+
+	nw_line(nw,x+w,y,0,h);
+	nw_line(nw,x+w+1,y,0,h);
+
+	nw_bgcolor(nw,0,0,0);
+}
+
+int main(int argc, char *argv[])
+{
+	/* Obtain the default window from parent process. */
+	nw = nw_create_default();
+	nw_clear(nw,0, 0, nw_width(nw), nw_height(nw));
+	nw_flush(nw);
+
+	/* Distribute window locations across screen. */
+	
+	int i;
+	for(i=0;i<NWINDOWS;i++) {
+		struct window *w = &windows[i];
+		w->x = i%2 ? nw_width(nw)/2 : 0;
+		w->y = i/2 ? nw_height(nw)/2 : 0;
+		w->w = nw_width(nw)/2-2;
+		w->h = nw_height(nw)/2-2;
+		//printf("window %d %d %d %d %d %s\n",i,w->w,w->h,w->x,w->y,w->exec);
+	}
+
+	/* Open each window and connect the various pipes. */
+	
+	for(i=0;i<NWINDOWS;i++) {
+		struct window *w = &windows[i];
+
+		struct nwindow *child = nw_create_child(nw,w->x+WINDOW_BORDER, w->y+WINDOW_TITLE_HEIGHT, w->w-WINDOW_BORDER*2, w->h-WINDOW_BORDER-WINDOW_TITLE_HEIGHT);
+
+		int window_fd = nw_fd(child);
+
+		if(w->console_mode) {
+			w->fds[0] = syscall_open_console(window_fd);
+			w->fds[1] = w->fds[0];
+			w->fds[2] = w->fds[0];
+			w->fds[3] = window_fd; // doesn't need a window fd
+			w->fds[4] = 4;
+			w->fds[5] = 5;
+		} else {
+			w->fds[0] = -1; // doesn't need stdin/stdout
+			w->fds[1] = -1;
+			w->fds[2] = -1;
+			w->fds[3] = window_fd;
+			w->fds[4] = 4;
+			w->fds[5] = 5;
+		}
+
+		draw_border(w,0);
+		nw_bgcolor(child,0,0,0);
+		nw_flush(nw);
+
+		const char *args[3];
+		args[0] = w->exec;
+		args[1] = w->arg;
+		args[2] = 0;
+
+		int pfd = syscall_open_file(KNO_STDDIR,w->exec,0,0);
+		if(pfd>=0) {
+			w->pid = syscall_process_wrun(pfd, w->argc, args, w->fds, 6);
+			if(w->pid<0) {
+				nw_string(child,10,10,"Unable to start process:");
+				nw_string(child,10,20,w->exec);
+				nw_string(child,10,30,strerror(pfd));
+				nw_flush(child);
+				/* keep going, let other processes run. */
+			}
+		} else {
+			nw_string(child,10,10,"Unable to access program:");
+			nw_string(child,10,20,w->exec);
+			nw_string(child,10,30,strerror(pfd));
+			nw_flush(child);
+			/* keep going, let other processes run. */
+		}
+	}
+
+	/* Finally, allow the user to switch between windows*/
+	int active = 0;
+
+	/* Draw green window around active process */
+	draw_border(&windows[active],1);
+	nw_flush(nw);
+
+	/* Now wait for events to arrive at the manager. */
+	struct event e;
+	while (nw_next_event(nw,&e)) {
+
+		if(e.type==EVENT_CLOSE) break;
+		if(e.type!=EVENT_KEY_DOWN) continue;
+
+		char c = e.code;
+
+		if (c == '\t') {
+			/* If tab entered, go to the next process */
+
+			/* Draw white boundary around old window. */
+			draw_border(&windows[active],0);
+			nw_flush(nw);
+			active = (active + 1) % NWINDOWS;
+
+			/* Draw green window around new window. */
+			draw_border(&windows[active],1);
+			nw_flush(nw);
+		} else if (c=='~') {
+			/* If tilde entered, cancel the whole thing. */
+			break;
+		} else {
+			if(windows[active].console_mode) {
+				// Post a single character to the console.
+				syscall_object_write(windows[active].fds[KNO_STDIN],&c,1,KERNEL_IO_POST);
+			} else {
+				// Post a complete event to the window.
+				syscall_object_write(windows[active].fds[KNO_STDWIN],&e,sizeof(e),KERNEL_IO_POST);
+			}
+		}
+	}
+
+	/* Reap all children processes */
+	for (i=0;i<NWINDOWS;i++) {
+		syscall_process_reap(windows[i].pid);
+	}
+
+	/* XXX should kill child process here */
+
+	/* Clean up the window */
+	nw_clear(nw, 0, 0, nw_width(nw), nw_height(nw));
+	nw_flush(nw);
+	return 0;
+}
+