toaruos/userspace/compositor.c
2012-04-10 22:34:36 -05:00

1218 lines
33 KiB
C

/*
* The ToAru Sample Game
*/
#include <stdio.h>
#include <stdint.h>
#include <syscall.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <assert.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/window.h"
#include "../kernel/include/signal.h"
#include "../kernel/include/mouse.h"
DECL_SYSCALL0(mkpipe);
DEFN_SYSCALL0(mousedevice, 33);
DEFN_SYSCALL3(clone, 30, uintptr_t, uintptr_t, void *);
DEFN_SYSCALL0(gettid, 41);
void spin_lock(int volatile * lock) {
while(__sync_lock_test_and_set(lock, 0x01)) {
syscall_yield();
}
}
void spin_unlock(int volatile * lock) {
__sync_lock_release(lock);
}
int clone(uintptr_t,uintptr_t,void*) __attribute__((alias("syscall_clone")));
int gettid() __attribute__((alias("syscall_gettid")));
typedef struct {
uint32_t id;
char * stack;
void * ret_val;
} pthread_t;
typedef unsigned int pthread_attr_t;
#define PTHREAD_STACK_SIZE 10240
int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg) {
char * stack = malloc(PTHREAD_STACK_SIZE);
uintptr_t stack_top = (uintptr_t)stack + PTHREAD_STACK_SIZE;
thread->stack = stack;
thread->id = clone(stack_top, (uintptr_t)start_routine, arg);
return 0;
}
void pthread_exit(void * value) {
/* Perform nice cleanup */
#if 0
/* XXX: LOCK */
free(stack);
/* XXX: Return value!? */
#endif
__asm__ ("jmp 0xFFFFB00F"); /* Force thread exit */
}
sprite_t * sprites[128];
#define WIN_D 32
#define WIN_B (WIN_D / 8)
list_t * process_list;
int32_t mouse_x, mouse_y;
#define MOUSE_SCALE 10
#define MOUSE_OFFSET_X 26
#define MOUSE_OFFSET_Y 26
void redraw_region_slow(int32_t x, int32_t y, int32_t width, int32_t height);
void redraw_cursor() {
//redraw_region_slow(mouse_x / MOUSE_SCALE - 32, mouse_y / MOUSE_SCALE - 32, 64, 64);
draw_sprite(sprites[3], mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X, mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y);
}
extern window_t * init_window (process_windows_t * pw, wid_t wid, int32_t x, int32_t y, uint16_t width, uint16_t height, uint16_t index);
extern void free_window (window_t * window);
extern void resize_window_buffer (window_t * window, int16_t left, int16_t top, uint16_t width, uint16_t height);
uint16_t * depth_map = NULL;
uintptr_t * top_map = NULL;
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;
}
static window_t * get_window (wid_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;
}
static window_t * get_window_with_process (process_windows_t * pw, wid_t wid) {
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();
}
int32_t min(int32_t a, int32_t b) {
return (a < b) ? a : b;
}
int32_t max(int32_t a, int32_t b) {
return (a > b) ? a : b;
}
uint8_t is_between(int32_t lo, int32_t hi, int32_t val) {
if (val >= lo && val < hi) return 1;
return 0;
}
uint8_t is_top(window_t *window, uint16_t x, uint16_t y) {
uint16_t index = window->z;
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;
}
uint8_t inline is_top_fast(window_t * window, uint16_t x, uint16_t y) {
if (x >= graphics_width || y >= graphics_height) {
return 0;
}
if (window->z == depth_map[x + y * graphics_width]) {
return 1;
}
return 0;
}
window_t * top_at(uint16_t x, uint16_t y) {
uint32_t index_top = 0;
window_t * window_top = NULL;
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 (is_between(win->x, win->x + win->width, x) && is_between(win->y, win->y + win->height, y)) {
if (window_top == NULL) {
window_top = win;
index_top = win->z;
} else {
if (win->z < index_top) continue;
window_top = win;
index_top = win->z;
}
}
}
}
return window_top;
}
window_t * top_at_fast(uint16_t x, uint16_t y) {
uint32_t index_top = 0;
window_t * window_top = NULL;
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 (is_top_fast(win, x, y)) return win;
}
}
return NULL;
}
window_t * absolute_top() {
uint32_t index_top = 0;
window_t * window_top = NULL;
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->z < index_top) continue;
window_top = win;
}
}
return window_top;
}
void make_top(window_t * window) {
uint16_t index = window->z;
if (index == 0) return;
if (index == 0xFFFF) return;
uint16_t highest = 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->z == 0) continue;
if (win->z == 0xFFFF) continue;
if (highest < win->z) highest = win->z;
if (win == window) continue;
if (win->z > window->z) win->z--;
}
}
window->z = highest;
}
window_t * focused_window() {
#if 0
return top_at_fast(mouse_x / MOUSE_SCALE, mouse_y / MOUSE_SCALE);
#else
return top_at(mouse_x / MOUSE_SCALE, mouse_y / MOUSE_SCALE);
#endif
}
volatile int am_drawing = 0;
window_t * moving_window = NULL;
int32_t moving_window_l = 0;
int32_t moving_window_t = 0;
/* Internal drawing functions */
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) {
/* XXX MAKE THIS FASTER */
if (is_top_fast(window, x, y)) {
if (TO_WINDOW_OFFSET(x,y) >= window->width * window->height) continue;
GFX(x,y) = ((uint32_t *)window->buffer)[TO_WINDOW_OFFSET(x,y)];
}
}
}
//redraw_region_slow(mouse_x / MOUSE_SCALE - 32, mouse_y / MOUSE_SCALE - 32, 64, 64);
//redraw_cursor();
}
void reorder_window (window_t * window, uint16_t new_zed) {
if (!window) {
return;
}
window->z = new_zed;
}
void redraw_full_window (window_t * window) {
if (!window) {
return;
}
redraw_window(window, (uint16_t)0, (uint16_t)0, window->width, window->height);
}
void redraw_region_slow(int32_t x, int32_t y, int32_t width, int32_t height) {
uint16_t _lo_x = max(x, 0);
uint16_t _hi_x = min(x + width, graphics_width);
uint16_t _lo_y = max(y, 0);
uint16_t _hi_y = min(y + height, graphics_height);
for (uint32_t y = _lo_y; y < _hi_y; ++y) {
for (uint32_t x = _lo_x; x < _hi_x; ++x) {
window_t * window = top_at(x,y);
if (window) {
//GFX(x,y) = ((uint32_t *)window->buffer)[TO_WINDOW_OFFSET(x,y)];
depth_map[x + y * graphics_width] = window->z;
top_map[x + y * graphics_width] = (uintptr_t)window;
} else {
//GFX(x,y) = (y % 2 ^ x % 2) ? rgb(0,0,0) : rgb(255,255,255);
depth_map[x + y * graphics_width] = 0;
top_map[x + y * graphics_width] = 0;
}
}
}
}
void redraw_everything_fast() {
for (uint32_t y = 0; y < graphics_height; ++y) {
for (uint32_t x = 0; x < graphics_width; ++x) {
window_t * window = (window_t *)top_map[x + y * graphics_width];
if (window) {
/* UGGGG */
if (TO_WINDOW_OFFSET(x,y) >= window->width * window->height) continue;
GFX(x,y) = ((uint32_t *)window->buffer)[TO_WINDOW_OFFSET(x,y)];
}
}
}
}
void draw_bounding_box(window_t * window, int32_t left, int32_t top) {
if (!window) return;
uint16_t _lo_x = max(left, 0);
uint16_t _hi_x = min(left + window->width, graphics_width);
uint16_t _lo_y = max(top, 0);
uint16_t _hi_y = min(top + window->height, graphics_height);
#define TO_DERPED_OFFSET(x,y) (((x) - left) + ((y) - top) * window->width)
for (uint16_t y = _lo_y; y < _hi_y; ++y) {
for (uint16_t x = _lo_x; x < _hi_x; ++x) {
/* XXX MAKE THIS FASTER */
//if (TO_DERPED_OFFSET(x,y) >= window->width * window->height) continue;
GFX(x,y) = alpha_blend(GFX(x,y), ((uint32_t *)window->buffer)[TO_DERPED_OFFSET(x,y)], rgb(127,0,0));
}
}
}
void redraw_bounding_box(window_t *window, int32_t left, int32_t top, uint32_t derped) {
return;
if (!window) {
return;
}
int32_t _min_x = max(left, 0);
int32_t _min_y = max(top, 0);
int32_t _max_x = min(left + window->width - 1, graphics_width - 1);
int32_t _max_y = min(top + window->height - 1, graphics_height - 1);
if (!derped) {
redraw_region_slow(_min_x, _min_y, (_max_x - _min_x + 1), 1);
redraw_region_slow(_min_x, _max_y, (_max_x - _min_x + 1), 1);
redraw_region_slow(_min_x, _min_y, 1, (_max_y - _min_y + 1));
redraw_region_slow(_max_x, _min_y, 1, (_max_y - _min_y + 1));
} else {
uint32_t color = rgb(255,0,0);
draw_line(_min_x, _max_x, _min_y, _min_y, color);
draw_line(_min_x, _max_x, _max_y, _max_y, color);
draw_line(_min_x, _min_x, _min_y, _max_y, color);
draw_line(_max_x, _max_x, _min_y, _max_y, color);
}
}
void redraw_bounding_box_r(window_t *window, int32_t width, int32_t height, uint32_t derped) {
return;
if (!window) {
return;
}
int32_t _min_x = max(window->x, 0);
int32_t _min_y = max(window->y, 0);
int32_t _max_x = min(window->x + width - 1, graphics_width - 1);
int32_t _max_y = min(window->y + height - 1, graphics_height - 1);
if (!derped) {
redraw_region_slow(_min_x, _min_y, (_max_x - _min_x + 1), 1);
redraw_region_slow(_min_x, _max_y, (_max_x - _min_x + 1), 1);
redraw_region_slow(_min_x, _min_y, 1, (_max_y - _min_y + 1));
redraw_region_slow(_max_x, _min_y, 1, (_max_y - _min_y + 1));
} else {
uint32_t color = rgb(0,255,0);
draw_line(_min_x, _max_x, _min_y, _min_y, color);
draw_line(_min_x, _max_x, _max_y, _max_y, color);
draw_line(_min_x, _min_x, _min_y, _max_y, color);
draw_line(_max_x, _max_x, _min_y, _max_y, color);
}
}
wid_t volatile _next_wid = 0;
void send_window_event (process_windows_t * pw, uint8_t event, w_window_t * packet) {
/* Construct the header */
wins_packet_t header;
header.magic = WINS_MAGIC;
header.command_type = event;
header.packet_size = sizeof(w_window_t);
/* Send them */
// XXX: we have a race condition here
write(pw->event_pipe, &header, sizeof(wins_packet_t));
write(pw->event_pipe, packet, sizeof(w_window_t));
syscall_send_signal(pw->pid, SIGWINEVENT); // SIGWINEVENT
syscall_yield();
}
void send_keyboard_event (process_windows_t * pw, uint8_t event, w_keyboard_t packet) {
/* Construct the header */
wins_packet_t header;
header.magic = WINS_MAGIC;
header.command_type = event;
header.packet_size = sizeof(w_keyboard_t);
/* Send them */
// XXX: we have a race condition here
write(pw->event_pipe, &header, sizeof(wins_packet_t));
write(pw->event_pipe, &packet, sizeof(w_keyboard_t));
syscall_send_signal(pw->pid, SIGWINEVENT); // SIGWINEVENT
}
void process_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);
int max_requests_per_cycle = 1;
while ((buf.st_size > 0) && (max_requests_per_cycle > 0)) {
#if 0
if (!(buf.st_size > sizeof(wins_packet_t))) {
fstat(pw->command_pipe, &buf);
continue;
}
#endif
w_window_t wwt;
wins_packet_t header;
printf("[compositor] read [%d] {\n", pw->pid);
int bytes_read = read(pw->command_pipe, &header, sizeof(wins_packet_t));
printf("[compositor] } read [%d] \n", pw->pid);
while (header.magic != WINS_MAGIC) {
printf("Magic is wrong from pid %d, expected 0x%x but got 0x%x [read %d bytes of %d]\n", pw->pid, WINS_MAGIC, header.magic, bytes_read, sizeof(header));
max_requests_per_cycle--;
goto bad_magic;
memcpy(&header, (void *)((uintptr_t)&header + 1), (sizeof(header) - 1));
read(pw->event_pipe, (char *)((uintptr_t)&header + sizeof(header) - 1), 1);
}
max_requests_per_cycle--;
switch (header.command_type) {
case WC_NEWWINDOW:
printf("[compositor] New window request\n");
read(pw->command_pipe, &wwt, sizeof(w_window_t));
wwt.wid = _next_wid;
init_window(pw, _next_wid, wwt.left, wwt.top, wwt.width, wwt.height, _next_wid); //XXX: an actual index
_next_wid++;
send_window_event(pw, WE_NEWWINDOW, &wwt);
redraw_region_slow(0,0,graphics_width,graphics_height);
break;
case WC_RESIZE:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
resize_window_buffer(get_window(wwt.wid), wwt.left, wwt.top, wwt.width, wwt.height);
send_window_event(pw, WE_RESIZED, &wwt);
break;
case WC_DESTROY:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
window_t * win = get_window_with_process(pw, wwt.wid);
win->x = 0xFFFF;
redraw_region_slow(0,0,graphics_width,graphics_height);
/* Wait until we're done drawing */
spin_lock(&am_drawing);
spin_unlock(&am_drawing);
free_window(win);
send_window_event(pw, WE_DESTROYED, &wwt);
break;
case WC_DAMAGE:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
//redraw_window(get_window_with_process(pw, wwt.wid), wwt.left, wwt.top, wwt.width, wwt.height);
break;
case WC_REDRAW:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
//redraw_window(get_window_with_process(pw, wwt.wid), wwt.left, wwt.top, wwt.width, wwt.height);
send_window_event(pw, WE_REDRAWN, &wwt);
break;
case WC_REORDER:
read(pw->command_pipe, &wwt, sizeof(w_window_t));
reorder_window(get_window_with_process(pw, wwt.wid), wwt.left);
redraw_region_slow(0,0,graphics_width,graphics_height);
break;
default:
printf("[compositor] WARN: Unknown command type %d...\n", header.command_type);
void * nullbuf = malloc(header.packet_size);
read(pw->command_pipe, nullbuf, header.packet_size);
free(nullbuf);
break;
}
bad_magic:
fstat(pw->command_pipe, &buf);
}
}
syscall_yield();
}
void waitabit() {
int x = time(NULL);
while (time(NULL) < x + 1) {
syscall_yield();
}
}
/* Request page system */
wins_server_global_t volatile * _request_page;
void reset_request_system () {
_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->server_pid = getpid();
_request_page->server_width = graphics_width;
_request_page->server_height = graphics_height;
_request_page->server_depth = graphics_depth;
_request_page->magic = WINS_MAGIC;
}
void init_request_system () {
size_t size = sizeof(wins_server_global_t);
_request_page = (wins_server_global_t *)syscall_shm_obtain(WINS_SERVER_IDENTIFIER, &size);
if (!_request_page) {
fprintf(stderr, "[wins] Could not get a shm block for its request page! Bailing...");
exit(-1);
}
reset_request_system();
}
void process_request () {
fflush(stdout);
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_done = 0;
_request_page->server_done = 1;
list_insert(process_list, pw);
}
if (!_request_page->lock) {
reset_request_system();
}
}
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 * ignore(void * value) {
return NULL;
}
void init_signal_handlers () {
#if 0
syscall_sys_signal(SIGWINEVENT, (uintptr_t)process_window_command); // SIGWINEVENT
#else
syscall_sys_signal(SIGWINEVENT, (uintptr_t)ignore); // SIGWINEVENT
#endif
}
/* Sprite stuff */
sprite_t alpha_tmp;
void init_sprite(int i, char * filename, char * alpha) {
sprites[i] = malloc(sizeof(sprite_t));
load_sprite(sprites[i], filename);
if (alpha) {
sprites[i]->alpha = 1;
load_sprite(&alpha_tmp, alpha);
sprites[i]->masks = alpha_tmp.bitmap;
} else {
sprites[i]->alpha = 0;
}
sprites[i]->blank = 0x0;
}
int center_x(int x) {
return (graphics_width - x) / 2;
}
int center_y(int y) {
return (graphics_height - y) / 2;
}
static int progress = 0;
static int progress_width = 0;
#define PROGRESS_WIDTH 120
#define PROGRESS_HEIGHT 6
#define PROGRESS_OFFSET 50
void draw_progress() {
int x = center_x(PROGRESS_WIDTH);
int y = center_y(0);
uint32_t color = rgb(0,120,230);
uint32_t fill = rgb(0,70,160);
draw_line(x, x + PROGRESS_WIDTH, y + PROGRESS_OFFSET, y + PROGRESS_OFFSET, color);
draw_line(x, x + PROGRESS_WIDTH, y + PROGRESS_OFFSET + PROGRESS_HEIGHT, y + PROGRESS_OFFSET + PROGRESS_HEIGHT, color);
draw_line(x, x, y + PROGRESS_OFFSET, y + PROGRESS_OFFSET + PROGRESS_HEIGHT, color);
draw_line(x + PROGRESS_WIDTH, x + PROGRESS_WIDTH, y + PROGRESS_OFFSET, y + PROGRESS_OFFSET + PROGRESS_HEIGHT, color);
if (progress_width > 0) {
int width = ((PROGRESS_WIDTH - 2) * progress) / progress_width;
for (int8_t i = 0; i < PROGRESS_HEIGHT - 1; ++i) {
draw_line(x + 1, x + 1 + width, y + PROGRESS_OFFSET + i + 1, y + PROGRESS_OFFSET + i + 1, fill);
}
}
}
uint32_t gradient_at(uint16_t j) {
float x = j * 80;
x = x / graphics_height;
return rgb(0, 1 * x, 2 * x);
}
void display() {
for (uint16_t j = 0; j < graphics_height; ++j) {
draw_line(0, graphics_width, j, j, gradient_at(j));
}
draw_sprite(sprites[0], center_x(sprites[0]->width), center_y(sprites[0]->height));
draw_progress();
flip();
}
typedef struct {
void (*func)();
char * name;
int time;
} startup_item;
list_t * startup_items;
void add_startup_item(char * name, void (*func)(), int time) {
progress_width += time;
startup_item * item = malloc(sizeof(startup_item));
item->name = name;
item->func = func;
item->time = time;
list_insert(startup_items, item);
}
static void test() {
/* Do Nothing */
}
void run_startup_item(startup_item * item) {
item->func();
progress += item->time;
}
FT_Library library;
FT_Face face;
FT_Face face_bold;
FT_Face face_italic;
FT_Face face_bold_italic;
FT_Face face_extra;
FT_GlyphSlot slot;
FT_UInt glyph_index;
char * loadMemFont(char * ident, char * name, size_t * size) {
FILE * f = fopen(name, "r");
size_t s = 0;
fseek(f, 0, SEEK_END);
s = ftell(f);
fseek(f, 0, SEEK_SET);
size_t shm_size = s;
char * font = (char *)syscall_shm_obtain(ident, &shm_size); //malloc(s);
assert((shm_size >= s) && "shm_obtain returned too little memory to load a font into!");
fread(font, s, 1, f);
fclose(f);
*size = s;
return font;
}
void _init_freetype() {
int error;
error = FT_Init_FreeType(&library);
}
#define FONT_SIZE 13
#define ACTUALLY_LOAD_FONTS 0
int error;
void _load_dejavu() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.sans-serif", "/usr/share/fonts/DejaVuSans.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face);
error = FT_Set_Pixel_Sizes(face, FONT_SIZE, FONT_SIZE);
#endif
}
void _load_dejavubold() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.sans-serif.bold", "/usr/share/fonts/DejaVuSans-Bold.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face_bold);
error = FT_Set_Pixel_Sizes(face_bold, FONT_SIZE, FONT_SIZE);
#endif
}
void _load_dejavuitalic() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.sans-serif.italic", "/usr/share/fonts/DejaVuSans-Oblique.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face_italic);
error = FT_Set_Pixel_Sizes(face_italic, FONT_SIZE, FONT_SIZE);
#endif
}
void _load_dejavubolditalic() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.sans-serif.bolditalic", "/usr/share/fonts/DejaVuSans-BoldOblique.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face_bold_italic);
error = FT_Set_Pixel_Sizes(face_bold_italic, FONT_SIZE, FONT_SIZE);
#endif
}
void _load_dejamonovu() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.monospace", "/usr/share/fonts/DejaVuSansMono.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face);
error = FT_Set_Pixel_Sizes(face, FONT_SIZE, FONT_SIZE);
#endif
}
void _load_dejamonovubold() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.monospace.bold", "/usr/share/fonts/DejaVuSansMono-Bold.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face_bold);
error = FT_Set_Pixel_Sizes(face_bold, FONT_SIZE, FONT_SIZE);
#endif
}
void _load_dejamonovuitalic() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.monospace.italic", "/usr/share/fonts/DejaVuSansMono-Oblique.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face_italic);
error = FT_Set_Pixel_Sizes(face_italic, FONT_SIZE, FONT_SIZE);
#endif
}
void _load_dejamonovubolditalic() {
char * font;
size_t s;
font = loadMemFont(WINS_SERVER_IDENTIFIER ".fonts.monospace.bolditalic", "/usr/share/fonts/DejaVuSansMono-BoldOblique.ttf", &s);
#if ACTUALLY_LOAD_FONTS
error = FT_New_Memory_Face(library, font, s, 0, &face_bold_italic);
error = FT_Set_Pixel_Sizes(face_bold_italic, FONT_SIZE, FONT_SIZE);
#endif
}
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();
list_insert(process_list, pw);
#if 1
/* Create the background window */
#if 0
window_t * root = init_window(pw, _next_wid++, 0, 0, graphics_width, graphics_height, 0);
window_draw_sprite(root, sprites[1], 0, 0);
redraw_full_window(root);
#endif
#if 0
/* Create the panel */
window_t * panel = init_window(pw, _next_wid++, 0, 0, graphics_width, 24, 0xFFFF);
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);
redraw_region_slow(0,0,graphics_width,graphics_height);
#endif
#endif
init_sprite(3, "/usr/share/arrow.bmp","/usr/share/arrow_alpha.bmp");
}
void * process_requests(void * garbage) {
int mfd = *((int *)garbage);
mouse_x = MOUSE_SCALE * graphics_width / 2;
mouse_y = MOUSE_SCALE * graphics_height / 2;
uint16_t _mouse_state = 0;
window_t * _mouse_window = NULL;
int32_t _mouse_init_x;
int32_t _mouse_init_y;
int32_t _mouse_win_x;
int32_t _mouse_win_y;
int32_t _mouse_win_x_p;
int32_t _mouse_win_y_p;
struct stat _stat;
char buf[1024];
while (1) {
fstat(mfd, &_stat);
while (_stat.st_size >= sizeof(mouse_device_packet_t)) {
mouse_device_packet_t * packet = (mouse_device_packet_t *)&buf;
int r = read(mfd, &buf, sizeof(mouse_device_packet_t));
#if 1
if (packet->magic != MOUSE_MAGIC) {
int r = read(mfd, buf, 1);
break;
}
//redraw_region_slow(mouse_x / MOUSE_SCALE - 32, mouse_y / MOUSE_SCALE - 32, 64, 64);
/* Apply mouse movement */
int c, l;
c = abs(packet->x_difference);
l = 0;
while (c >>= 1) {
l++;
}
mouse_x += packet->x_difference * l;
c = abs(packet->y_difference);
l = 0;
while (c >>= 1) {
l++;
}
mouse_y -= packet->y_difference * l;
if (mouse_x < 0) mouse_x = 0;
if (mouse_y < 0) mouse_y = 0;
if (mouse_x >= graphics_width * MOUSE_SCALE) mouse_x = (graphics_width) * MOUSE_SCALE;
if (mouse_y >= graphics_height * MOUSE_SCALE) mouse_y = (graphics_height) * MOUSE_SCALE;
//draw_sprite(sprites[3], mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X, mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y);
if (_mouse_state == 0 && (packet->buttons & MOUSE_BUTTON_RIGHT)) {
_mouse_window = focused_window();
if (_mouse_window) {
if (_mouse_window->z == 0 || _mouse_window->z == 0xFFFF) {
redraw_region_slow(0,0,graphics_width,graphics_height);
/* *sigh* */
} else {
_mouse_state = 1;
_mouse_init_x = mouse_x;
_mouse_init_y = mouse_y;
_mouse_win_x = _mouse_window->x;
_mouse_win_y = _mouse_window->y;
_mouse_win_x_p = _mouse_win_x;
_mouse_win_y_p = _mouse_win_y;
moving_window = _mouse_window;
moving_window_l = _mouse_win_x_p;
moving_window_t = _mouse_win_y_p;
make_top(_mouse_window);
redraw_region_slow(0,0,graphics_width,graphics_height);
}
}
} else if (_mouse_state == 0 && (packet->buttons & MOUSE_BUTTON_LEFT)) {
_mouse_window = focused_window();
if (_mouse_window) {
_mouse_state = 2; /* Dragging */
/* In window coordinates, that's... */
_mouse_win_x = _mouse_window->x;
_mouse_win_y = _mouse_window->y;
int32_t click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
int32_t click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
printf("Mouse down at @ %d,%d = %d,%d\n", mouse_x, mouse_y, click_x, click_y);
}
#if 0
_mouse_window = focused_window();
if (_mouse_window) {
if (_mouse_window->z == 0 || _mouse_window->z == 0xFFFF) {
} else {
_mouse_state = 2;
_mouse_init_x = mouse_x;
_mouse_init_y = mouse_y;
_mouse_win_x = _mouse_window->width;
_mouse_win_y = _mouse_window->height;
_mouse_win_x_p= _mouse_win_x;
_mouse_win_y_p= _mouse_win_y;
make_top(_mouse_window);
redraw_region_slow(0,0,graphics_width,graphics_height);
}
}
#endif
} else if (_mouse_state == 1) {
if (!(packet->buttons & MOUSE_BUTTON_RIGHT)) {
_mouse_window->x = _mouse_win_x + (mouse_x - _mouse_init_x) / MOUSE_SCALE;
_mouse_window->y = _mouse_win_y + (mouse_y - _mouse_init_y) / MOUSE_SCALE;
moving_window = NULL;
redraw_region_slow(0,0,graphics_width,graphics_height);
_mouse_state = 0;
} else {
redraw_bounding_box(_mouse_window, _mouse_win_x_p, _mouse_win_y_p, 0);
_mouse_win_x_p = _mouse_win_x + (mouse_x - _mouse_init_x) / MOUSE_SCALE;
_mouse_win_y_p = _mouse_win_y + (mouse_y - _mouse_init_y) / MOUSE_SCALE;
moving_window = _mouse_window;
moving_window_l = _mouse_win_x_p;
moving_window_t = _mouse_win_y_p;
redraw_bounding_box(_mouse_window, _mouse_win_x_p, _mouse_win_y_p, 1);
}
} else if (_mouse_state == 2) {
if (!(packet->buttons & MOUSE_BUTTON_LEFT)) {
/* Released */
_mouse_state = 0;
_mouse_win_x = _mouse_window->x;
_mouse_win_y = _mouse_window->y;
int32_t click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
int32_t click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
printf("Mouse up at @ %d,%d = %d,%d\n", mouse_x, mouse_y, click_x, click_y);
#if 0 /* Resizing */
_mouse_win_x_p = _mouse_win_x + (mouse_x - _mouse_init_x) / MOUSE_SCALE;
_mouse_win_y_p = _mouse_win_y + (mouse_y - _mouse_init_y) / MOUSE_SCALE;
if (_mouse_win_x_p < 10) _mouse_win_x_p = 10;
if (_mouse_win_y_p < 10) _mouse_win_y_p = 10;
printf("resizing window to %d x %d\n", _mouse_win_x_p, _mouse_win_y_p);
resize_window_buffer(_mouse_window, _mouse_window->x, _mouse_window->y, _mouse_win_x_p, _mouse_win_y_p);
w_window_t tmp;
tmp.left = _mouse_window->x;
tmp.top = _mouse_window->y;
tmp.wid = _mouse_window->wid;
tmp.width = _mouse_win_x_p;
tmp.height = _mouse_win_y_p;
send_window_event(_mouse_window->owner, WE_RESIZED, &tmp);
redraw_region_slow(0,0,graphics_width,graphics_height);
_mouse_state = 0;
#endif
} else {
/* Still down */
_mouse_win_x = _mouse_window->x;
_mouse_win_y = _mouse_window->y;
int32_t click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
int32_t click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
printf("Mouse move to @ %d,%d = %d,%d\n", mouse_x, mouse_y, click_x, click_y);
#if 0
redraw_bounding_box_r(_mouse_window, _mouse_win_x_p, _mouse_win_y_p, 0);
_mouse_win_x_p = _mouse_win_x + (mouse_x - _mouse_init_x) / MOUSE_SCALE;
_mouse_win_y_p = _mouse_win_y + (mouse_y - _mouse_init_y) / MOUSE_SCALE;
if (_mouse_win_x_p < 10) _mouse_win_x_p = 10;
if (_mouse_win_y_p < 10) _mouse_win_y_p = 10;
redraw_bounding_box_r(_mouse_window, _mouse_win_x_p, _mouse_win_y_p, 1);
#endif
}
}
#if 1
if (packet->buttons & MOUSE_BUTTON_MIDDLE) {
printf("middle click @%dx%d!\n", mouse_x / MOUSE_SCALE, mouse_y / MOUSE_SCALE);
window_t * focused = focused_window();
if (focused) {
if (focused->z != 0 && focused->z != 0xFFFF) {
free_window(focused);
}
redraw_region_slow(0,0,graphics_width,graphics_height);
}
}
#endif
#endif
fstat(mfd, &_stat);
}
fstat(0, &_stat);
if (_stat.st_size) {
int r = read(0, buf, 1);
if (r > 0) {
w_keyboard_t packet;
window_t * focused = focused_window();
if (focused) {
packet.wid = focused->wid;
packet.command = 0;
packet.key = (uint16_t)buf[0];
send_keyboard_event(focused->owner, WE_KEYDOWN, packet);
}
}
}
}
return NULL;
}
void * redraw_thread(void * derp) {
while (1) {
spin_lock(&am_drawing);
redraw_everything_fast();
/* Other stuff */
draw_bounding_box(moving_window, moving_window_l, moving_window_t);
redraw_cursor();
spin_unlock(&am_drawing);
flip();
syscall_yield();
}
}
int main(int argc, char ** argv) {
/* Initialize graphics setup */
init_graphics_double_buffer();
depth_map = malloc(sizeof(uint16_t) * graphics_width * graphics_height);
top_map = malloc(sizeof(uintptr_t) * graphics_width * graphics_height);
/* 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();
/* Count startup items */
startup_items = list_create();
add_startup_item("Initializing FreeType", _init_freetype, 1);
#if 1
add_startup_item("Loading font: Deja Vu Sans", _load_dejavu, 2);
add_startup_item("Loading font: Deja Vu Sans Bold", _load_dejavubold, 2);
add_startup_item("Loading font: Deja Vu Sans Oblique", _load_dejavuitalic, 2);
add_startup_item("Loading font: Deja Vu Sans Bold+Oblique", _load_dejavubolditalic, 2);
add_startup_item("Loading font: Deja Vu Sans Mono", _load_dejamonovu, 2);
add_startup_item("Loading font: Deja Vu Sans Mono Bold", _load_dejamonovubold, 2);
add_startup_item("Loading font: Deja Vu Sans Mono Oblique", _load_dejamonovuitalic, 2);
add_startup_item("Loading font: Deja Vu Sans Mono Bold+Oblique", _load_dejamonovubolditalic, 2);
#endif
foreach(node, startup_items) {
run_startup_item((startup_item *)node->value);
display();
}
#if 0
/* Reinitialize for single buffering */
init_graphics();
#endif
/* Create the root and panel */
init_base_windows();
process_windows_t * rootpw = get_process_windows(getpid());
if (!rootpw) {
printf("[compositor] SEVERE: No root process windows!\n");
return 1;
}
/* Grab the mouse */
int mfd = syscall_mousedevice();
pthread_t input_thread;
pthread_create(&input_thread, NULL, process_requests, (void *)&mfd);
pthread_t redraw_everything_thread;
pthread_create(&redraw_everything_thread, NULL, redraw_thread, NULL);
#if 0
if (!fork()) {
waitabit();
waitabit();
waitabit();
char * args[] = {"/bin/drawlines", "100","100","300","300",NULL};
execve(args[0], args, NULL);
}
if (!fork()) {
waitabit();
char * args[] = {"/bin/julia-win", "200","200","400","400",NULL};
execve(args[0], args, NULL);
}
if (!fork()) {
waitabit();
waitabit();
char * args[] = {"/bin/julia-win", "20","20","500","300",NULL};
execve(args[0], args, NULL);
}
#else
if (!fork()) {
char * args[] = {"/bin/wallpaper", NULL};
execve(args[0], args, NULL);
}
if (!fork()) {
char * args[] = {"/bin/panel", NULL};
execve(args[0], args, NULL);
}
#if 0
if (!fork()) {
char arg_width[10], arg_height[10];
sprintf(arg_width, "%d", graphics_width);
sprintf(arg_height, "%d", graphics_height);
char * args[] = {"/bin/glogin", arg_width, arg_height, NULL};
execve(args[0], args, NULL);
}
#else
#if 0
if (!fork()) {
waitabit();
char * args[] = {"/bin/julia-win", "200","400","400","400",NULL};
execve(args[0], args, NULL);
}
#endif
if (!fork()) {
char * args[] = {"/bin/terminal", NULL};
execve(args[0], args, NULL);
}
#endif
#endif
/* Sit in a run loop */
while (1) {
process_request();
process_window_command(0);
syscall_yield();
}
// XXX: Better have SIGINT/SIGSTOP handlers
return 0;
}