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;ix = 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;ix+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