erythros/System/Core/Compositor.HC

1152 lines
43 KiB
HolyC

U0 @truetype_init_fonts()
{
CDirEntry* font_files = FilesFind("M:/Fonts/*.ttf");
CDirEntry* de = font_files;
stbtt_fontinfo* info;
U8 name_buffer[512];
U8* name_ptr;
I32 length;
while (de) {
info = CAlloc(sizeof(stbtt_fontinfo), adam_task);
if (@stbtt_InitFont(info, FileRead(de->full_name), 0)) {
MemSet(name_buffer, NULL, 512);
name_ptr = @stbtt_GetFontNameDefault(info, &length);
MemCpy(name_buffer, name_ptr, length);
Fonts->set(name_buffer, info, JSON_NUMBER);
}
de = de->next;
}
DirTreeDel(font_files);
Fonts->set("sans-serif", Fonts->@("Free Sans"), JSON_NUMBER);
Fonts->set("sans-serif Bold", Fonts->@("Free Sans Bold"), JSON_NUMBER);
Fonts->set("sans-serif Bold Italic", Fonts->@("Free Sans Bold Oblique"), JSON_NUMBER);
Fonts->set("sans-serif Italic", Fonts->@("Free Sans Oblique"), JSON_NUMBER);
Fonts->set("serif", Fonts->@("Free Serif"), JSON_NUMBER);
Fonts->set("serif Bold", Fonts->@("Free Serif Bold"), JSON_NUMBER);
Fonts->set("serif Bold Italic", Fonts->@("Free Serif Bold Italic"), JSON_NUMBER);
Fonts->set("serif Italic", Fonts->@("Free Serif Italic"), JSON_NUMBER);
Fonts->set("monospace", Fonts->@("Free Monospaced"), JSON_NUMBER);
Fonts->set("monospace Bold", Fonts->@("Free Monospaced Bold"), JSON_NUMBER);
Fonts->set("monospace Bold Italic", Fonts->@("Free Monospaced Bold Oblique"), JSON_NUMBER);
Fonts->set("monospace Italic", Fonts->@("Free Monospaced Oblique"), JSON_NUMBER);
}
@truetype_init_fonts;
#define CPZ_MSG_WIN_CREATE 0x1001
#define CPZ_MSG_WIN_DESTROY 0x1002
#define CPZ_MSG_WIN_REPAINT 0x1003
#define CPZ_MSG_WIN_MOVE_TO 0x1004
#define CPZ_MSG_WIN_RESIZE_TO 0x1005
#define CPZ_MSG_WIN_MOUSE_AT 0x1006
#define CPZ_MSG_WIN_MOUSE_WHEEL 0x1007
#define CPZ_MSG_WIN_LEFT_BTN_UP 0x1008
#define CPZ_MSG_WIN_LEFT_BTN_DOWN 0x1009
#define CPZ_MSG_WIN_RIGHT_BTN_UP 0x100A
#define CPZ_MSG_WIN_RIGHT_BTN_DOWN 0x100B
#define CPZ_MSG_WIN_KEY_PRESS 0x100C
#define CPZ_MSG_WIN_WIDGET_DESTROY 0x100D
#define CPZ_MSG_WIN_SET_Z_INDEX 0x100E
#define CPZ_MSG_SET_WALLPAPER 0x100F
#define CPZ_WALLPAPER_CENTERED 0x0
#define CPZ_WALLPAPER_AUTORESIZE 0x1
#define CPZ_WALLPAPER_REPEAT 0x2
class @compositor_menubar
{
Window* win;
CTask* task;
TextInputWidget* title;
};
class @compositor_windows_list
{
@compositor_windows_list* prev;
@compositor_windows_list* next;
Window* window;
};
class @compositor
{
I64 next_id;
I64 max_z_index;
Window* active_win;
Context2D* blend_ctx;
Context2D* ctx;
Context2D* pointer;
@compositor_menubar menubar;
@compositor_windows_list* windows;
@compositor_windows_list* global_input_event_listeners;
Bounds2D bounds;
@mouse mouse;
@session session;
@theme theme;
Bool in_drag;
Bool in_resize;
CTask* task;
U0 (*Init)();
Window* (*CreateWindow)(I64 x, I64 y, I64 width, I64 height,
I64 flags = WIN_FLAGS_DEFAULT, U8* title = NULL,
Context2D* icon = NULL);
U0 (*DestroyWindow)(Window* win);
Window (*GetWindowByTitle)(U8* title);
Window (*GetWindowByZIndex)(I64 index);
U0 (*HideWindow)(Window* win);
U0 (*ShowWindow)(Window* win);
U0 (*RegisterForGlobalInputEvents)(Window* win);
U0 (*UnregisterForGlobalInputEvents)(Window* win);
U0 (*SetWallpaper)(Context2D* ctx, U32 mode = CPZ_WALLPAPER_AUTORESIZE, U32 background = Color(0, 0, 0));
U0 (*Task)();
};
@compositor Compositor;
U0 @compositor_add_window_to_list(Window* win)
{
@compositor_windows_list* win_list = Compositor.windows;
@compositor_windows_list* win_next = CAlloc(sizeof(@compositor_windows_list));
while (win_list->next) {
win_list = win_list->next;
}
win_next->window = win;
win_next->prev = win_list;
win_list->next = win_next;
}
U0 @compositor_add_global_input_event_listener_to_list(Window* win)
{
@compositor_windows_list* win_list = Compositor.global_input_event_listeners;
@compositor_windows_list* win_next = CAlloc(sizeof(@compositor_windows_list));
while (win_list->next) {
win_list = win_list->next;
}
win_next->window = win;
win_next->prev = win_list;
win_list->next = win_next;
}
U0 @compositor_remove_global_input_event_listener_from_list(Window* win)
{
@compositor_windows_list* win_list = Compositor.global_input_event_listeners;
@compositor_windows_list* win_list_prev = NULL;
@compositor_windows_list* win_list_next = NULL;
while (win_list) {
if (win_list->window == win) {
win_list_prev = win_list->prev;
win_list_next = win_list->next;
win_list_prev->next = win_list_next;
win_list_next->prev = win_list_prev;
Free(win_list);
return;
}
win_list = win_list->next;
}
}
U0 @compositor_refresh(Window* win)
{
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
msg->client = win->client;
msg->type = CPZ_MSG_WIN_REPAINT;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
if (!Compositor.menubar.win || Compositor.menubar.win == win)
return;
if (Compositor.active_win == win && Compositor.menubar.title) {
Gui.Widget.SetText(Compositor.menubar.title, win->title);
}
}
U0 @compositor_set_z_index(Window* win, I64 index)
{
if (!win)
return;
I64 i = 0;
@compositor_windows_list* win_index = NULL;
@compositor_windows_list* win_list = Compositor.windows->next;
@compositor_windows_list* prev = NULL;
@compositor_windows_list* next = NULL;
while (win_list) {
if (win_list->window == win) {
win_index = win_list;
if (win_index->prev)
prev = win_index->prev;
if (win_index->next)
next = win_index->next;
if (prev)
prev->next = next;
if (next)
next->prev = prev;
break;
}
win_list = win_list->next;
}
win_list = Compositor.windows->next;
prev = NULL;
while (win_list) {
if (i == index) {
prev = win_list->prev;
if (prev)
prev->next = win_index;
win_index->prev = prev;
win_index->next = win_list;
win_list->prev = win_index;
break;
}
i++;
win_list = win_list->next;
}
}
U0 @compositor_set_z_index_send_msg(Window* win, I64 index)
{
if (!win)
return;
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
msg->client = win->client;
msg->type = CPZ_MSG_WIN_SET_Z_INDEX;
msg->payload = win;
msg->i64 = index;
Ipc.MsgSend(Compositor.task, msg);
}
U0 @compositor_set_wallpaper(Context2D* ctx, U32 mode, U32 background)
{ // Sets the wallpaper, doesn't Free the Context, you need to Free it after.
if (!ctx) {
return;
}
Window* win = Compositor.GetWindowByTitle("Wallpaper");
Context2D* tmp = ctx;
if (!win) { // Please, don't call this if the system isn't initialized
System.Log(Fs, "Trying to set the Wallpaper, but the System isn't initialized completely!");
return;
}
if (Display.Width() != ctx->width || Display.Height() != ctx->height) {
if (Display.Width() > ctx->width && Display.Height() > ctx->height) {
switch (mode) {
case CPZ_WALLPAPER_CENTERED:
tmp = NewContext2D(Display.Width(), Display.Height());
tmp->fill(background);
CopyRect2D(tmp,
(Display.Width() / 2) - (ctx->width / 2),
(Display.Height() / 2) - (ctx->height / 2),
ctx);
break;
case CPZ_WALLPAPER_REPEAT:
tmp = NewContext2D(Display.Width(), Display.Height());
I64 x = 0;
I64 y = 0;
while (TRUE) {
CopyRect2D(tmp, x, y, ctx);
x += ctx->width;
if (x >= Display.Width()) {
x = 0;
y += ctx->height;
if (y >= Display.Height())
break;
}
}
break;
case CPZ_WALLPAPER_AUTORESIZE:
default:
tmp = Scale2D(tmp, Display.Width() / ToF64(ctx->width), Display.Height() / ToF64(ctx->height));
break;
}
} else {
tmp = Scale2D(tmp, Display.Width() / ToF64(ctx->width), Display.Height() / ToF64(ctx->height));
}
}
MemCpyU32(win->backing_store->fb, tmp->fb,
Display.Width() * Display.Height());
if (tmp != ctx) // We don't want to delete the context so it can be reused later (If necessary)
DelContext2D(tmp);
}
U0 @compositor_set_wallpaper_send_msg(Context2D* ctx, U32 mode = CPZ_WALLPAPER_AUTORESIZE, U32 background = Color(0, 0, 0))
{
if (!ctx)
return;
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
msg->client = Fs;
msg->type = CPZ_MSG_SET_WALLPAPER;
msg->payload = ctx;
msg->i64.u32[0] = mode;
msg->i64.u32[1] = background;
Ipc.MsgSend(Compositor.task, msg);
}
U0 @compositor_ipc_queue_process()
{
Window* win;
IpcMessage* msg;
@compositor_windows_list* win_list = Compositor.windows->next;
@compositor_windows_list* prev;
@compositor_windows_list* next;
msg = Ipc.MsgRecv();
if (msg) {
switch (msg->type) {
case CPZ_MSG_WIN_CREATE:
win = msg->payload;
win->client = msg->client;
win->render_ctx = NewContext2D(Display.Width(), Display.Height());
win->backing_store = NewContext2D(Display.Width(), Display.Height());
win->backing_store->width = win->width;
win->backing_store->height = win->height;
@compositor_add_window_to_list(win);
System.Log(Fs, "Received message ← CreateWindow (%dx%d at %d, %d)",
win->width, win->height, win->x, win->y);
Free(msg);
msg = CAlloc(sizeof(IpcMessage));
msg->client = win->client;
msg->type = CPZ_MSG_WIN_REPAINT;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
break;
case CPZ_MSG_WIN_DESTROY:
win = msg->payload;
while (win_list) {
if (win_list->window == win) {
prev = win_list->prev;
next = win_list->next;
prev->next = next;
next->prev = prev;
if (win_list->window->backing_store)
DelContext2D(win_list->window->backing_store);
if (win_list->window->render_ctx)
DelContext2D(win_list->window->render_ctx);
// FIXME: free Widgets
Free(win_list->window);
Free(win_list);
Compositor.active_win = NULL;
System.Log(Fs, "Received message ← DestroyWindow 0x%08x", win);
break;
}
win_list = win_list->next;
}
break;
case CPZ_MSG_WIN_SET_Z_INDEX:
@compositor_set_z_index(msg->payload, msg->i64);
System.Log(Fs, "Received message ← SetZIndex (%08X, %d)", msg->payload,
msg->i64);
Free(msg);
break;
case CPZ_MSG_SET_WALLPAPER:
Context2D* ctx = msg->payload;
U32 mode = msg->i64.u32[0];
U32 background = msg->i64.u32[1];
System.Log(Fs, "Received message ← SetWallpaper (%08X, Mode: %d, Background: %d)", ctx,
mode, background);
@compositor_set_wallpaper(ctx, mode, background);
Free(msg);
break;
default:
Free(msg);
break;
}
}
}
Window* @compositor_get_window_by_title(U8* title)
{
@compositor_windows_list* win_list = Compositor.windows->next;
while (win_list) {
if (win_list->window)
if (!StrCmp(&win_list->window->title, title))
return win_list->window;
win_list = win_list->next;
}
return NULL;
}
Window* @compositor_get_window_by_z_index(I64 index)
{
@compositor_windows_list* win_list = Compositor.windows->next;
I64 i = 0;
while (win_list) {
if (i == index)
return win_list->window;
i++;
win_list = win_list->next;
}
return NULL;
}
U0 @compositor_handle_active_window_flags()
{
if (!Compositor.active_win)
return;
if (Compositor.active_win->flags & WIN_FLAGS_MINIMIZED) {
Compositor.active_win = Compositor.GetWindowByTitle("Wallpaper");
if (Compositor.menubar.win) {
Gui.Widget.SetText(Compositor.menubar.title,
&Compositor.active_win->title);
Gui.Window.Refresh(Compositor.menubar.win);
}
}
}
Context2D* @compositor_set_theme_pointer(U8* path, U8* pointer)
{
U8 file_path[512];
StrPrint(&file_path, "%sPointer/%s.png", path, pointer);
Context2D* ctx = Image.FileToContext2D(&file_path);
return ctx;
}
U0 @compositor_set_theme_wallpaper(U8* path)
{
U8 file_path[512];
StrPrint(&file_path, "%s%s", path, "wallpaper.jpg");
Compositor.theme.wallpaper = Image.FileToContext2D(file_path);
if (!Compositor.theme.wallpaper) {
Compositor.theme.wallpaper = NewContext2D(Display.Width(), Display.Height());
}
}
U0 @compositor_set_theme(U8* theme)
{
U8 theme_path[512];
U8 exec_path[512];
StrPrint(&theme_path, "M:/Media/Themes/%s/", theme);
if (!IsDir(&theme_path)) {
System.Log(Fs, "SetTheme failed: Theme does not exist: '%s'", theme);
return;
}
// FIXME: This is disgusting
Compositor.theme.pointer.pointer =
@compositor_set_theme_pointer(&theme_path, "pointer");
Compositor.theme.pointer.pen =
@compositor_set_theme_pointer(&theme_path, "pen");
Compositor.theme.pointer.move =
@compositor_set_theme_pointer(&theme_path, "move");
Compositor.theme.pointer.link =
@compositor_set_theme_pointer(&theme_path, "link");
Compositor.theme.pointer.horz =
@compositor_set_theme_pointer(&theme_path, "horz");
Compositor.theme.pointer.vert =
@compositor_set_theme_pointer(&theme_path, "vert");
Compositor.theme.pointer.text =
@compositor_set_theme_pointer(&theme_path, "text");
Compositor.theme.pointer.cross =
@compositor_set_theme_pointer(&theme_path, "cross");
Compositor.theme.pointer.dgn1 =
@compositor_set_theme_pointer(&theme_path, "dgn1");
Compositor.theme.pointer.dgn2 =
@compositor_set_theme_pointer(&theme_path, "dgn2");
Compositor.theme.pointer.help =
@compositor_set_theme_pointer(&theme_path, "help");
Compositor.theme.pointer.alternate =
@compositor_set_theme_pointer(&theme_path, "alternate");
Compositor.theme.pointer.unavailable =
@compositor_set_theme_pointer(&theme_path, "unavailable");
@compositor_set_theme_wallpaper(&theme_path);
StrPrint(&exec_path, "%sTheme.HC", &theme_path);
ExeDoc(DocRead(exec_path));
}
Bool @compositor_active_win_flag_is_set(U64 flag)
{
if (@gui_window_flag_is_set(Compositor.active_win, flag))
return TRUE;
return FALSE;
}
U0 @compositor_set_pointer(Context2D* pointer = NULL)
{
if (!pointer)
pointer = Compositor.theme.pointer.pointer;
if (Animation2D.IsAnimation(pointer))
Compositor.pointer = Animation2D.Frame(pointer);
else
Compositor.pointer = pointer;
Mouse.PointerSet(Compositor.pointer->fb, Compositor.pointer->width,
Compositor.pointer->height);
}
U0 @compositor_set_active_window(Window* win)
{
if (!win)
return;
if (Compositor.active_win == win)
return;
IpcMessage* msg;
@compositor_windows_list* win_list = Compositor.windows->next;
@compositor_windows_list* prev;
@compositor_windows_list* next;
while (win_list) {
if (!(win->flags & WIN_FLAGS_NO_REINDEX)) {
if (win_list->window == win && win_list->next) {
prev = win_list->prev;
next = win_list->next;
prev->next = next;
next->prev = prev;
while (next->next) {
next = next->next;
}
win_list->prev = next;
win_list->next = NULL;
next->next = win_list;
break;
}
}
win_list = win_list->next;
}
if (Compositor.active_win && Compositor.active_win != win) {
msg = CAlloc(sizeof(IpcMessage));
msg->client = Compositor.active_win->client;
msg->type = CPZ_MSG_WIN_REPAINT;
msg->payload = Compositor.active_win;
Ipc.MsgSend(msg->client, msg);
}
Compositor.active_win = win;
if (Compositor.menubar.win && Compositor.menubar.title) {
Gui.Widget.SetText(Compositor.menubar.title, win->title);
Gui.Window.Refresh(Compositor.menubar.win);
}
System.Log(Fs, "SetActiveWindow (%dx%d at %d, %d)", win->width, win->height,
win->x, win->y);
msg = CAlloc(sizeof(IpcMessage));
msg->client = win->client;
msg->type = CPZ_MSG_WIN_REPAINT;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
@compositor_set_pointer();
}
U0 @compositor_handle_window_resize()
{
if (!Compositor.active_win)
return;
if (Compositor.active_win->signature != WIN_SIGNATURE)
return;
if (!(@compositor_active_win_flag_is_set(WIN_FLAGS_RESIZABLE)))
goto resize_set_pointer;
Bool set_pointer_to_resize = FALSE;
I64 new_width;
I64 new_height;
// Bottom right
if (Mouse.x > Compositor.active_win->x + Compositor.active_win->width - 16 && Mouse.x < Compositor.active_win->x + Compositor.active_win->width && Mouse.y > Compositor.active_win->y + Compositor.active_win->height - 16 && Mouse.y < Compositor.active_win->y + Compositor.active_win->height) {
@compositor_set_pointer(Compositor.theme.pointer.dgn1);
set_pointer_to_resize = TRUE;
}
if (Mouse.left && !Compositor.mouse.left && Compositor.active_win) {
if (Mouse.x > Compositor.active_win->x + Compositor.active_win->width - 16 && Mouse.x < Compositor.active_win->x + Compositor.active_win->width && Mouse.y > Compositor.active_win->y + Compositor.active_win->height - 16 && Mouse.y < Compositor.active_win->y + Compositor.active_win->height) {
Compositor.active_win->origin.x = Compositor.active_win->x;
Compositor.active_win->origin.y = Compositor.active_win->y;
Compositor.active_win->origin.width = Compositor.active_win->width;
Compositor.active_win->origin.height = Compositor.active_win->height;
Compositor.active_win->origin.mouse_x = Mouse.x;
Compositor.active_win->origin.mouse_y = Mouse.y;
Compositor.in_resize = TRUE;
}
}
if (!Mouse.left) {
Compositor.in_drag = FALSE;
Compositor.in_resize = FALSE;
}
if (Compositor.in_resize) {
// FIXME: Set minimum width and height in Compositor.theme or Window.
new_width = Max(16, Compositor.active_win->origin.width + (Mouse.x - Compositor.active_win->origin.mouse_x));
new_height = Max(16, Compositor.active_win->origin.height + (Mouse.y - Compositor.active_win->origin.mouse_y));
new_width = Max(Compositor.theme.window.min_width, new_width);
new_height = Max(Compositor.theme.window.min_height, new_height);
if (Compositor.active_win->width != new_width || Compositor.active_win->height != new_height && !Compositor.active_win->repainting) {
Window* win = Compositor.active_win;
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
System.Log(Fs,
"Sent message → WindowResizeTo (%dx%d at %d, %d) to (%dx%d)",
Compositor.active_win->width, Compositor.active_win->height,
Compositor.active_win->x, Compositor.active_win->y, new_width,
new_height);
if (win->signature != WIN_SIGNATURE)
return;
win->width = new_width;
win->height = new_height;
msg->client = Compositor.active_win->client;
msg->type = CPZ_MSG_WIN_RESIZE_TO;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
}
}
resize_set_pointer:
// FIXME: Move this to @compositor_set_pointer_for_window() or somewhere more
// appropriate?
if (!set_pointer_to_resize) {
if (Compositor.active_win)
if (@gui_window_is_hovered(Compositor.active_win))
if (Compositor.active_win->hovered_widget)
if (Compositor.active_win->hovered_widget->pointer)
@compositor_set_pointer(
Compositor.active_win->hovered_widget->pointer);
else {
if (Compositor.active_win->pointer)
@compositor_set_pointer(Compositor.active_win->pointer);
else
@compositor_set_pointer();
}
else {
if (Compositor.active_win->pointer)
@compositor_set_pointer(Compositor.active_win->pointer);
else
@compositor_set_pointer();
}
else
@compositor_set_pointer();
else
@compositor_set_pointer();
}
}
U0 @compositor_handle_window_drag()
{
if (!(@compositor_active_win_flag_is_set(WIN_FLAGS_MOVABLE)))
return;
I64 title_length;
I64 title_offset;
I64 new_x;
I64 new_y;
// FIXME: Get title_length and title_offset values from theme and Window
// flags.
title_offset = 0;
title_length = Compositor.active_win->width;
if (@compositor_active_win_flag_is_set(WIN_FLAGS_TITLE_BAR)) {
title_offset = Compositor.active_win->title_bar_x;
title_length = Compositor.active_win->title_bar_width;
}
if (Mouse.left && !Compositor.mouse.left && Compositor.active_win) {
if (Mouse.x > Compositor.active_win->x + title_offset && Mouse.x < Compositor.active_win->x + title_offset + title_length && Mouse.y > Compositor.active_win->y && Mouse.y < Compositor.active_win->y + 18) {
Compositor.active_win->origin.x = Compositor.active_win->x;
Compositor.active_win->origin.y = Compositor.active_win->y;
Compositor.active_win->origin.width = Compositor.active_win->width;
Compositor.active_win->origin.height = Compositor.active_win->height;
Compositor.active_win->origin.mouse_x = Mouse.x;
Compositor.active_win->origin.mouse_y = Mouse.y;
Compositor.in_drag = TRUE;
}
}
if (!Mouse.left) {
Compositor.in_drag = FALSE;
Compositor.in_resize = FALSE;
}
if (Compositor.in_drag) {
new_x = Compositor.active_win->origin.x + (Mouse.x - Compositor.active_win->origin.mouse_x);
new_y = Compositor.active_win->origin.y + (Mouse.y - Compositor.active_win->origin.mouse_y);
if (Compositor.active_win->x != new_x || Compositor.active_win->y != new_y) {
Window* win = Compositor.active_win;
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
System.Log(
Fs, "Sent message → WindowMoveTo (%dx%d at %d, %d) to (%d, %d)",
Compositor.active_win->width, Compositor.active_win->height,
Compositor.active_win->x, Compositor.active_win->y, new_x, new_y);
win->x = Min(Compositor.bounds.x2, Max(Compositor.bounds.x1, new_x));
win->y = Min(Compositor.bounds.y2, Max(Compositor.bounds.y1, new_y));
msg->client = Compositor.active_win->client;
msg->type = CPZ_MSG_WIN_MOVE_TO;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
}
}
}
U0 @compositor_handle_window_select()
{
Window* win;
@compositor_windows_list* win_list;
if (Mouse.left && !Compositor.mouse.left) {
if (((Mouse.x < Compositor.active_win->x || Mouse.x > Compositor.active_win->x + Compositor.active_win->width) || (Mouse.y < Compositor.active_win->y || Mouse.y > Compositor.active_win->y + Compositor.active_win->height)) ||
@compositor_active_win_flag_is_set(WIN_FLAGS_NO_REINDEX)) {
win_list = Compositor.windows->next;
while (win_list->next) {
win_list = win_list->next;
}
while (win_list) {
if (Mouse.x > win_list->window->x && Mouse.x < win_list->window->x + win_list->window->width && Mouse.y > win_list->window->y && Mouse.y < win_list->window->y + win_list->window->height) {
if (Compositor.active_win != win_list->window && !(@gui_window_flag_is_set(win_list->window, WIN_FLAGS_MINIMIZED)) && !(@gui_window_flag_is_set(win_list->window, WIN_FLAGS_HIDDEN))) {
@compositor_set_active_window(win_list->window);
return;
}
}
win_list = win_list->prev;
}
}
}
}
U0 @compositor_handle_global_input_events()
{
// FIXME: Handle registered global input events
IpcMessage* msg;
I64 mouse_x;
I64 mouse_y;
I64 type = NULL;
Bool mouse_left = Mouse.left;
Bool mouse_right = Mouse.right;
I64 key = Keyboard.active_key;
I64 tS = Keyboard.active_key_tS;
if (key && tS != Keyboard.last_key_tS) {
@compositor_windows_list* win_list = Compositor.global_input_event_listeners->next;
while (win_list) {
msg = CAlloc(sizeof(IpcMessage));
System.Log(Fs, "Sent message → WinKeyPress [%08x] to window 0x%08x", key,
win_list->window);
msg->client = win_list->window->client;
msg->type = CPZ_MSG_WIN_KEY_PRESS;
msg->payload = win_list->window;
msg->i64 = key;
Ipc.MsgSend(msg->client, msg);
win_list = win_list->next;
}
}
}
U0 @compositor_register_global_input_event_listener(Window* win)
{
@compositor_add_global_input_event_listener_to_list(win);
}
U0 @compositor_unregister_global_input_event_listener(Window* win)
{
@compositor_remove_global_input_event_listener_from_list(win);
}
U0 @compositor_handle_window_input_events(Window* win)
{
if (!win)
return;
IpcMessage* msg;
I64 mouse_x;
I64 mouse_y;
I64 type = NULL;
Bool mouse_left = Mouse.left;
Bool mouse_right = Mouse.right;
if (win->focused_widget) {
if (win->focused_widget->type == WIDGET_TYPE_INPUT) {
if (@widget_input_handle_key(win->focused_widget)) {
msg = CAlloc(sizeof(IpcMessage));
System.Log(Fs, "Sent message → WinKeyPress");
msg->client = win->client;
msg->type = CPZ_MSG_WIN_KEY_PRESS;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
}
if (win->focused_widget(BitmapFontTextInputWidget*)
->selected_region_start
== -1
|| win->focused_widget(BitmapFontTextInputWidget*)
->selected_region_end
== -1) {
if (win->focused_widget(BitmapFontTextInputWidget*)->blink != Blink) {
win->focused_widget(BitmapFontTextInputWidget*)->blink = !win->focused_widget(BitmapFontTextInputWidget*)->blink;
@compositor_refresh(win);
}
}
}
}
if (Mouse.z != Compositor.mouse.delta_z) {
msg = CAlloc(sizeof(IpcMessage));
System.Log(Fs, "Sent message → WindowMouseWheel");
msg->client = win->client;
msg->type = CPZ_MSG_WIN_MOUSE_WHEEL;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
}
if (Mouse.x != Compositor.mouse.x || Mouse.y != Compositor.mouse.y || Mouse.left != Compositor.mouse.left || Mouse.right != Compositor.mouse.right) {
if (Mouse.x != Compositor.mouse.x || Mouse.y != Compositor.mouse.y) {
mouse_x = Mouse.x - win->x;
mouse_y = Mouse.y - win->y;
if (Mouse.x >= win->x && Mouse.x <= win->x + win->width && Mouse.y >= win->y && Mouse.y <= win->y + win->height && (mouse_x != win->mouse.x || mouse_y != win->mouse.y)) {
win->mouse.x = mouse_x;
win->mouse.y = mouse_y;
msg = CAlloc(sizeof(IpcMessage));
System.Log(Fs, "Sent message → WindowMouseAt (%dx%d)", mouse_x,
mouse_y);
msg->client = win->client;
msg->type = CPZ_MSG_WIN_MOUSE_AT;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
}
}
if (mouse_left != win->mouse.left) {
switch (mouse_left) {
case MS_UP:
System.Log(Fs, "Sent message → WindowMouseLeftBtnUp");
type = CPZ_MSG_WIN_LEFT_BTN_UP;
break;
case MS_DOWN:
System.Log(Fs, "Sent message → WindowMouseLeftBtnDown");
type = CPZ_MSG_WIN_LEFT_BTN_DOWN;
break;
default:
break;
}
win->mouse.left = mouse_left;
win->left_btn_down.x = Mouse.x - win->x;
win->left_btn_down.y = Mouse.y - win->y;
msg = CAlloc(sizeof(IpcMessage));
msg->client = win->client;
msg->type = type;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
}
if (mouse_right != win->mouse.right) {
switch (mouse_right) {
case MS_UP:
System.Log(Fs, "Sent message → WindowMouseRightBtnUp");
type = CPZ_MSG_WIN_RIGHT_BTN_UP;
break;
case MS_DOWN:
System.Log(Fs, "Sent message → WindowMouseRightBtnDown");
type = CPZ_MSG_WIN_RIGHT_BTN_DOWN;
break;
default:
break;
}
win->mouse.right = mouse_right;
win->right_btn_down.x = Mouse.x - win->x;
win->right_btn_down.y = Mouse.y - win->y;
msg = CAlloc(sizeof(IpcMessage));
msg->client = win->client;
msg->type = type;
msg->payload = win;
Ipc.MsgSend(msg->client, msg);
}
}
}
U0 @compositor_handle_windows_input_events()
{
if (Compositor.active_win)
@compositor_handle_window_input_events(Compositor.active_win);
@compositor_windows_list* win_list = Compositor.windows;
Compositor.max_z_index = 0;
while (win_list) {
if (win_list->window) {
if (win_list->window->flags & WIN_FLAGS_MENU && win_list->window != Compositor.active_win && Gui.Window.IsVisible(win_list->window))
@compositor_handle_window_input_events(win_list->window);
}
Compositor.max_z_index++;
win_list = win_list->next;
}
}
U0 @compositor_reset_input_event_timestamps()
{
Keyboard.last_key_tS = Keyboard.active_key_tS;
}
Window* @compositor_create_window(I64 x, I64 y, I64 width, I64 height,
I64 flags = WIN_FLAGS_DEFAULT,
U8* title = NULL, Context2D* icon = NULL)
{
Window* win = CAlloc(sizeof(Window));
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
win->x = x;
win->y = y;
win->width = width;
win->height = height;
win->opacity = 255;
win->flags = flags;
win->icon = icon;
win->client = Fs;
win->signature = WIN_SIGNATURE;
win->widget = CAlloc(sizeof(@window_widgets_list));
win->callback.close = &@gui_window_callback_close;
win->callback.maximize = &@gui_window_callback_maximize;
win->callback.minimize = &@gui_window_callback_minimize;
win->callback.repaint = NULL;
if (title)
StrCpy(&win->title, title);
else
StrCpy(&win->title, "Untitled window");
msg->client = Fs;
msg->type = CPZ_MSG_WIN_CREATE;
msg->payload = win;
Ipc.MsgSend(Compositor.task, msg);
while (!win->backing_store) {
Sleep(1);
};
return win;
}
U0 @compositor_destroy_window(Window* win)
{
IpcMessage* msg = CAlloc(sizeof(IpcMessage));
msg->client = Fs;
msg->type = CPZ_MSG_WIN_DESTROY;
msg->payload = win;
Ipc.MsgSend(Compositor.task, msg);
}
U0 @compositor_hide_window(Window* win)
{
@gui_window_hide(win);
Compositor.active_win = NULL;
}
U0 @compositor_show_window(Window* win) { @gui_window_show(win); }
Context2D* @compositor_win_select_backing_store(Window* win)
{
I64 iterations = 0;
while (Compositor.in_resize && win == Compositor.active_win && (win->width != win->backing_store->width || win->height != win->backing_store->height) && iterations < 64) {
iterations++;
if (!(iterations % 8))
@compositor_refresh(win);
Sleep(1);
}
return win->backing_store;
}
U0 @compositor_blit_window_backing_stores()
{
@compositor_windows_list* win_list;
win_list = Compositor.windows;
while (win_list) {
if (win_list->window) {
if (!(@gui_window_flag_is_set(win_list->window, WIN_FLAGS_MINIMIZED)) && !(@gui_window_flag_is_set(win_list->window, WIN_FLAGS_HIDDEN)) && win_list->window->signature == WIN_SIGNATURE) {
if (@compositor_win_select_backing_store(win_list->window) == win_list->window->resize_ctx) {
CopyRect2D(Compositor.ctx, win_list->window->x, win_list->window->y,
win_list->window->resize_ctx);
} else {
if (win_list->window->alpha) {
Compositor.blend_ctx->width = win_list->window->width;
Compositor.blend_ctx->height = win_list->window->height;
CopyRect2D(Compositor.blend_ctx, -win_list->window->x,
-win_list->window->y, Compositor.ctx);
BlendRect2D(win_list->window->backing_store, Compositor.blend_ctx);
CopyRect2D(Compositor.ctx, win_list->window->x, win_list->window->y,
Compositor.blend_ctx);
} else {
CopyRect2D(Compositor.ctx, win_list->window->x, win_list->window->y,
win_list->window->backing_store);
}
}
if (win_list->window == Compositor.active_win && !(@gui_window_flag_is_set(win_list->window, WIN_FLAGS_NOHILIGHT))) {
// Top border
Line2D(Compositor.ctx, win_list->window->x - 1,
win_list->window->y - 1,
win_list->window->x - 1 + win_list->window->width + 2,
win_list->window->y - 1, Compositor.theme.color.active_border);
// Left border
Line2D(Compositor.ctx, win_list->window->x - 1,
win_list->window->y - 1, win_list->window->x - 1,
win_list->window->y + win_list->window->height,
Compositor.theme.color.active_border);
// Bottom border
Line2D(Compositor.ctx, win_list->window->x - 1,
win_list->window->y + win_list->window->height,
win_list->window->x - 1 + win_list->window->width + 2,
win_list->window->y + win_list->window->height,
Compositor.theme.color.active_border);
// Right border
Line2D(Compositor.ctx,
win_list->window->x - 1 + win_list->window->width + 1,
win_list->window->y - 1,
win_list->window->x - 1 + win_list->window->width + 1,
win_list->window->y + win_list->window->height,
Compositor.theme.color.active_border);
// Bottom shadow
Line2D(Compositor.ctx, win_list->window->x + 1,
win_list->window->y + win_list->window->height + 1,
win_list->window->x + win_list->window->width + 2,
win_list->window->y + win_list->window->height + 1,
Compositor.theme.color.active_border);
// Right shadow
Line2D(Compositor.ctx,
win_list->window->x - 1 + win_list->window->width + 2,
win_list->window->y + 1,
win_list->window->x - 1 + win_list->window->width + 2,
win_list->window->y + win_list->window->height + 1,
Compositor.theme.color.active_border);
}
}
}
win_list = win_list->next;
}
}
U0 @compositor_init()
{
Compositor.blend_ctx = NewContext2D(Display.Width(), Display.Height());
Compositor.ctx = NewContext2D(Display.Width(), Display.Height());
Compositor.windows = CAlloc(sizeof(@compositor_windows_list));
Compositor.global_input_event_listeners = CAlloc(sizeof(@compositor_windows_list));
Compositor.bounds.x1 = -Display.Width();
Compositor.bounds.y1 = 33;
Compositor.bounds.x2 = Display.Width();
Compositor.bounds.y2 = Display.Height();
Compositor.active_win = NULL;
Compositor.menubar.win = NULL;
Compositor.menubar.task = NULL;
Compositor.menubar.title = NULL;
Compositor.next_id = 0;
Compositor.session.user.uid = 1;
StrCpy(&Compositor.session.home, "/home/alec");
StrCpy(&Compositor.session.hostname, "erythros");
StrCpy(&Compositor.session.user.name, "alec");
StrCpy(&Compositor.session.user.fullname, "Alec Murphy");
@compositor_set_theme("Umami");
@compositor_set_pointer();
}
U0 @compositor_task()
{
Window* win;
Ipc.InitQueue(Fs);
Compositor.task = Fs;
System.Log(Fs, "Task running at 0x%08x", Fs);
I64 total_mem;
I64 free_mem;
while (1) {
// Process client IpcMessages.
@compositor_ipc_queue_process();
// Handle active window flags
@compositor_handle_active_window_flags();
// Handle window resize
@compositor_handle_window_resize();
// Handle window drag
@compositor_handle_window_drag();
// Handle window select
@compositor_handle_window_select();
// Handle global input events
@compositor_handle_global_input_events();
// Handle windows input events
@compositor_handle_windows_input_events();
// Reset input event timestamps
@compositor_reset_input_event_timestamps();
// Blit window backing stores
@compositor_blit_window_backing_stores();
// Draw Mouse Pointer (if no mouse integration).
// if (!Mouse.Update || Mouse.integration_type == MI_QEMU)
Compositor.ctx->blot(Mouse.X(), Mouse.Y(), Compositor.pointer);
// Debug stuff
I64 debug_row;
if (KeyDown(SC_F12) || (config->o("debug") && config->o("debug")->@("show_compositor_overlay"))) {
debug_row = 32;
total_mem = sys_code_bp->alloced_u8s;
if (sys_data_bp) {
total_mem += sys_data_bp->alloced_u8s;
}
free_mem = sys_code_bp->alloced_u8s - sys_code_bp->used_u8s;
if (sys_data_bp) {
free_mem += sys_data_bp->alloced_u8s - sys_data_bp->used_u8s;
}
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"SysTimerRead : 0x%08x", SysTimerRead);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Total Memory : 0x%08x", total_mem);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Free Memory : 0x%08x", free_mem);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Mouse.X() : %d", Mouse.X());
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Mouse.Y() : %d", Mouse.Y());
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Mouse.Z() : %d", Mouse.z);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Compositor.mouse.z : %d", Compositor.mouse.z);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Mouse.left() : %d", Compositor.mouse.left > 0);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Mouse.right() : %d", Compositor.mouse.right > 0);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"Active window: 0x%08x", Compositor.active_win);
if (Compositor.active_win) {
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
"[+] x : %d", Compositor.active_win->x);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
" y : %d", Compositor.active_win->y);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
" width : %d", Compositor.active_win->width);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
" height : %d", Compositor.active_win->height);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
" title : %s", Compositor.active_win->title);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
" flags : %016b", Compositor.active_win->flags);
ConsolePrint2D(Compositor.ctx, 08 * 03, 16 * debug_row++, , ,
" opacity : %d", Compositor.active_win->opacity);
}
}
// Flip off-screen context to framebuffer.
Graphics2D.Flip(Compositor.ctx);
// Update Compositor mouse button state
Compositor.mouse.x = Mouse.x;
Compositor.mouse.y = Mouse.y;
if (Compositor.mouse.delta_z != Mouse.z)
Compositor.mouse.z = (Mouse.z - Compositor.mouse.delta_z) * T(Mouse.natural_scroll, -Mouse.wheel_sensitivity, Mouse.wheel_sensitivity);
Compositor.mouse.delta_z = Mouse.z;
Compositor.mouse.left = Mouse.left;
Compositor.mouse.right = Mouse.right;
if (Display.Update)
Display.Update();
Sleep(1);
}
}
Gui.Window.Refresh = &@compositor_refresh;
Gui.Window.SetFocus = &@compositor_set_active_window;
Gui.Window.SetZIndex = &@compositor_set_z_index_send_msg;
Compositor.GetWindowByTitle = &@compositor_get_window_by_title;
Compositor.GetWindowByZIndex = &@compositor_get_window_by_z_index;
Compositor.Init = &@compositor_init;
Compositor.CreateWindow = &@compositor_create_window;
Compositor.DestroyWindow = &@compositor_destroy_window;
Compositor.HideWindow = &@compositor_hide_window;
Compositor.RegisterForGlobalInputEvents = &@compositor_register_global_input_event_listener;
Compositor.ShowWindow = &@compositor_show_window;
Compositor.Task = &@compositor_task;
Compositor.UnregisterForGlobalInputEvents = &@compositor_unregister_global_input_event_listener;
Compositor.SetWallpaper = &@compositor_set_wallpaper_send_msg;
"compositor ";