toaruos/userspace/compositor.c
Kevin Lange ac52d41144 Unicode Text Support
* Some applications now support UTF-8 text through the use of a very
  simple decoder.
* The terminal uses a slow, but accurate method to determine the width
  of a character the first time it is printed to the screen. Characters
  are now stored in the terminal in two bytes, rather than one, and may
  in the future be increased to 3 or 4 bytes to ensure support for
  Unicode supplemental planes.
* A simple font-fallback method is employed in the applications that
  support unicode that will make use of the VL Gothic fonts if the
  DejaVu font does not have a character. No guarantees are made for
  support of writing systems other than extended Latin and Japanese.
2012-09-05 20:19:52 -07:00

1251 lines
34 KiB
C

/*
* Compositor
*
* This is the window compositor application.
* It serves shared memory regions to clients
* and renders them to the screen.
*/
#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 "lib/pthread.h"
#include "../kernel/include/signal.h"
#include "../kernel/include/mouse.h"
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);
}
sprite_t * sprites[128];
gfx_context_t * ctx;
#define WIN_D 32
#define WIN_B (WIN_D / 8)
#define MOUSE_DISCARD_LEVEL 6
list_t * process_list;
int32_t mouse_x, mouse_y;
int32_t click_x, click_y;
uint32_t mouse_discard = 0;
#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(ctx, 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 >= ctx->width || y >= ctx->height) {
return 0;
}
if (window->z == depth_map[x + y * ctx->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, ctx->width);
uint16_t _lo_y = max(window->y + y, 0);
uint16_t _hi_y = min(window->y + height, ctx->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(ctx,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, ctx->width);
uint16_t _lo_y = max(y, 0);
uint16_t _hi_y = min(y + height, ctx->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(ctx,x,y) = ((uint32_t *)window->buffer)[TO_WINDOW_OFFSET(x,y)];
depth_map[x + y * ctx->width] = window->z;
top_map[x + y * ctx->width] = (uintptr_t)window;
} else {
//GFX(ctx,x,y) = (y % 2 ^ x % 2) ? rgb(0,0,0) : rgb(255,255,255);
depth_map[x + y * ctx->width] = 0;
top_map[x + y * ctx->width] = 0;
}
}
}
}
void redraw_everything_fast() {
for (uint32_t y = 0; y < ctx->height; ++y) {
for (uint32_t x = 0; x < ctx->width; ++x) {
window_t * window = (window_t *)top_map[x + y * ctx->width];
if (window) {
/* UGGGG */
if (TO_WINDOW_OFFSET(x,y) >= window->width * window->height) continue;
GFX(ctx,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, ctx->width);
uint16_t _lo_y = max(top, 0);
uint16_t _hi_y = min(top + window->height, ctx->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) {
GFX(ctx,x,y) = alpha_blend(GFX(ctx,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, ctx->width - 1);
int32_t _max_y = min(top + window->height - 1, ctx->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(ctx, _min_x, _max_x, _min_y, _min_y, color);
draw_line(ctx, _min_x, _max_x, _max_y, _max_y, color);
draw_line(ctx, _min_x, _min_x, _min_y, _max_y, color);
draw_line(ctx, _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, ctx->width - 1);
int32_t _max_y = min(window->y + height - 1, ctx->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(ctx, _min_x, _max_x, _min_y, _min_y, color);
draw_line(ctx, _min_x, _max_x, _max_y, _max_y, color);
draw_line(ctx, _min_x, _min_x, _min_y, _max_y, color);
draw_line(ctx, _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
syscall_yield();
}
FILE *fdopen(int fd, const char *mode);
void send_mouse_event (process_windows_t * pw, uint8_t event, w_mouse_t * packet) {
/* Construct the header */
wins_packet_t header;
header.magic = WINS_MAGIC;
header.command_type = event;
header.packet_size = sizeof(w_mouse_t);
/* Send them */
fwrite(&header, 1, sizeof(wins_packet_t), pw->event_pipe_file);
fwrite(packet, 1, sizeof(w_mouse_t), pw->event_pipe_file);
fflush(pw->event_pipe_file);
//syscall_send_signal(pw->pid, SIGWINEVENT); // SIGWINEVENT
//syscall_yield();
}
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;
int bytes_read = read(pw->command_pipe, &header, sizeof(wins_packet_t));
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,ctx->width,ctx->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,ctx->width,ctx->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,ctx->width,ctx->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 = ctx->width;
_request_page->server_height = ctx->height;
_request_page->server_depth = ctx->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->event_pipe_file = fdopen(pw->event_pipe, "a");
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_signal(SIGWINEVENT, process_window_command); // SIGWINEVENT
#else
syscall_signal(SIGWINEVENT, 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 (ctx->width - x) / 2;
}
int center_y(int y) {
return (ctx->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(ctx, x, x + PROGRESS_WIDTH, y + PROGRESS_OFFSET, y + PROGRESS_OFFSET, color);
draw_line(ctx, x, x + PROGRESS_WIDTH, y + PROGRESS_OFFSET + PROGRESS_HEIGHT, y + PROGRESS_OFFSET + PROGRESS_HEIGHT, color);
draw_line(ctx, x, x, y + PROGRESS_OFFSET, y + PROGRESS_OFFSET + PROGRESS_HEIGHT, color);
draw_line(ctx, 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(ctx, 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 / ctx->height;
return rgb(0, 1 * x, 2 * x);
}
void display() {
for (uint16_t j = 0; j < ctx->height; ++j) {
draw_line(ctx, 0, ctx->width, j, j, gradient_at(j));
}
draw_sprite(ctx, sprites[0], center_x(sprites[0]->width), center_y(sprites[0]->height));
draw_progress();
flip(ctx);
}
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, ctx->width, ctx->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, ctx->width, 24, 0xFFFF);
window_fill(panel, rgb(0,120,230));
init_sprite(2, "/usr/share/panel.bmp", NULL);
for (uint32_t i = 0; i < ctx->width; i += sprites[2]->width) {
window_draw_sprite(panel, sprites[2], i, 0);
}
redraw_full_window(panel);
redraw_region_slow(0,0,ctx->width,ctx->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 * ctx->width / 2;
mouse_y = MOUSE_SCALE * ctx->height / 2;
click_x = 0;
click_y = 0;
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;
int8_t _mouse_moved = 0;
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 >= ctx->width * MOUSE_SCALE) mouse_x = (ctx->width) * MOUSE_SCALE;
if (mouse_y >= ctx->height * MOUSE_SCALE) mouse_y = (ctx->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,ctx->width,ctx->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,ctx->width,ctx->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;
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
mouse_discard = 1;
_mouse_moved = 0;
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,ctx->width,ctx->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,ctx->width,ctx->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;
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
if (!_mouse_moved) {
printf("Finished a click!\n");
w_mouse_t _packet;
_packet.wid = _mouse_window->wid;
_mouse_win_x = _mouse_window->x;
_mouse_win_y = _mouse_window->y;
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
_packet.new_x = click_x;
_packet.new_y = click_y;
_packet.old_x = -1;
_packet.old_y = -1;
_packet.buttons = packet->buttons;
_packet.command = WE_MOUSECLICK;
send_mouse_event(_mouse_window->owner, WE_MOUSEMOVE, &_packet);
}
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,ctx->width,ctx->height);
_mouse_state = 0;
#endif
} else {
/* Still down */
_mouse_moved = 1;
mouse_discard--;
if (mouse_discard < 1) {
mouse_discard = MOUSE_DISCARD_LEVEL;
w_mouse_t _packet;
_packet.wid = _mouse_window->wid;
_mouse_win_x = _mouse_window->x;
_mouse_win_y = _mouse_window->y;
_packet.old_x = click_x;
_packet.old_y = click_y;
click_x = mouse_x / MOUSE_SCALE - _mouse_win_x;
click_y = mouse_y / MOUSE_SCALE - _mouse_win_y;
_packet.new_x = click_x;
_packet.new_y = click_y;
_packet.buttons = packet->buttons;
_packet.command = WE_MOUSEMOVE;
send_mouse_event(_mouse_window->owner, WE_MOUSEMOVE, &_packet);
}
#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,ctx->width,ctx->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(ctx);
syscall_yield();
}
}
int main(int argc, char ** argv) {
/* Initialize graphics setup */
ctx = init_graphics_fullscreen_double_buffer();
depth_map = malloc(sizeof(uint16_t) * ctx->width * ctx->height);
top_map = malloc(sizeof(uintptr_t) * ctx->width * ctx->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", ctx->width);
sprintf(arg_height, "%d", ctx->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;
}