@@ -9,22 +9,36 @@
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_CACHE_H

#include "lib/list.h"
#include "lib/graphics.h"
#include "lib/compositing.h"

//DEFN_SYSCALL0(getpid, 9)
//DEFN_SYSCALL0(mkpipe, 21)
DEFN_SYSCALL2(shm_obtain, 35, char *, int)
DEFN_SYSCALL1(shm_release, 36, char *)
DEFN_SYSCALL2(sys_signal, 38, int, int)
DEFN_SYSCALL2(share_fd, 39, int, int)

/* For terminal, not for us */
#define FREETYPE 1

sprite_t * sprites[128];

#define WIN_D 32
#define WIN_B WIN_D / 8

typedef struct process_windows process_windows_t;

typedef struct {
uint32_t wid; /* Window identifier */
uint32_t owner; /* Owning process */
process_windows_t * owner; /* Owning process (back ptr) */

uint16_t width; /* Buffer width in pixels */
uint16_t height; /* Buffer height in pixels */
@@ -34,12 +48,52 @@ typedef struct {
uint16_t z; /* Stack order */

void * buffer; /* Window buffer */
uint16_t bufid; /* We occasionally replace the buffer; each is uniquely-indexed */
} window_t;

struct process_windows {
uint32_t pid;

int event_pipe; /* Pipe to send events through */
int command_pipe; /* Pipe on which we receive commands */

list_t * windows;
};

list_t * process_list;

process_windows_t * get_process_windows (uint32_t pid) {
foreach(n, process_list) {
process_windows_t * pw = (process_windows_t *)n->value;
if (pw->pid == pid) {
return pw;
}
}

return NULL;
}

window_t * get_window (uint32_t wid) {
foreach (n, process_list) {
process_windows_t * pw = (process_windows_t *)n->value;
foreach (m, pw->windows) {
window_t * w = (window_t *)m->value;
if (w->wid == wid) {
return w;
}
}
}

return NULL;
}

void init_process_list () {
process_list = list_create();
}

#define TO_WINDOW_OFFSET(x,y) (((x) - window->x) + ((y) - window->y) * window->width)
#define DIRECT_OFFSET(x,y) ((x) + (y) * window->width)

list_t * window_list;

int32_t min(int32_t a, int32_t b) {
return (a < b) ? a : b;
@@ -56,22 +110,79 @@ uint8_t is_between(int32_t lo, int32_t hi, int32_t val) {

uint8_t is_top(window_t *window, uint16_t x, uint16_t y) {
uint16_t index = window->z;
foreach(node, window_list) {
window_t * win = (window_t *)node->value;
if (win == window) continue;
if (win->z < index) continue;
if (is_between(win->x, win->x + win->width, x) && is_between(win->y, win->y + win->height, y)) {
return 0;
foreach(n, process_list) {
process_windows_t * pw = (process_windows_t *)n->value;

foreach(node, pw->windows) {
window_t * win = (window_t *)node->value;
if (win == window) continue;
if (win->z < index) continue;
if (is_between(win->x, win->x + win->width, x) && is_between(win->y, win->y + win->height, y)) {
return 0;
}
}
}
return 1;
}

void redraw_window(window_t *window) {
uint16_t _lo_x = max(window->x, 0);
uint16_t _hi_x = min(window->x + window->width, graphics_width);
uint16_t _lo_y = max(window->y, 0);
uint16_t _hi_y = min(window->y + window->height, graphics_height);

window_t * init_window (process_windows_t * pw, int32_t x, int32_t y, uint16_t width, uint16_t height, uint16_t index) {
static int _last_wid = 0;

window_t * window = malloc(sizeof(window));
if (!window) {
printf("[compositor] SEVERE: Could not malloc a window_t!");
return NULL;
}

window->owner = pw;
window->wid = _last_wid++;
window->bufid = 0;

window->width = width;
window->height = height;
window->x = x;
window->y = y;
window->z = index;

char key[256];
SHMKEY(key, 256, window);
window->buffer = (uint8_t *)syscall_shm_obtain(key, (width * height * WIN_B));
if (!window->buffer) {
printf("[compositor] SEVERE: Could not create a buffer for a new window for pid %d!", pw->pid);
free(window);
return NULL;
}

list_insert(pw->windows, window);

return window;
}

void resize_window (window_t * window, uint16_t width, uint16_t height) {
window->width = width;
window->height = height;

/* Release the old buffer */
char key[256];
SHMKEY(key, 256, window);
syscall_shm_release(key);

/* Create the new one */
window->bufid++;
SHMKEY(key, 256, window);
window->buffer = (uint8_t *)syscall_shm_obtain(key, (width * height * WIN_B));
}

void redraw_window(window_t *window, uint16_t x, uint16_t y, uint16_t width, uint16_t height) {
if (!window) {
return;
}

uint16_t _lo_x = max(window->x + x, 0);
uint16_t _hi_x = min(window->x + width, graphics_width);
uint16_t _lo_y = max(window->y + y, 0);
uint16_t _hi_y = min(window->y + height, graphics_height);

for (uint16_t y = _lo_y; y < _hi_y; ++y) {
for (uint16_t x = _lo_x; x < _hi_x; ++x) {
@@ -82,17 +193,90 @@ void redraw_window(window_t *window) {
}
}

void init_window(window_t *window, int32_t x, int32_t y, uint16_t width, uint16_t height, uint16_t index) {
window->width = width;
window->height = height;
window->x = x;
window->y = y;
window->z = index;
/* XXX */
window->buffer = (void *)malloc(sizeof(uint32_t) * window->width * window->height);
void redraw_full_window (window_t * window) {
if (!window) {
return;
}

redraw_window(window, (uint16_t)0, (uint16_t)0, window->width, window->height);
}

void destroy_window (window_t * window) {
/* Free the window buffer */
char key[256];
SHMKEY(key, 256, window);
syscall_shm_release(key);

/* Now, kill the object itself */
process_windows_t * pw = window->owner;

node_t * n = list_find(pw->windows, window);
list_delete(pw->windows, n);
free(n);

#if 0
/* Does the owner have any windows themselves? */
if (pw->windows->length == 0) {
delete_process(pw);
}
#endif
}

void sig_window_command (int sig) {
foreach(n, process_list) {
process_windows_t * pw = (process_windows_t *)n->value;

/* Are there any messages in this process's command pipe? */
struct stat buf;
fstat(pw->command_pipe, &buf);
while (buf.st_size > 0) {
w_window_t wwt;
wins_packet_t header;
read(pw->command_pipe, &header, sizeof(wins_packet_t));

switch (header.command_type) {
case WC_NEWWINDOW:
/* No packet */
read(pw->command_pipe, &wwt, sizeof(w_window_t));
init_window(pw, wwt.left, wwt.top, wwt.width, wwt.height, 0); //XXX: an actual index
break;

case WC_RESIZE:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
resize_window(get_window(wwt.wid), /*wwt.left, wwt.top,*/ wwt.width, wwt.height);
break;

case WC_DESTROY:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
destroy_window(get_window(wwt.wid));
break;

case WC_DAMAGE:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
redraw_window(get_window(wwt.wid), wwt.left, wwt.top, wwt.width, wwt.height);
break;

default:
printf("[compositor] WARN: Unknown command type %d...\n");
void * nullbuf = malloc(header.packet_size);
read(pw->command_pipe, nullbuf, header.packet_size);
free(nullbuf);
break;
}

fstat(pw->command_pipe, &buf);
}
}
}

void window_set_point(window_t * window, uint16_t x, uint16_t y, uint32_t color) {
#if 0
printf("window_set_point(0x%x, %d, %d) = 0x%x\n", window->buffer, x, y, color);
if (!window) {
return;
}
#endif

((uint32_t *)window->buffer)[DIRECT_OFFSET(x,y)] = color;
}

@@ -118,8 +302,11 @@ void window_draw_line(window_t * window, uint16_t x0, uint16_t x1, uint16_t y0,
}

void window_draw_sprite(window_t * window, sprite_t * sprite, uint16_t x, uint16_t y) {
for (uint16_t _y = 0; _y < sprite->height; ++_y) {
for (uint16_t _x = 0; _x < sprite->width; ++_x) {
int x_hi = min(sprite->width, (graphics_width - x));
int y_hi = min(sprite->height, (graphics_height - y));

for (uint16_t _y = 0; _y < y_hi; ++_y) {
for (uint16_t _x = 0; _x < x_hi; ++_x) {
if (sprite->alpha) {
/* Technically, unsupported! */
window_set_point(window, x + _x, y + _y, SPRITE(sprite, _x, _y));
@@ -132,7 +319,6 @@ void window_draw_sprite(window_t * window, sprite_t * sprite, uint16_t x, uint16
}
}


void window_fill(window_t *window, uint32_t color) {
for (uint16_t i = 0; i < window->height; ++i) {
for (uint16_t j = 0; j < window->width; ++j) {
@@ -148,6 +334,84 @@ void waitabit() {
}
}


/* Request page system */


wins_server_global_t * _request_page;

void init_request_system () {
_request_page = (wins_server_global_t *)syscall_shm_obtain(WINS_SERVER_IDENTIFIER, sizeof(wins_server_global_t));
if (!_request_page) {
printf("Compositor could not get a shm block for its request page! Bailing...");
exit(-1);
}

_request_page->lock = 0;
_request_page->server_done = 0;
_request_page->client_done = 0;
_request_page->client_pid = 0;
_request_page->event_pipe = 0;
_request_page->command_pipe = 0;
_request_page->magic = WINS_MAGIC;
}

void process_request () {
if (_request_page->client_done) {
process_windows_t * pw = malloc(sizeof(process_windows_t));
pw->pid = _request_page->client_pid;
pw->event_pipe = syscall_mkpipe();
pw->command_pipe = syscall_mkpipe();
pw->windows = list_create();

_request_page->event_pipe = syscall_share_fd(pw->event_pipe, pw->pid);
_request_page->command_pipe = syscall_share_fd(pw->command_pipe, pw->pid);
_request_page->client_pid = 0;
_request_page->server_done = 1;
}
}

void delete_process (process_windows_t * pw) {
list_destroy(pw->windows);
list_free(pw->windows);
free(pw->windows);

close(pw->command_pipe);
close(pw->event_pipe);

node_t * n = list_find(process_list, pw);
list_delete(process_list, n);
free(n);
free(pw);
}


/* Signals */


void init_signal_handlers () {
syscall_sys_signal(WC_NEWWINDOW, (uintptr_t)sig_window_command);
syscall_sys_signal(WC_RESIZE, (uintptr_t)sig_window_command);
syscall_sys_signal(WC_DESTROY, (uintptr_t)sig_window_command);
syscall_sys_signal(WC_DAMAGE, (uintptr_t)sig_window_command);

#if 0
syscall_sys_signal(WE_KEYDOWN, (uintptr_t)sig_event);
syscall_sys_signal(WE_KEYUP, (uintptr_t)sig_event);
syscall_sys_signal(WE_MOUSEMOVE, (uintptr_t)sig_event);
syscall_sys_signal(WE_MOUSEENTER, (uintptr_t)sig_event);
syscall_sys_signal(WE_MOUSELEAVE, (uintptr_t)sig_event);
syscall_sys_signal(WE_MOUSECLICK, (uintptr_t)sig_event);
syscall_sys_signal(WE_MOUSEUP, (uintptr_t)sig_event);
syscall_sys_signal(WE_NEWWINDOW, (uintptr_t)sig_event);
syscall_sys_signal(WE_RESIZED, (uintptr_t)sig_event);
#endif
}


/* Sprite stuff */


sprite_t alpha_tmp;

void init_sprite(int i, char * filename, char * alpha) {
@@ -237,7 +501,9 @@ static void test() {
}

void run_startup_item(startup_item * item) {
#if 0 // No printing!
printf("[compositor] Running startup item: %s\n", item->name);
#endif
item->func();
progress += item->time;
}
@@ -309,11 +575,42 @@ void _load_wallpaper() {
init_sprite(1, "/usr/share/wallpaper.bmp", NULL);
}

void init_base_windows () {
process_windows_t * pw = malloc(sizeof(process_windows_t));
pw->pid = getpid();
pw->command_pipe = syscall_mkpipe(); /* nothing in here */
pw->event_pipe = syscall_mkpipe(); /* nothing in here */
pw->windows = list_create();

/* Create the background window */
window_t * root = init_window(pw, 0, 0, graphics_width, graphics_height, 0);
window_draw_sprite(root, sprites[1], 0, 0);
redraw_full_window(root);

/* Create the panel */
window_t * panel = init_window(pw, 0, 0, graphics_width, 24, -1);
window_fill(panel, rgb(0,120,230));
init_sprite(2, "/usr/share/panel.bmp", NULL);
for (uint32_t i = 0; i < graphics_width; i += sprites[2]->width) {
window_draw_sprite(panel, sprites[2], i, 0);
}
redraw_full_window(panel);
}

int main(int argc, char ** argv) {

/* Initialize graphics setup */
init_graphics_double_buffer();

/* Initialize the client request system */
init_request_system();

/* Initialize process list */
init_process_list();

/* Initialize signal handlers */
init_signal_handlers();

/* Load sprites */
init_sprite(0, "/usr/share/bs.bmp", "/usr/share/bs-alpha.bmp");
display();
@@ -339,71 +636,39 @@ int main(int argc, char ** argv) {
init_graphics();
#endif

window_list = list_create();

window_t wina, winb, root, panel;

init_window(&root, 0, 0, graphics_width, graphics_height, 0);
list_insert(window_list, &root);
#if 0
uint32_t odd = 0;
uint32_t black = rgb(0,0,0);
uint32_t white = rgb(255,255,255);
for (uint16_t j = 0; j < root.height; ++j) {
for (uint16_t i = 0; i < root.width; ++i) {
odd++;
if ((odd + j) % 2) {
window_set_point(&root, i, j, black);
} else {
window_set_point(&root, i, j, white);

}
}
}
#endif
window_draw_sprite(&root, sprites[1], 0, 0);
/* Create the root and panel */
init_base_windows();

init_window(&panel, 0, 0, graphics_width, 24, -1);
list_insert(window_list, &panel);
window_fill(&panel, rgb(0,120,230));
init_sprite(2, "/usr/share/panel.bmp", NULL);
for (uint32_t i = 0; i < graphics_width; i += sprites[2]->width) {
window_draw_sprite(&panel, sprites[2], i, 0);
}
process_windows_t * rootpw = get_process_windows(getpid());

#define WINA_WIDTH 300
#define WINA_HEIGHT 300
init_window(&wina, 10, 10, WINA_WIDTH, WINA_HEIGHT, 1);
list_insert(window_list, &wina);
window_fill(&wina, rgb(0,255,0));
window_t * wina = init_window(rootpw, 10, 10, WINA_WIDTH, WINA_HEIGHT, 1);
window_fill(wina, rgb(0,255,0));

#define WINB_WIDTH 700
#define WINB_HEIGHT 700
init_window(&winb, 120, 120, WINB_WIDTH, WINB_HEIGHT, 2);
list_insert(window_list, &winb);
window_fill(&winb, rgb(0,0,255));
window_t * winb = init_window(rootpw, 120, 120, WINB_WIDTH, WINB_HEIGHT, 2);
window_fill(winb, rgb(0,0,255));

redraw_window(&root); /* We only need to redraw root if things move around */
redraw_window(&panel);
redraw_window(&wina);
redraw_window(&winb);
redraw_full_window(wina);
redraw_full_window(winb);

#if 0
flip();
#endif

while (1) {
window_draw_line(&wina, rand() % WINA_WIDTH, rand() % WINA_WIDTH, rand() % WINA_HEIGHT, rand() % WINA_HEIGHT, rgb(rand() % 255,rand() % 255,rand() % 255));
window_draw_line(&winb, rand() % WINB_WIDTH, rand() % WINB_WIDTH, rand() % WINB_HEIGHT, rand() % WINB_HEIGHT, rgb(rand() % 255,rand() % 255,rand() % 255));
redraw_window(&wina);
redraw_window(&winb);
window_draw_line(wina, rand() % WINA_WIDTH, rand() % WINA_WIDTH, rand() % WINA_HEIGHT, rand() % WINA_HEIGHT, rgb(rand() % 255,rand() % 255,rand() % 255));
window_draw_line(winb, rand() % WINB_WIDTH, rand() % WINB_WIDTH, rand() % WINB_HEIGHT, rand() % WINB_HEIGHT, rgb(rand() % 255,rand() % 255,rand() % 255));
redraw_full_window(wina);
redraw_full_window(winb);
#if 0
redraw_window(&root);
redraw_window(&panel);
flip();
#endif
}


return 0;
}
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>

#include "compositing.h"

#ifndef syscall_shm_obtain
@@ -35,7 +36,7 @@ static struct {
} wins_status;

int wins_connect() {
wins_globals = (wins_server_global_t *)syscall_shm_obtain(WINS_SERVER_IDENTIFIER, sizeof(wins_server_global_t));
wins_globals = (volatile wins_server_global_t *)syscall_shm_obtain(WINS_SERVER_IDENTIFIER, sizeof(wins_server_global_t));

/* Verify magic */
if (wins_globals->magic != WINS_MAGIC) {
@@ -64,6 +65,8 @@ int wins_connect() {
wins_status.command_pipe = syscall_get_fd(tmp);

/* Reset client status for next client */
wins_globals->event_pipe = 0;
wins_globals->command_pipe = 0;
wins_globals->client_done = 0;

/* Done with lock */
@@ -9,21 +9,25 @@
#include <stdint.h>

typedef struct {
/* Control flow structures */
volatile uint8_t lock; /* Spinlock byte */

/* LOCK REQUIRED REGION */
volatile uint8_t client_done; /* Client has finished work */
volatile uint8_t server_done; /* Server has finished work */

/* The actual data passed back and forth */
pid_t client_pid; /* Actively communicating client process */
uintptr_t event_pipe; /* Client event pipe (ie, mouse, keyboard) */
uintptr_t command_pipe; /* Client command pipe (ie, resize) */
/* END LOCK REQUIRED REGION */

/* Data about the system */
uint16_t server_width; /* Screen resolution, width */
uint16_t server_height; /* Screen resolution, height */
uint8_t server_depth; /* Native screen depth (in bits) */
uint32_t magic;

uint32_t magic;
} wins_server_global_t;

typedef struct {
@@ -82,4 +86,7 @@ typedef struct {
#define MOUSE_BUTTON_MIDDLE 0x04


#define SHMKEY(buf,sz,window) snprintf(buf, sz, "%s.%d.%d.%d", WINS_SERVER_IDENTIFIER, window->owner->pid, window->wid, window->bufid);


#endif