#include "settings.h" #include "paging.h" #include "window.h" #include "drive.h" #include "panic.h" #include "task.h" #include "util.h" #include "pmap.h" #include "elf.h" #include "kbd.h" #include "log.h" #include "vbe.h" #define MAX_WINDOWS 64 #define ACTION_BUFFER_PAGES 1 #define AB_END(buf) (buf + (ACTION_BUFFER_PAGES * 4096) / sizeof(struct window_action)) #define GSC(x, y) (x / 4 + y / 4 >= 256 ? 255 : x / 4 + y / 4) #define BACKGROUND(x, y) ((struct super_pixel){.from_window = 0, .p = (struct pixel){.r = GSC(x / 2, y / 3), .g = GSC(x, y), .b = GSC(x, y / 2)}}) static struct pixel border_color; #define MOVE_BY 5 static struct window { const volatile struct pixel *pixel_buffer_pma; uint16_t width; uint16_t height; uint16_t xpos; uint16_t ypos; struct window_action *action_buffer; struct window_action *next_action_read; struct window_action *next_action_write; struct window *above; struct window *below; struct task_state *from_task; bool wants_mouse_movements; } windows[MAX_WINDOWS]; static struct window *bottom_window = 0; static struct window *top_window = 0; struct super_pixel { struct pixel p; //0 indicates bg const struct window *from_window; }; static struct super_pixel *buffer; static uint32_t buffer_pages; static uint32_t pix_clear_mask; static void load_mode_params() { if (buffer) free_pages(buffer, buffer_pages); const uint32_t fb_len = VBE_MODE_INFO->width * VBE_MODE_INFO->height; buffer_pages = (fb_len * sizeof(struct super_pixel) - 1) / 4096 + 1; buffer = allocate_kernel_pages(buffer_pages); if (!buffer) PANIC("could not allocate intermediate framebuffer"); #define MASK(offset, length) ((~((1 << offset) - 1)) - (offset + length == 32 ? 0 : (~((1 << (offset + length)) - 1)))) pix_clear_mask = ~( MASK(VBE_MODE_INFO->red_off, VBE_MODE_INFO->red_len) | MASK(VBE_MODE_INFO->green_off, VBE_MODE_INFO->green_len) | MASK(VBE_MODE_INFO->blue_off, VBE_MODE_INFO->blue_len) | MASK(VBE_MODE_INFO->alpha_off, VBE_MODE_INFO->alpha_len) ); } static inline void blit_pixel(uint32_t *into, struct pixel from) { *into &= pix_clear_mask; *into |= (from.r >> (8 - VBE_MODE_INFO->red_len)) << VBE_MODE_INFO->red_off; *into |= (from.g >> (8 - VBE_MODE_INFO->green_len)) << VBE_MODE_INFO->green_off; *into |= (from.b >> (8 - VBE_MODE_INFO->blue_len)) << VBE_MODE_INFO->blue_off; } static uint16_t mouse_y; static uint16_t mouse_x; #define MOUSE_WIDTH 8 #define MOUSE_HEIGHT 8 #define B {.r = 0, .g = 0, .b = 0, .pad = 0} #define W {.r = 255, .g = 255, .b = 255, .pad = 0} #define T {.pad = 1} static const struct pixel mouse_image[] = { W, W, W, W, W, W, T, T, W, B, B, B, W, T, T, T, W, B, B, B, W, W, T, T, W, B, B, B, B, W, W, T, W, W, W, B, B, B, W, T, W, T, W, W, B, B, B, W, T, T, T, W, W, B, W, W, T, T, T, T, W, W, W, T }; static void blit_mouse() { uint16_t y_max = mouse_y + MOUSE_HEIGHT > VBE_MODE_INFO->height ? VBE_MODE_INFO->height - mouse_y : MOUSE_HEIGHT; uint16_t x_max = mouse_x + MOUSE_WIDTH > VBE_MODE_INFO->width ? VBE_MODE_INFO->width - mouse_x : MOUSE_WIDTH; void *row = VBE_MODE_INFO->frame_buf + mouse_y * VBE_MODE_INFO->pitch + mouse_x * (VBE_MODE_INFO->bpp / 8); for (uint16_t y = 0; y < y_max; ++y) { uint32_t *out_pix = row; for (uint16_t x = 0; x < x_max; ++x) { if (!mouse_image[y * MOUSE_WIDTH + x].pad) blit_pixel(out_pix, mouse_image[y * MOUSE_WIDTH + x]); out_pix = (uint32_t *)((void *)out_pix + VBE_MODE_INFO->bpp / 8); } row += VBE_MODE_INFO->pitch; } } static void blit(uint16_t x_min, uint16_t x_max, uint16_t y_min, uint16_t y_max) { void *row = VBE_MODE_INFO->frame_buf + y_min * VBE_MODE_INFO->pitch + x_min * (VBE_MODE_INFO->bpp / 8); const struct super_pixel *from_row = buffer + y_min * VBE_MODE_INFO->width + x_min; for (uint16_t y = y_min; y < y_max; ++y) { uint32_t *out_pix = row; const struct super_pixel *from = from_row; for (uint16_t x = x_min; x < x_max; ++x) { blit_pixel(out_pix, from->p); out_pix = (uint32_t *)((void *)out_pix + VBE_MODE_INFO->bpp / 8); ++from; } row += VBE_MODE_INFO->pitch; from_row += VBE_MODE_INFO->width; } if ((y_min < mouse_y) && (y_max > mouse_y) && (x_min < mouse_x) && (x_max > mouse_x)) blit_mouse(); } #define POWER_OFF_MESSAGE_PITCH 45 #define POWER_OFF_MESSAGE_ROWS 28 static const bool power_off_message[] = { 1,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1, 1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1, 0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0, 0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,0,1,0,1,0, 0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, 0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, 0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, 0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; #define POWER_OFF_SCALE 3 void show_shutdown() { void *row = VBE_MODE_INFO->frame_buf; for (uint32_t y = 0; y < VBE_MODE_INFO->height; ++y) { void *i = row; for (uint32_t x = 0; x < VBE_MODE_INFO->width; ++x) { blit_pixel(i, (struct pixel){.r = 0, .g = 0, .b = 0}); i += (VBE_MODE_INFO->bpp / 8); } row += VBE_MODE_INFO->pitch; } const uint16_t x_pad = (VBE_MODE_INFO->width - POWER_OFF_MESSAGE_PITCH * POWER_OFF_SCALE) / 2; const uint16_t y_pad = (VBE_MODE_INFO->height - POWER_OFF_MESSAGE_ROWS * POWER_OFF_SCALE) / 2; for (uint8_t r = 0; r < POWER_OFF_MESSAGE_ROWS; ++r) for (uint8_t i = 0; i < POWER_OFF_MESSAGE_PITCH; ++i) if (power_off_message[r * POWER_OFF_MESSAGE_PITCH + i]) { void *const o = VBE_MODE_INFO->frame_buf + (y_pad + r * POWER_OFF_SCALE) * VBE_MODE_INFO->pitch + (x_pad + i * POWER_OFF_SCALE) * VBE_MODE_INFO->bpp / 8; for (uint8_t y = 0; y < POWER_OFF_SCALE; ++y) for (uint8_t x = 0; x < POWER_OFF_SCALE; ++x) blit_pixel(o + y * VBE_MODE_INFO->pitch + x * VBE_MODE_INFO->bpp / 8, (struct pixel){.r = 255, .g = 255, .b = 255}); } } static inline void draw_hz_line(uint16_t y, uint16_t xs, uint16_t xm, struct super_pixel value) { if (y >= VBE_MODE_INFO->height) return; if (xs >= VBE_MODE_INFO->width) xs = 0; if (xm > VBE_MODE_INFO->width) xm = VBE_MODE_INFO->width; for (uint16_t x = xs; x < xm; ++x) buffer[y * VBE_MODE_INFO->width + x] = value; } static inline void draw_vt_line(uint16_t x, uint16_t ys, uint16_t ym, struct super_pixel value) { if (x >= VBE_MODE_INFO->width) return; if (ys >= VBE_MODE_INFO->height) ys = 0; if (ym > VBE_MODE_INFO->height) ym = VBE_MODE_INFO->height; for (uint16_t y = ys; y < ym; ++y) buffer[y * VBE_MODE_INFO->width + x] = value; } static void get_window_edges(const struct window *w, uint16_t *xmin, uint16_t *xmax, uint16_t *ymin, uint16_t *ymax) { *ymin = w->ypos < VBE_MODE_INFO->height ? 0 : -w->ypos; *xmin = w->xpos < VBE_MODE_INFO->width ? 0 : -w->xpos; *ymax = ((w->ypos + w->height) & 0xffff) <= VBE_MODE_INFO->height ? w->height : VBE_MODE_INFO->height - w->ypos; *xmax = ((w->xpos + w->width) & 0xffff) <= VBE_MODE_INFO->width ? w->width : VBE_MODE_INFO->width - w->xpos; } static void paint_and_above(const struct window *w) { switch_to_kernel_cr3(); for (const struct window *i = w; i; i = i->above) { uint16_t xmin, xmax, ymin, ymax; get_window_edges(i, &xmin, &xmax, &ymin, &ymax); //logf(LOG_INFO, "y: %n .. %n", ys, ym - 1); //logf(LOG_INFO, "x: %n .. %n", xs, xm - 1); for (uint16_t y = ymin; y < ymax; ++y) for (uint16_t x = xmin; x < xmax; ++x) { struct super_pixel *const into = buffer + (((y + i->ypos) & 0xffff) * VBE_MODE_INFO->width + ((x + i->xpos) & 0xffff)); into->from_window = i; into->p = i->pixel_buffer_pma[y * i->width + x]; } /* buffer[((y + i->ypos) & 0xffff) * VBE_MODE_INFO->width + ((x + i->xpos) & 0xffff)] = (struct super_pixel){.from_window = i, .p = i->pixel_buffer_pma[y * i->width + x]};*/ struct super_pixel super = {.from_window = i, .p = border_color}; draw_hz_line(i->ypos - 2, i->xpos - 2, i->xpos + i->width + 2, super); draw_hz_line(i->ypos - 1, i->xpos - 2, i->xpos + i->width + 2, super); draw_hz_line(i->ypos + i->height, i->xpos - 2, i->xpos + i->width + 2, super); draw_hz_line(i->ypos + i->height + 1, i->xpos - 2, i->xpos + i->width + 2, super); draw_vt_line(i->xpos - 2, i->ypos, i->ypos + i->height, super); draw_vt_line(i->xpos - 1, i->ypos, i->ypos + i->height, super); draw_vt_line(i->xpos + i->width, i->ypos, i->ypos + i->height, super); draw_vt_line(i->xpos + i->width + 1, i->ypos, i->ypos + i->height, super); } blit(0, VBE_MODE_INFO->width, 0, VBE_MODE_INFO->height); switch_to_task_cr3(); } static void paint_bg() { for (uint16_t y = 0; y < VBE_MODE_INFO->height; ++y) for (uint16_t x = 0; x < VBE_MODE_INFO->width; ++x) buffer[y * VBE_MODE_INFO->width + x] = BACKGROUND(x, y); } static void paint_all() { paint_bg(); paint_and_above(bottom_window); } static void send_action(struct window *w, struct window_action packet) { struct window_action *next_next = w->next_action_write + 1; if (next_next >= AB_END(w->action_buffer)) next_next = w->action_buffer; if (next_next != w->next_action_read) { *(w->next_action_write) = packet; w->next_action_write = next_next; unwait(w->from_task, (struct wait){.mode = WINDOW_ACTION}); } } struct window *new_window(uint16_t width, uint16_t height, const struct pixel *pixel_buffer) { if (!pixel_buffer) { logf(LOG_WARN, "Refusing to create window with null pixel buffer for task %s.", active_task->name); return 0; } struct window *w; for (uint8_t i = 0; i < MAX_WINDOWS; ++i) if (!windows[i].pixel_buffer_pma) { w = &windows[i]; goto got_window; } return 0; got_window: w->pixel_buffer_pma = vma_to_pma(active_task->page_directory, pixel_buffer); w->width = width; w->height = height; w->xpos = (VBE_MODE_INFO->width / 2) - (width / 2); w->ypos = (VBE_MODE_INFO->height / 2) - (height / 2); struct window_action *const ab = allocate_kernel_pages(ACTION_BUFFER_PAGES); w->action_buffer = ab; w->next_action_read = ab; w->next_action_write = ab; if (top_window) { send_action(top_window, (struct window_action){.action_type = FOCUS_LEAVE}); top_window->above = w; } else bottom_window = w; w->above = 0; w->below = top_window; top_window = w; send_action(top_window, (struct window_action){.action_type = FOCUS_ENTER}); w->from_task = active_task; w->wants_mouse_movements = false; paint_and_above(w); return w; } static void del_no_paint(struct window *w) { if ((w < windows) || (w >= windows + MAX_WINDOWS) || (((void *)w - (void *)windows) % sizeof(struct window))) { logf(LOG_WARN, "Refusing to delete bad window pointer 0x%h", w); return; } if (w == top_window) { top_window = w->below; if (top_window) send_action(top_window, (struct window_action){.action_type = FOCUS_ENTER}); } if (w == bottom_window) bottom_window = w->above; if (w->below) w->below->above = w->above; if (w->above) w->above->below = w->below; free_pages(w->action_buffer, ACTION_BUFFER_PAGES); w->pixel_buffer_pma = 0; } void del_window(struct window *w) { del_no_paint(w); paint_all(); } void delete_any_windows_from(struct task_state *tstate) { bool need_to_paint = false; for (struct window *w = windows; w < windows + MAX_WINDOWS; ++w) if (w->pixel_buffer_pma && (w->from_task == tstate)) { del_no_paint(w); need_to_paint = true; } if (need_to_paint) paint_all(); } void resize_window(struct window *w, uint16_t width, uint16_t height, const struct pixel *pixel_buffer) { const bool smaller = (width < w->width) || (height < w->height); w->width = width; w->height = height; reassign_pixel_buffer(w, pixel_buffer); if (smaller) paint_all(); else paint_and_above(w); } void reassign_pixel_buffer(struct window *w, const struct pixel *pixel_buffer) { w->pixel_buffer_pma = vma_to_pma(active_task->page_directory, pixel_buffer); } void push_window_paint(const struct window *w) { switch_to_kernel_cr3(); uint16_t xmin, xmax, ymin, ymax; get_window_edges(w, &xmin, &xmax, &ymin, &ymax); for (uint16_t y = ymin; y < ymax; ++y) for (uint16_t x = xmin; x < xmax; ++x) { struct super_pixel *const into = buffer + (((y + w->ypos) & 0xffff) * VBE_MODE_INFO->width + ((x + w->xpos) & 0xffff)); if (into->from_window == w) into->p = w->pixel_buffer_pma[y * w->width + x]; } blit(w->xpos + xmin, w->xpos + xmax, w->ypos + ymin, w->ypos + ymax); switch_to_task_cr3(); } struct window_action next_window_action(struct window *w) { if (w->next_action_write == w->next_action_read) return (struct window_action){.action_type = NONE}; const struct window_action *const action = w->next_action_read; if (++(w->next_action_read) >= AB_END(w->action_buffer)) w->next_action_read = w->action_buffer; return *action; } #define RUN_COMMAND_FILE "sys/winspace.rc" enum wm_action { WM_MOVE_LEFT, WM_MOVE_RIGHT, WM_MOVE_UP, WM_MOVE_DOWN, WM_RUN_COMMAND, N_WM_ACTIONS }; static struct key_packet keybinds[] = { {.key_id = KEY_LEFT_ARROW, .modifiers = WINS}, {.key_id = KEY_RIGHT_ARROW, .modifiers = WINS}, {.key_id = KEY_UP_ARROW, .modifiers = WINS}, {.key_id = KEY_DOWN_ARROW, .modifiers = WINS}, {.key_id = KEY_SPACE, .modifiers = WINS} }; static inline bool fuzzy_key_match(struct key_packet t, struct key_packet a) { if (t.key_id != a.key_id) return false; if (((t.modifiers & SHIFTS) == SHIFTS) && (a.modifiers & SHIFTS)) a.modifiers |= SHIFTS; if (((t.modifiers & CTRLS) == CTRLS) && (a.modifiers & CTRLS)) a.modifiers |= CTRLS; if (((t.modifiers & ALTS) == ALTS) && (a.modifiers & ALTS)) a.modifiers |= ALTS; if (((t.modifiers & WINS) == WINS) && (a.modifiers & WINS)) a.modifiers |= WINS; return a.modifiers == t.modifiers; } static char *run_command; static char *run_command_pass = ""; void init_win() { if (!try_get_color_setting("wm-border-color", &border_color)) PANIC("could not load window border color setting."); buffer = 0; load_mode_params(); paint_bg(); blit(0, VBE_MODE_INFO->width, 0, VBE_MODE_INFO->height); mouse_x = (VBE_MODE_INFO->width - MOUSE_WIDTH) / 2; mouse_y = (VBE_MODE_INFO->height - MOUSE_HEIGHT) / 2; blit_mouse(); const file_id_t fid = drives->get_file(drives, RUN_COMMAND_FILE); if (!fid) PANIC("Couldn't open " RUN_COMMAND_FILE "."); const uint32_t len = drives->get_file_length(drives, fid); run_command = allocate_kernel_pages(len / 4096 + 1); if (!run_command) PANIC("Couldn't make buffer for " RUN_COMMAND_FILE " contents."); fmcpy(run_command, drives, fid, 0, len); run_command[len] = '\0'; drives->free_file(drives, fid); for (char *c = run_command; *c; ++c) if (*c == ' ') { *c = '\0'; run_command_pass = c + 1; break; } } void on_action(struct window_action packet) { //logf(LOG_INFO, "Window action, top window = 0x%d from %s.", top_window, top_window->from_task->name); if (packet.action_type == NOT_READY) return; if (packet.action_type == KEY_DOWN) for (uint8_t i = 0; i < N_WM_ACTIONS; ++i) if (fuzzy_key_match(keybinds[i], packet.as_key)) { switch_to_kernel_cr3(); switch (i) { case WM_MOVE_LEFT: if (top_window) { top_window->xpos -= MOVE_BY; paint_all(); } break; case WM_MOVE_RIGHT: if (top_window) { top_window->xpos += MOVE_BY; paint_all(); } break; case WM_MOVE_UP: if (top_window) { top_window->ypos -= MOVE_BY; paint_all(); } break; case WM_MOVE_DOWN: if (top_window) { top_window->ypos += MOVE_BY; paint_all(); } break; case WM_RUN_COMMAND: if (!try_elf_run(drives, run_command, run_command_pass, 0)) logf(LOG_ERROR, "Couldn't run program listed in " RUN_COMMAND_FILE "."); break; } switch_to_task_cr3(); return; } if (top_window) send_action(top_window, packet); } struct window *being_moved = 0; int16_t winpos_rel_y; int16_t winpos_rel_x; void move_mouse_by(int16_t y, int16_t x) { //logf(LOG_INFO, "old mouse coords: (%d, %d)", mouse_x, mouse_y); switch_to_kernel_cr3(); const uint16_t old_y = mouse_y; const uint16_t old_x = mouse_x; mouse_y = (-y > mouse_y) ? 0 : (y + mouse_y + MOUSE_HEIGHT > VBE_MODE_INFO->height) ? VBE_MODE_INFO->height - MOUSE_HEIGHT : y + mouse_y; mouse_x = (-x > mouse_x) ? 0 : (x + mouse_x + MOUSE_WIDTH > VBE_MODE_INFO->width) ? VBE_MODE_INFO->width - MOUSE_WIDTH : x + mouse_x; if (being_moved) { being_moved->ypos = winpos_rel_y + mouse_y; being_moved->xpos = winpos_rel_x + mouse_x; paint_all(); } else { blit(old_x, old_x + MOUSE_WIDTH > VBE_MODE_INFO->width ? VBE_MODE_INFO->width : old_x + MOUSE_WIDTH, old_y, old_y + MOUSE_HEIGHT > VBE_MODE_INFO->height ? VBE_MODE_INFO->height : old_y + MOUSE_HEIGHT); blit_mouse(); struct window *const moving_over = buffer[mouse_y * VBE_MODE_INFO->width + mouse_x].from_window; if (moving_over && moving_over->wants_mouse_movements && (mouse_y >= moving_over->ypos) && (mouse_y < moving_over->ypos + moving_over->height) && (mouse_x >= moving_over->xpos) && (mouse_x < moving_over->xpos + moving_over->width)) send_action(moving_over, (struct window_action){ .action_type = MOUSE_MOVE, .moved_to = { .x = mouse_x - moving_over->xpos, .y = mouse_y - moving_over->ypos } }); } switch_to_task_cr3(); //logf(LOG_INFO, "new mouse coords: (%d, %d)", mouse_x, mouse_y); } static void focus(struct window *w) { send_action(top_window, (struct window_action){.action_type = FOCUS_LEAVE}); if (w->below) w->below->above = w->above; else bottom_window = w->above; w->above->below = w->below; w->above = 0; w->below = top_window; top_window->above = w; top_window = w; send_action(w, (struct window_action){.action_type = FOCUS_ENTER}); } static void send_bottom(struct window *w) { if (w == bottom_window) return; if (w == top_window) { send_action(w, (struct window_action){.action_type = FOCUS_LEAVE}); top_window = w->below; top_window->above = 0; w->above = bottom_window; w->below = 0; bottom_window->below = w; bottom_window = w; send_action(top_window, (struct window_action){.action_type = FOCUS_ENTER}); } else { w->above->below = w->below; w->below->above = w->above; bottom_window->below = w; w->above = bottom_window; w->below = 0; bottom_window = w; } paint_and_above(w->above); } bool skip_up_right = false; void mouse_button(enum mouse_button which, bool up) { if (!top_window) return; struct window *const clicked_on = buffer[mouse_y * VBE_MODE_INFO->width + mouse_x].from_window; if (!clicked_on) return; if ((mouse_y < clicked_on->ypos) || (mouse_y >= clicked_on->ypos + clicked_on->height) || (mouse_x < clicked_on->xpos) || (mouse_x >= clicked_on->xpos + clicked_on->width)) //TODO: resizing return; if (up && being_moved && (which == LEFT)) being_moved = 0; else if (!up && !being_moved && (keymods & ALTS) && (which == LEFT)) { being_moved = clicked_on; winpos_rel_y = clicked_on->ypos - mouse_y; winpos_rel_x = clicked_on->xpos - mouse_x; } else if (!up && (keymods & ALTS) && (which == RIGHT)) { send_bottom(clicked_on); skip_up_right = true; } else if (up && skip_up_right && (which == RIGHT)) skip_up_right = false; else { if (clicked_on != top_window) { focus(clicked_on); paint_and_above(clicked_on); } send_action(clicked_on, (struct window_action){.action_type = up ? MOUSE_UP : MOUSE_DOWN, .as_mouse = {.y = mouse_y - clicked_on->ypos, .x = mouse_x - clicked_on->xpos, .which = which}}); } } void window_wants_mouse_movements(struct window *w) { w->wants_mouse_movements = true; }