217 lines
5.4 KiB
C
217 lines
5.4 KiB
C
/*
|
|
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;
|
|
}
|
|
|