summaryrefslogtreecommitdiff
path: root/userland/windowserver
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-03-25 14:41:22 +0100
committerAnton Kling <anton@kling.gg>2024-03-25 17:56:47 +0100
commit6baa733f5682f660143c851a635a53dc2c2df7ae (patch)
treea3026692cac900d4ba54556f09a8f8ba08091437 /userland/windowserver
parent1217ad6470585cd57c17eaec020598457cd89230 (diff)
WindowServer: Add focus, minimize support
Diffstat (limited to 'userland/windowserver')
-rw-r--r--userland/windowserver/draw.c130
-rw-r--r--userland/windowserver/draw.h17
-rw-r--r--userland/windowserver/ws.c346
-rw-r--r--userland/windowserver/ws.h6
4 files changed, 326 insertions, 173 deletions
diff --git a/userland/windowserver/draw.c b/userland/windowserver/draw.c
index 1e02d0d..190707d 100644
--- a/userland/windowserver/draw.c
+++ b/userland/windowserver/draw.c
@@ -1,42 +1,7 @@
#include "draw.h"
+#include <math.h>
#include <string.h>
-#define place_pixel(_p, _w, _h) \
- { \
- *(uint32_t *)(disp->back_buffer + disp->bpp * (_w) + \
- (disp->width * disp->bpp * (_h))) = _p; \
- }
-
-#define place_pixel_pos(_p, _pos) \
- { *(uint32_t *)(disp->back_buffer + disp->bpp * (_pos)) = _p; }
-
-int mx;
-int my;
-
-void update_display(const DISPLAY *disp) {
- for (int i = 0; i < 20; i++) {
- uint32_t color = 0xFFFFFFFF;
- // Make every other pixel black to make the mouse more visible on all
- // backgrounds.
- if (i & 1) {
- color = 0x0;
- }
- place_pixel(color, mx + i, my + i);
- if (i <= 10) {
- place_pixel(color, mx, my + i);
- place_pixel(color, mx + i, my);
- }
- }
- uint32_t *dst = disp->true_buffer;
- uint32_t *src = disp->back_buffer;
- const uint32_t n = disp->size / disp->bpp;
- for (int i = 0; i < n; i++) {
- *dst = *src;
- dst++;
- src++;
- }
-}
-
void draw_wallpaper(const DISPLAY *disp) {
uint32_t *dst = disp->back_buffer;
uint32_t *src = disp->wallpaper_buffer;
@@ -48,10 +13,17 @@ void draw_wallpaper(const DISPLAY *disp) {
}
}
-void draw_mouse(DISPLAY *disp, int mouse_x, int mouse_y) {
- mx = mouse_x;
- my = mouse_y;
- update_full_display(disp, mouse_x, mouse_y);
+void draw_outline(DISPLAY *disp, int x, int y, int sx, int sy, int border_px,
+ uint32_t color) {
+ // Top
+ draw_rectangle(disp, x, y, sx + border_px, border_px, color);
+ // Bottom
+ draw_rectangle(disp, x, y + sy+border_px, sx + border_px, border_px, color);
+ // Left
+ draw_rectangle(disp, x, y, border_px, sy + border_px * 2, color);
+ // Right
+ draw_rectangle(disp, x + sx + border_px, y, border_px, sy + border_px * 2,
+ color);
}
void draw_line(DISPLAY *disp, int sx, int sy, int dx, int dy, uint32_t color) {
@@ -62,77 +34,33 @@ void draw_line(DISPLAY *disp, int sx, int sy, int dx, int dy, uint32_t color) {
if (y * disp->width + x > disp->height * disp->width)
break;
- if (x >= dx - 1 && y >= dy - 1)
+ if (x >= dx - 1 && y >= dy - 1) {
break;
+ }
uint32_t *ptr =
disp->back_buffer + (disp->bpp * y * disp->width) + (x * disp->bpp);
*ptr = color;
- if (x < dx - 1)
+ if (x < dx - 1) {
x++;
- if (y < dy - 1)
+ }
+ if (y < dy - 1) {
y++;
+ }
}
}
-void draw_window(DISPLAY *disp, const WINDOW *w) {
- int x, y;
- uint8_t border_size = disp->border_size;
- const int px = w->x + border_size;
- const int py = w->y;
- const int sx = w->sx;
- const int sy = w->sy;
- const int b_sx = w->buffer_sx;
- const int b_sy = w->buffer_sy;
- x = px;
- y = py;
- // Draw a border around the current selected window
- if (w == disp->active_window) {
- // Top
- draw_line(disp, px - 1, py - 1, px + sx + 1, py - 1, 0xFF00FF);
- // Bottom
- draw_line(disp, px - 1, py + sy, px + sx + 1, py + sy, 0xFF00FF);
- // Left
- draw_line(disp, px - 1, py - 1, px - 1, py + sy + 1, 0xFF00FF);
- // Right
- draw_line(disp, px + sx, py - 1, px + sx, py + sy + 1, 0xFF00FF);
- }
-
- for (int i = 0; i < sy; i++) {
- if ((i + py) * disp->width + px > disp->height * disp->width)
- break;
- uint32_t *ptr = disp->back_buffer + disp->bpp * ((i + py) * disp->width) +
- px * disp->bpp;
- if (i * sx > disp->height * disp->width)
- break;
- if (i < b_sy) {
- uint32_t *bm = &w->bitmap_ptr[i * b_sx];
- int j = 0;
- for (; j < b_sx && j < sx; j++) {
- ptr[j] = bm[j];
- }
- for (; j < sx; j++) {
- ptr[j] = 0;
+void draw_rectangle(DISPLAY *disp, int x, int y, int sx, int sy,
+ uint32_t color) {
+ for (int i = y; i < y + sy; i++) {
+ for (int j = x; j < x + sx; j++) {
+ // Bounds checking
+ if (i * disp->width + j > disp->height * disp->width) {
+ break;
}
- } else {
- for (int j = 0; j < sx; j++) {
- ptr[j] = 0;
- }
- }
- }
-}
-void update_active_window(DISPLAY *disp) {
- for (int i = 0; i < 100; i++) {
- if (!disp->windows[i])
- continue;
- if (!disp->windows[i]->bitmap_ptr)
- continue;
- draw_window(disp, disp->windows[i]);
+ uint32_t *ptr =
+ disp->back_buffer + (disp->bpp * i * disp->width) + (j * disp->bpp);
+ *ptr = color;
+ }
}
}
-
-void update_full_display(DISPLAY *disp, int mouse_x, int mouse_y) {
- draw_wallpaper(disp);
- update_active_window(disp);
- update_display(disp);
-}
diff --git a/userland/windowserver/draw.h b/userland/windowserver/draw.h
index db5f6ee..fe78bc1 100644
--- a/userland/windowserver/draw.h
+++ b/userland/windowserver/draw.h
@@ -2,9 +2,18 @@
#define DRAW_H
#include "ws.h"
+#define place_pixel(_p, _w, _h) \
+ { \
+ *(uint32_t *)(disp->back_buffer + disp->bpp * (_w) + \
+ (disp->width * disp->bpp * (_h))) = _p; \
+ }
+
+#define place_pixel_pos(_p, _pos) \
+ { *(uint32_t *)(disp->back_buffer + disp->bpp * (_pos)) = _p; }
+
+void draw_line(DISPLAY *disp, int sx, int sy, int dx, int dy, uint32_t color);
void draw_wallpaper(const DISPLAY *disp);
-void draw_window(DISPLAY *disp, const WINDOW *w);
-void update_full_display(DISPLAY *disp, int mouse_x, int mouse_y);
-void update_active_window(DISPLAY *disp);
-void draw_mouse(DISPLAY *disp, int mouse_x, int mouse_y);
+void draw_rectangle(DISPLAY *disp, int x, int y, int sx, int sy,
+ uint32_t color);
+void draw_outline(DISPLAY *disp, int x, int y, int sx, int sy, int border_px, uint32_t color);
#endif
diff --git a/userland/windowserver/ws.c b/userland/windowserver/ws.c
index a4f5a59..ceb4f64 100644
--- a/userland/windowserver/ws.c
+++ b/userland/windowserver/ws.c
@@ -7,6 +7,7 @@
#include <socket.h>
#include <stddef.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
@@ -14,10 +15,16 @@
#define WINDOW_SERVER_SOCKET "/windowserver"
-WINDOW *windows[100];
+WINDOW *window;
int mouse_x = 0;
int mouse_y = 0;
+int mouse_down = 0;
+int mouse_up = 0;
+int active_id = -1;
+
+int ui_id = 0;
+int ui_state = 0;
DISPLAY main_display;
@@ -28,6 +35,8 @@ uint64_t socket_fd_poll;
uint64_t keyboard_fd_poll;
uint64_t mouse_fd_poll;
+void draw(void);
+
// Taken from drivers/keyboard.c
struct KEY_EVENT {
char c;
@@ -50,6 +59,12 @@ int create_socket(void) {
return fd;
}
+int next_ui_id(void) {
+ int r = ui_id;
+ ui_id++;
+ return r;
+}
+
void setup_display(DISPLAY *disp, const char *path, uint64_t size) {
disp->wallpaper_color = 0x3;
disp->size = size;
@@ -61,7 +76,7 @@ void setup_display(DISPLAY *disp, const char *path, uint64_t size) {
}
disp->true_buffer = mmap(NULL, size, 0, 0, disp->vga_fd, 0);
disp->back_buffer = malloc(size + 0x1000);
- disp->windows = windows;
+ disp->window = window;
disp->wallpaper_fd = shm_open("wallpaper", O_RDWR, 0);
assert(disp->wallpaper_fd >= 0);
@@ -100,13 +115,10 @@ void setup(void) {
main_display.border_size = 1;
main_display.border_color = 0xF;
main_display.active_window = NULL;
- for (int i = 0; i < 100; i++) {
- windows[i] = NULL;
- }
+ main_display.window = NULL;
num_fds = 100;
- fds = malloc(sizeof(struct pollfd[num_fds]));
- memset(fds, 0, sizeof(struct pollfd[num_fds]));
+ fds = calloc(num_fds, sizeof(struct pollfd));
for (size_t i = 0; i < num_fds; i++)
fds[i].fd = -1;
// Create socket
@@ -150,15 +162,19 @@ void add_fd(int fd) {
void add_window(int fd) {
int window_socket = accept(fd, NULL, NULL);
add_fd(window_socket);
- int i;
- for (i = 0; i < 100; i++)
- if (!windows[i])
- break;
- printf("adding window: %d\n", i);
- WINDOW *w = windows[i] = malloc(sizeof(WINDOW));
+ WINDOW *w = calloc(sizeof(WINDOW), 1);
w->fd = window_socket;
- w->bitmap_ptr = NULL;
main_display.active_window = w;
+ if (NULL == main_display.window) {
+ assert(NULL == main_display.window_tail);
+ main_display.window = w;
+ main_display.window_tail = w;
+ } else {
+ w->next = main_display.window;
+ assert(NULL == main_display.window->prev);
+ main_display.window->prev = w;
+ main_display.window = w;
+ }
}
#define CLIENT_EVENT_CREATESCREEN 0
@@ -184,11 +200,10 @@ typedef struct {
void parse_window_event(WINDOW *w) {
uint8_t event_type;
if (0 == read(w->fd, &event_type, sizeof(uint8_t))) {
- printf("empty\n");
return;
}
if (0 == event_type) {
- update_full_display(&main_display, mouse_x, mouse_y);
+ draw();
return;
}
if (1 == event_type) {
@@ -200,7 +215,7 @@ void parse_window_event(WINDOW *w) {
bitmap_name[e.name_len] = '\0';
int bitmap_fd = shm_open(bitmap_name, O_RDWR, O_CREAT);
create_window(w, bitmap_fd, e.px, e.py, e.sx, e.sy);
- update_full_display(&main_display, mouse_x, mouse_y);
+ draw();
}
}
@@ -232,16 +247,20 @@ void clamp_screen_position(int *x, int *y) {
}
}
+void send_kill_window(WINDOW *w) {
+ WS_EVENT e = {
+ .type = WINDOWSERVER_EVENT_WINDOW_EXIT,
+ };
+ write(w->fd, &e, sizeof(e));
+}
+
int windowserver_key_events(struct KEY_EVENT ev, int *redraw) {
if (ev.release)
return 0;
if (!(ev.mode & (1 << 1)))
return 0;
if ('q' == ev.c) {
- WS_EVENT e = {
- .type = WINDOWSERVER_EVENT_WINDOW_EXIT,
- };
- write(main_display.active_window->fd, &e, sizeof(e));
+ send_kill_window(main_display.active_window);
return 1;
}
if ('n' == ev.c) {
@@ -290,24 +309,6 @@ struct mouse_event {
uint8_t y;
};
-void update_mouse(void) {
- draw_mouse(&main_display, mouse_x, mouse_y);
- return;
-}
-
-void focus_window(int x, int y) {
- for (int i = 0; i < 100; i++) {
- if (!windows[i])
- continue;
- WINDOW *w = windows[i];
- if (w->x < x && x < w->x + w->sx) {
- if (w->y < y && y < w->y + w->sy) {
- main_display.active_window = windows[i];
- }
- }
- }
-}
-
void parse_mouse_event(int fd) {
int16_t xc = 0;
int16_t yc = 0;
@@ -339,13 +340,18 @@ void parse_mouse_event(int fd) {
}
mouse_x += xc;
mouse_y -= yc;
- if (mouse_x < 0)
+ if (mouse_x < 0) {
mouse_x = 0;
- if (mouse_y < 0)
+ }
+ if (mouse_y < 0) {
mouse_y = 0;
- if (left_button) {
- focus_window(mouse_x, mouse_y);
}
+ if (mouse_down && !left_button) {
+ mouse_up = 1;
+ } else {
+ mouse_up = 0;
+ }
+ mouse_down = left_button;
if (middle_button) {
if (main_display.active_window) {
main_display.active_window->x += xc;
@@ -360,7 +366,7 @@ void parse_mouse_event(int fd) {
main_display.active_window->sy -= yc;
}
}
- update_mouse();
+ draw();
}
void parse_keyboard_event(int fd) {
@@ -372,40 +378,53 @@ void parse_keyboard_event(int fd) {
break;
int n = rc / sizeof(ev[0]);
for (int i = 0; i < n; i++) {
- if (windowserver_key_events(ev[i], &redraw))
+ if (windowserver_key_events(ev[i], &redraw)) {
continue;
- if (!main_display.active_window)
+ }
+ if (!main_display.active_window) {
continue;
+ }
send_key_event_to_window(ev[i]);
}
}
- if (redraw)
- update_full_display(&main_display, mouse_x, mouse_y);
+ if (redraw) {
+ draw();
+ }
}
-WINDOW *get_window(int fd, int *index) {
- for (int i = 0; i < 100; i++) {
- if (!windows[i])
- continue;
- if (windows[i]->fd == fd) {
- if (index)
- *index = i;
- return windows[i];
+WINDOW *get_window(int fd) {
+ WINDOW *w = main_display.window;
+ for (; w; w = w->next) {
+ if (fd == w->fd) {
+ return w;
}
}
return NULL;
}
-void kill_window(int i) {
- windows[i] = NULL;
- update_full_display(&main_display, mouse_x, mouse_y);
- main_display.active_window = NULL;
- for (int i = 0; i < 100; i++) {
- if (windows[i]) {
- main_display.active_window = windows[i];
- break;
+void kill_window(WINDOW *w) {
+ WINDOW *prev = w->prev;
+ if (prev) {
+ assert(prev->next == w);
+ WINDOW *next_window = w->next;
+ prev->next = next_window;
+ if (next_window) {
+ next_window->prev = prev;
+ }
+ } else {
+ assert(w = main_display.window);
+ main_display.window = w->next;
+ if (main_display.window) {
+ main_display.window->prev = NULL;
}
+ main_display.active_window = NULL;
}
+
+ if (w == main_display.window_tail) {
+ assert(NULL == w->next);
+ main_display.window_tail = prev;
+ }
+ free(w);
}
void parse_revents(struct pollfd *fds, size_t s) {
@@ -424,11 +443,10 @@ void parse_revents(struct pollfd *fds, size_t s) {
parse_mouse_event(fds[i].fd);
continue;
}
- int index;
- WINDOW *w = get_window(fds[i].fd, &index);
+ WINDOW *w = get_window(fds[i].fd);
assert(w);
if (fds[i].revents & POLLHUP) {
- kill_window(index);
+ kill_window(w);
fds[i].fd = -1;
} else {
parse_window_event(w);
@@ -444,6 +462,200 @@ void run(void) {
}
}
+int contains(int x, int y, int sx, int sy, int px, int py) {
+ if ((px >= x) && (px <= x + sx) && (py >= y) && (py <= y + sy)) {
+ return 1;
+ }
+ return 0;
+}
+
+int draw_button(DISPLAY *disp, int x, int y, int sx, int sy, uint32_t border,
+ uint32_t filled, int id) {
+ draw_rectangle(disp, x + 1, y + 1, sx, sy, filled);
+ draw_outline(disp, x, y, sx, sy, 1, border);
+
+ if (contains(x, y, sx, sy, mouse_x, mouse_y)) {
+ if (mouse_down) {
+ active_id = id;
+ } else if (mouse_up) {
+ if (id == active_id) {
+ return 1;
+ }
+ }
+ } else {
+ if (id == active_id && mouse_up) {
+ active_id = -1;
+ }
+ }
+ return 0;
+}
+
+int draw_window(DISPLAY *disp, WINDOW *w, int id) {
+ int x, y;
+ uint8_t border_size = disp->border_size;
+ const int px = w->x + border_size;
+ const int py = w->y;
+ const int sx = w->sx;
+ const int sy = w->sy;
+ const int b_sx = w->buffer_sx;
+ const int b_sy = w->buffer_sy;
+ x = px;
+ y = py;
+ int border_px = 1;
+ if (draw_button(disp, x + sx - 40, y - 20, 20, 20, 0x000000, 0x999999,
+ next_ui_id())) {
+ w->minimized = 1;
+ }
+ if (draw_button(disp, x + sx - 20, y - 20, 20, 20, 0x000000, 0x999999,
+ next_ui_id())) {
+ send_kill_window(w);
+ }
+
+ uint32_t border_color = 0x999999;
+ if (w == disp->active_window) {
+ border_color = 0xFF00FF;
+ }
+ draw_outline(disp, x, y, sx, sy, border_px, border_color);
+ x += border_px;
+ y += border_px;
+
+ for (int i = 0; i < sy; i++) {
+ if ((i + y) * disp->width + x > disp->height * disp->width)
+ break;
+ uint32_t *ptr =
+ disp->back_buffer + disp->bpp * ((i + y) * disp->width) + x * disp->bpp;
+ if (i * sx > disp->height * disp->width)
+ break;
+ if (i < b_sy) {
+ uint32_t *bm = &w->bitmap_ptr[i * b_sx];
+ int j = 0;
+ for (; j < b_sx && j < sx; j++) {
+ ptr[j] = bm[j];
+ }
+ for (; j < sx; j++) {
+ ptr[j] = 0;
+ }
+ } else {
+ for (int j = 0; j < sx; j++) {
+ ptr[j] = 0;
+ }
+ }
+ }
+
+ if (contains(px, py, sx, sy, mouse_x, mouse_y)) {
+ if (mouse_down) {
+ active_id = id;
+ } else if (mouse_up) {
+ if (id == active_id) {
+ return 1;
+ }
+ }
+ } else {
+ if (id == active_id && mouse_up) {
+ active_id = -1;
+ }
+ }
+ return 0;
+}
+
+void update_display(const DISPLAY *disp) {
+ for (int i = 0; i < 20; i++) {
+ uint32_t color = 0xFFFFFFFF;
+ // Make every other pixel black to make the mouse more visible on all
+ // backgrounds.
+ if (i & 1) {
+ color = 0x0;
+ }
+ place_pixel(color, mouse_x + i, mouse_y + i);
+ if (i <= 10) {
+ place_pixel(color, mouse_x, mouse_y + i);
+ place_pixel(color, mouse_x + i, mouse_y);
+ }
+ }
+ uint32_t *dst = disp->true_buffer;
+ uint32_t *src = disp->back_buffer;
+ const uint32_t n = disp->size / disp->bpp;
+ for (int i = 0; i < n; i++) {
+ *dst = *src;
+ dst++;
+ src++;
+ }
+}
+
+void draw(void) {
+ ui_id = 0;
+ DISPLAY *disp = &main_display;
+ draw_wallpaper(disp);
+
+ WINDOW *w = disp->window_tail;
+ for (int i = 100; w; w = w->prev, i++) {
+ if (!w->bitmap_ptr) {
+ continue;
+ }
+ if (w->minimized) {
+ continue;
+ }
+ if (draw_window(disp, w, i)) {
+ if (w == main_display.active_window) {
+ continue;
+ }
+ ui_state = 1;
+ main_display.active_window = w;
+ if (w == main_display.window) {
+ continue;
+ }
+ // Remove w from the list
+ WINDOW *prev = w->prev;
+ assert(prev);
+ assert(prev->next == w);
+ WINDOW *next_window = w->next;
+ prev->next = next_window;
+ if (next_window) {
+ next_window->prev = prev;
+ }
+
+ if (w == main_display.window_tail) {
+ assert(NULL == w->next);
+ main_display.window_tail = prev;
+ assert(NULL == prev->next);
+ }
+ // Place it in front
+ WINDOW *m = main_display.window;
+ assert(NULL == m->prev);
+ m->prev = w;
+ w->next = m;
+ w->prev = NULL;
+ main_display.window = w;
+ assert(main_display.window ==
+ ((WINDOW *)main_display.window->next)->prev);
+ if (NULL == m->next) {
+ assert(m == main_display.window_tail);
+ }
+ }
+ }
+
+ int disp_x = 0;
+ w = disp->window_tail;
+ for (; w; w = w->prev) {
+ if (w->minimized) {
+ if (draw_button(disp, disp_x, 0, 20, 20, 0x000000, 0x999999,
+ next_ui_id())) {
+ ui_state = 1;
+ w->minimized = 0;
+ }
+ disp_x += 20;
+ }
+ }
+ if (ui_state) {
+ mouse_down = 0;
+ mouse_up = 0;
+ ui_state = 0;
+ draw();
+ } else {
+ update_display(disp);
+ }
+}
+
int main(void) {
open("/dev/serial", O_WRITE, 0);
open("/dev/serial", O_WRITE, 0);
diff --git a/userland/windowserver/ws.h b/userland/windowserver/ws.h
index 477f123..9978b9c 100644
--- a/userland/windowserver/ws.h
+++ b/userland/windowserver/ws.h
@@ -16,6 +16,9 @@ typedef struct {
int sy;
int buffer_sx;
int buffer_sy;
+ int minimized;
+ struct WINDOW *next;
+ struct WINDOW *prev;
} WINDOW;
typedef struct {
@@ -32,6 +35,7 @@ typedef struct {
uint8_t border_color;
uint8_t wallpaper_color;
WINDOW *active_window;
- WINDOW **windows;
+ WINDOW *window;
+ WINDOW *window_tail;
} DISPLAY;
#endif