From a3384aac9e6ac68f4bc69a7f4afd8f2c40614431 Mon Sep 17 00:00:00 2001 From: Markus Schober Date: Fri, 10 Feb 2012 23:26:30 -0600 Subject: [PATCH] The new compositor is armed and (almost) fully operational! --- userspace/compositor.c | 403 ++++++++++++++++++++++++++++++------ userspace/lib/compositing.c | 5 +- userspace/lib/compositing.h | 9 +- 3 files changed, 346 insertions(+), 71 deletions(-) diff --git a/userspace/compositor.c b/userspace/compositor.c index 67f7a3af..7167014b 100644 --- a/userspace/compositor.c +++ b/userspace/compositor.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include FT_FREETYPE_H @@ -16,15 +17,28 @@ #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,64 +636,33 @@ int main(int argc, char ** argv) { init_graphics(); #endif - window_list = list_create(); + /* Create the root and panel */ + init_base_windows(); - 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); - - 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); @@ -404,6 +670,5 @@ int main(int argc, char ** argv) { #endif } - return 0; } diff --git a/userspace/lib/compositing.c b/userspace/lib/compositing.c index b72b4058..03b98042 100644 --- a/userspace/lib/compositing.c +++ b/userspace/lib/compositing.c @@ -7,6 +7,7 @@ #include #include #include + #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 */ diff --git a/userspace/lib/compositing.h b/userspace/lib/compositing.h index 4331f3b8..fd8d0fc6 100644 --- a/userspace/lib/compositing.h +++ b/userspace/lib/compositing.h @@ -9,21 +9,25 @@ #include 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