diff --git a/build.sh b/build.sh index 3a8bc784..81f3c5b3 100644 --- a/build.sh +++ b/build.sh @@ -53,6 +53,7 @@ if [ "$rdi_from_pdb" = "1" ]; then didbuild=1 && $compile ../src/rdi_fr if [ "$rdi_from_dwarf" = "1" ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf || exit 1; fi if [ "$rdi_dump" = "1" ]; then didbuild=1 && $compile ../src/rdi_dump/rdi_dump_main.c $compile_link $out rdi_dump || exit 1; fi if [ "$rdi_breakpad_from_pdb" = "1" ]; then didbuild=1 && $compile ../src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c $compile_link $out rdi_breakpad_from_pdb || exit 1; fi +if [ "$ryan_scratch" = "1" ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $out ryan_scratch || exit 1; fi cd .. # --- Warn On No Builds ------------------------------------------------------- diff --git a/project.4coder b/project.4coder index f6eaee9e..9584f3ae 100644 --- a/project.4coder +++ b/project.4coder @@ -1,175 +1,177 @@ -version(2); -project_name = "The RAD Debugger"; - -indent_width = "2"; -default_tab_width = "2"; - -patterns = -{ - "*.c", - "*.cpp", - "*.h", - "*.inc", - "*.hpp", - "*.bat", - "*.sh", - "*.4coder", - "*.glsl", - "*.bfs", - "*.html", - "*.txt", - "*.md", - "*.mdesk", - "*.asm", -}; - -blacklist_patterns = -{ - ".*", - "metagen_base_*", - "metagen_os_*", -}; - -paths = -{ - { .path = ".", .recursive = false, .relative = true, }, - { .path = "src", .recursive = true , .relative = true, }, - { .path = "local", .recursive = true , .relative = true, }, -}; - -load_paths = -{ - .win = paths, - .linux = paths, -}; - -commands = -{ - .rjf_f1 = - { - //.win = "build rdi_from_pdb rdi_dump && pushd build && rdi_from_pdb --pdb:mule_main.pdb --out:mule_main.rdi && rdi_dump mule_main.rdi > mule_main.dump && popd", - .win = "build raddbg telemetry", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .rjf_f2 = - { - .win = "build rdi_from_pdb rdi_dump && pushd build && rdi_from_pdb --pdb:mule_main.pdb --out:mule_main.rdi && rdi_dump mule_main.rdi > mule_main.dump && popd", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .rjf_f3 = - { - .win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --project:local_dev.raddbg_project && popd", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .rjf_f4 = - { - .win = "build rdi_from_pdb release telemetry && pushd build && rdi_from_pdb.exe --pdb:UnrealEditorFortnite.pdb --out:profile.rdi --capture && popd", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .rjf_f5 = - { - .win = "pushd build && rdi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.rdi --capture && popd", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .build_raddbg = - { - .win = "build raddbg", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .build_raddbg_release_telemetry = - { - .win = "build raddbg release telemetry", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .build_rdi_from_pdb = - { - .win = "build rdi_from_pdb", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .build_rdi_dump = - { - .win = "build rdi_dump", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .build_mule_main = - { - .win = "build mule_main", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .build_ryan_scratch = - { - .win = "build ryan_scratch", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, - .run_raddbg = - { - .win = "pushd build && raddbg.exe && popd", - .linux = "", - .out = "*compilation*", - .footer_panel = true, - .save_dirty_files = true, - .cursor_at_end = false, - }, -}; - -fkey_command = -{ - .F1 = "build_raddbg", - .F3 = "run_raddbg", -}; - -fkey_command_override = -{ - .rjf = - { - .F1 = "rjf_f1", - .F2 = "rjf_f2", - .F3 = "rjf_f3", - .F4 = "rjf_f4", - .F5 = "rjf_f5", - }, -}; +version(2); +project_name = "The RAD Debugger"; + +indent_width = "2"; +default_tab_width = "2"; + +patterns = +{ + "*.c", + "*.cpp", + "*.h", + "*.inc", + "*.hpp", + "*.bat", + "*.sh", + "*.4coder", + "*.glsl", + "*.bfs", + "*.html", + "*.txt", + "*.md", + "*.mdesk", + "*.asm", +}; + +blacklist_patterns = +{ + ".*", + "metagen_base_*", + "metagen_os_*", +}; + +paths = +{ + { .path = ".", .recursive = false, .relative = true, }, + { .path = "src", .recursive = true , .relative = true, }, + { .path = "local", .recursive = true , .relative = true, }, +}; + +load_paths = +{ + .win = paths, + .linux = paths, +}; + +commands = +{ + .rjf_f1 = + { + //.win = "build rdi_from_pdb rdi_dump && pushd build && rdi_from_pdb --pdb:mule_main.pdb --out:mule_main.rdi && rdi_dump mule_main.rdi > mule_main.dump && popd", + //.win = "build raddbg telemetry", + .win = "build ryan_scratch", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .rjf_f2 = + { + .win = "build rdi_from_pdb rdi_dump && pushd build && rdi_from_pdb --pdb:mule_main.pdb --out:mule_main.rdi && rdi_dump mule_main.rdi > mule_main.dump && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .rjf_f3 = + { + // .win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --project:local_dev.raddbg_project && popd", + .win = "pushd build && ryan_scratch.exe && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .rjf_f4 = + { + .win = "build rdi_from_pdb release telemetry && pushd build && rdi_from_pdb.exe --pdb:UnrealEditorFortnite.pdb --out:profile.rdi --capture && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .rjf_f5 = + { + .win = "pushd build && rdi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.rdi --capture && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_raddbg = + { + .win = "build raddbg", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_raddbg_release_telemetry = + { + .win = "build raddbg release telemetry", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_rdi_from_pdb = + { + .win = "build rdi_from_pdb", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_rdi_dump = + { + .win = "build rdi_dump", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_mule_main = + { + .win = "build mule_main", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .build_ryan_scratch = + { + .win = "build ryan_scratch", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .run_raddbg = + { + .win = "pushd build && raddbg.exe && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, +}; + +fkey_command = +{ + .F1 = "build_raddbg", + .F3 = "run_raddbg", +}; + +fkey_command_override = +{ + .rjf = + { + .F1 = "rjf_f1", + .F2 = "rjf_f2", + .F3 = "rjf_f3", + .F4 = "rjf_f4", + .F5 = "rjf_f5", + }, +}; diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 498ec0b5..e3a3f029 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -49,7 +49,7 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum #if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL) ctrl_init(); #endif -#if defined(OS_GRAPHICAL_H) && !defined(OS_GFX_INIT_MANUAL) +#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL) os_gfx_init(); #endif #if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL) diff --git a/src/demon/demon_inc.c b/src/demon/demon_inc.c index daab75e2..0f0507c2 100644 --- a/src/demon/demon_inc.c +++ b/src/demon/demon_inc.c @@ -1,10 +1,12 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "demon_core.c" - -#if OS_WINDOWS -# include "win32/demon_core_win32.c" -#else -# error Demon layer backend not defined for this operating system. -#endif +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "demon/demon_core.c" + +#if OS_WINDOWS +# include "demon/win32/demon_core_win32.c" +#elif OS_LINUX +# include "demon/linux/demon_core_linux.c" +#else +# error Demon layer backend not defined for this operating system. +#endif diff --git a/src/demon/demon_inc.h b/src/demon/demon_inc.h index b7266cca..8bd7b092 100644 --- a/src/demon/demon_inc.h +++ b/src/demon/demon_inc.h @@ -4,10 +4,12 @@ #ifndef DEMON_INC_H #define DEMON_INC_H -#include "demon_core.h" +#include "demon/demon_core.h" #if OS_WINDOWS -# include "win32/demon_core_win32.h" +# include "demon/win32/demon_core_win32.h" +#elif OS_LINUX +# include "demon/linux/demon_core_linux.h" #else # error Demon layer backend not defined for this operating system. #endif diff --git a/src/demon/linux/demon_core_linux.c b/src/demon/linux/demon_core_linux.c new file mode 100644 index 00000000..5c9e16cd --- /dev/null +++ b/src/demon/linux/demon_core_linux.c @@ -0,0 +1,174 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS) + +internal void +dmn_init(void) +{ +} + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) + +internal DMN_CtrlCtx * +dmn_ctrl_begin(void) +{ +} + +internal void +dmn_ctrl_exclusive_access_begin(void) +{ +} + +internal void +dmn_ctrl_exclusive_access_end(void) +{ +} + +internal U32 +dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params) +{ +} + +internal B32 +dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid) +{ +} + +internal B32 +dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code) +{ +} + +internal B32 +dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process) +{ +} + +internal DMN_EventList +dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) +{ +} + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) + +internal void +dmn_halt(U64 code, U64 user_data) +{ +} + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS) + +//- rjf: run/memory/register counters + +internal U64 +dmn_run_gen(void) +{ +} + +internal U64 +dmn_mem_gen(void) +{ +} + +internal U64 +dmn_reg_gen(void) +{ +} + +//- rjf: non-blocking-control-thread access barriers + +internal B32 +dmn_access_open(void) +{ +} + +internal void +dmn_access_close(void) +{ +} + +//- rjf: processes + +internal U64 +dmn_process_memory_reserve(DMN_Handle process, U64 vaddr, U64 size) +{ +} + +internal void +dmn_process_memory_commit(DMN_Handle process, U64 vaddr, U64 size) +{ +} + +internal void +dmn_process_memory_decommit(DMN_Handle process, U64 vaddr, U64 size) +{ +} + +internal void +dmn_process_memory_release(DMN_Handle process, U64 vaddr, U64 size) +{ +} + +internal void +dmn_process_memory_protect(DMN_Handle process, U64 vaddr, U64 size, OS_AccessFlags flags) +{ +} + +internal U64 +dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst) +{ +} + +internal B32 +dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) +{ +} + +//- rjf: threads + +internal Architecture +dmn_arch_from_thread(DMN_Handle handle) +{ +} + +internal U64 +dmn_stack_base_vaddr_from_thread(DMN_Handle handle) +{ +} + +internal U64 +dmn_tls_root_vaddr_from_thread(DMN_Handle handle) +{ +} + +internal B32 +dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block) +{ +} + +internal B32 +dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block) +{ +} + +//- rjf: system process listing + +internal void +dmn_process_iter_begin(DMN_ProcessIter *iter) +{ +} + +internal B32 +dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out) +{ +} + +internal void +dmn_process_iter_end(DMN_ProcessIter *iter) +{ +} diff --git a/src/demon/linux/demon_core_linux.h b/src/demon/linux/demon_core_linux.h new file mode 100644 index 00000000..a0bae69a --- /dev/null +++ b/src/demon/linux/demon_core_linux.h @@ -0,0 +1,7 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_CORE_LINUX_H +#define DEMON_CORE_LINUX_H + +#endif // DEMON_CORE_LINUX_H diff --git a/src/font_provider/font_provider_inc.h b/src/font_provider/font_provider_inc.h index 6fcf5d03..c3001d25 100644 --- a/src/font_provider/font_provider_inc.h +++ b/src/font_provider/font_provider_inc.h @@ -8,12 +8,17 @@ //~ rjf: Backend Constants #define FP_BACKEND_DWRITE 1 +#define FP_BACKEND_FREETYPE 2 //////////////////////////////// //~ rjf: Decide On Backend -#if !defined(FP_BACKEND) && OS_WINDOWS -# define FP_BACKEND FP_BACKEND_DWRITE +#if !defined(FP_BACKEND) +# if OS_WINDOWS +# define FP_BACKEND FP_BACKEND_DWRITE +# elif OS_LINUX +# define FP_BACKEND FP_BACKEND_FREETYPE +# endif #endif //////////////////////////////// @@ -26,6 +31,8 @@ #if FP_BACKEND == FP_BACKEND_DWRITE # include "dwrite/font_provider_dwrite.h" +#elif FP_BACKEND == FP_BACKEND_FREETYPE +# include "freetype/font_provider_freetype.h" #else # error Font provider backend not specified. #endif diff --git a/src/font_provider/freetype/font_provider_freetype.c b/src/font_provider/freetype/font_provider_freetype.c new file mode 100644 index 00000000..8ac6bce5 --- /dev/null +++ b/src/font_provider/freetype/font_provider_freetype.c @@ -0,0 +1,2 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) diff --git a/src/font_provider/freetype/font_provider_freetype.h b/src/font_provider/freetype/font_provider_freetype.h new file mode 100644 index 00000000..2efe2a50 --- /dev/null +++ b/src/font_provider/freetype/font_provider_freetype.h @@ -0,0 +1,7 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef FONT_PROVIDER_FREETYPE_H +#define FONT_PROVIDER_FREETYPE_H + +#endif // FONT_PROVIDER_FREETYPE_H diff --git a/src/os/gfx/linux/os_gfx_linux.c b/src/os/gfx/linux/os_gfx_linux.c index 1982f794..4309bf90 100644 --- a/src/os/gfx/linux/os_gfx_linux.c +++ b/src/os/gfx/linux/os_gfx_linux.c @@ -1,13 +1,45 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Helpers + +internal OS_LNX_Window * +os_lnx_window_from_x11window(Window window) +{ + OS_LNX_Window *result = 0; + for(OS_LNX_Window *w = os_lnx_gfx_state->first_window; w != 0; w = w->next) + { + if(w->window == window) + { + result = w; + break; + } + } + return result; +} + //////////////////////////////// //~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) internal void os_gfx_init(void) { + //- rjf: initialize basics + Arena *arena = arena_alloc(); + os_lnx_gfx_state = push_array(arena, OS_LNX_GfxState, 1); + os_lnx_gfx_state->arena = arena; + os_lnx_gfx_state->display = XOpenDisplay(0); + //- rjf: calculate atoms + os_lnx_gfx_state->wm_delete_window_atom = XInternAtom(os_lnx_gfx_state->display, "WM_DELETE_WINDOW", 0); + os_lnx_gfx_state->wm_sync_request_atom = XInternAtom(os_lnx_gfx_state->display, "_NET_WM_SYNC_REQUEST", 0); + os_lnx_gfx_state->wm_sync_request_counter_atom = XInternAtom(os_lnx_gfx_state->display, "_NET_WM_SYNC_REQUEST_COUNTER", 0); + + //- rjf: fill out gfx info + os_lnx_gfx_state->gfx_info.double_click_time = 0.5f; + os_lnx_gfx_state->gfx_info.caret_blink_time = 0.5f; + os_lnx_gfx_state->gfx_info.default_refresh_rate = 60.f; } //////////////////////////////// @@ -16,7 +48,7 @@ os_gfx_init(void) internal OS_GfxInfo * os_get_gfx_info(void) { - return 0; + return &os_lnx_gfx_state->gfx_info; } //////////////////////////////// @@ -31,7 +63,8 @@ os_set_clipboard_text(String8 string) internal String8 os_get_clipboard_text(Arena *arena) { - + String8 result = {0}; + return result; } //////////////////////////////// @@ -40,121 +73,178 @@ os_get_clipboard_text(Arena *arena) internal OS_Handle os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) { + //- rjf: allocate window + OS_LNX_Window *w = os_lnx_gfx_state->free_window; + if(w) + { + SLLStackPop(os_lnx_gfx_state->free_window); + } + else + { + w = push_array_no_zero(os_lnx_gfx_state->arena, OS_LNX_Window, 1); + } + MemoryZeroStruct(w); + DLLPushBack(os_lnx_gfx_state->first_window, os_lnx_gfx_state->last_window, w); + //- rjf: create window & equip with x11 info + w->window = XCreateWindow(os_lnx_gfx_state->display, + XDefaultRootWindow(os_lnx_gfx_state->display), + 0, 0, resolution.x, resolution.y, + 0, + CopyFromParent, + InputOutput, + CopyFromParent, + 0, + 0); + XSelectInput(os_lnx_gfx_state->display, w->window, + ExposureMask| + PointerMotionMask| + ButtonPressMask| + ButtonReleaseMask| + KeyPressMask| + KeyReleaseMask| + FocusChangeMask); + Atom protocols[] = + { + os_lnx_gfx_state->wm_delete_window_atom, + os_lnx_gfx_state->wm_sync_request_atom, + }; + XSetWMProtocols(os_lnx_gfx_state->display, w->window, protocols, ArrayCount(protocols)); + { + XSyncValue initial_value; + XSyncIntToValue(&initial_value, 0); + w->counter_xid = XSyncCreateCounter(os_lnx_gfx_state->display, initial_value); + } + XChangeProperty(os_lnx_gfx_state->display, w->window, os_lnx_gfx_state->wm_sync_request_counter_atom, XA_CARDINAL, 32, PropModeReplace, (U8 *)&w->counter_xid, 1); + + //- rjf: attach name + Temp scratch = scratch_begin(0, 0); + String8 title_copy = push_str8_copy(scratch.arena, title); + XStoreName(os_lnx_gfx_state->display, w->window, (char *)title_copy.str); + scratch_end(scratch); + + //- rjf: convert to handle & return + OS_Handle handle = {(U64)w}; + return handle; } internal void os_window_close(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void -os_window_first_paint(OS_Handle window_handle) +os_window_first_paint(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return;} + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + XMapWindow(os_lnx_gfx_state->display, w->window); } internal void os_window_equip_repaint(OS_Handle handle, OS_WindowRepaintFunctionType *repaint, void *user_data) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void os_window_focus(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal B32 os_window_is_focused(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return 0;} + return 0; } internal B32 os_window_is_fullscreen(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return 0;} + return 0; } internal void os_window_set_fullscreen(OS_Handle handle, B32 fullscreen) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal B32 os_window_is_maximized(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return 0;} + return 0; } internal void os_window_set_maximized(OS_Handle handle, B32 maximized) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void os_window_minimize(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void os_window_bring_to_front(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void -os_window_set_monitor(OS_Handle window_handle, OS_Handle monitor) +os_window_set_monitor(OS_Handle handle, OS_Handle monitor) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void os_window_clear_custom_border_data(OS_Handle handle) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void os_window_push_custom_title_bar(OS_Handle handle, F32 thickness) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void os_window_push_custom_edges(OS_Handle handle, F32 thickness) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal void os_window_push_custom_title_bar_client_area(OS_Handle handle, Rng2F32 rect) { - + if(os_handle_match(handle, os_handle_zero())) {return;} } internal Rng2F32 os_rect_from_window(OS_Handle handle) { - + return r2f32p(0, 0, 0, 0); } internal Rng2F32 os_client_rect_from_window(OS_Handle handle) { - + return r2f32p(0, 0, 0, 0); } internal F32 os_dpi_from_window(OS_Handle handle) { - + return 0; } //////////////////////////////// @@ -163,31 +253,34 @@ os_dpi_from_window(OS_Handle handle) internal OS_HandleArray os_push_monitors_array(Arena *arena) { - + OS_HandleArray result = {0}; + return result; } internal OS_Handle os_primary_monitor(void) { - + OS_Handle result = {0}; + return result; } internal OS_Handle os_monitor_from_window(OS_Handle window) { - + OS_Handle result = {0}; + return result; } internal String8 os_name_from_monitor(Arena *arena, OS_Handle monitor) { - + return str8_zero(); } internal Vec2F32 os_dim_from_monitor(OS_Handle monitor) { - + return v2f32(0, 0); } //////////////////////////////// @@ -202,25 +295,169 @@ os_send_wakeup_event(void) internal OS_EventList os_get_events(Arena *arena, B32 wait) { - + OS_EventList evts = {0}; + for(;XPending(os_lnx_gfx_state->display) > 0 || (wait && evts.count == 0);) + { + XEvent evt = {0}; + XNextEvent(os_lnx_gfx_state->display, &evt); + switch(evt.type) + { + default:{}break; + + //- rjf: key presses/releases + case KeyPress: + case KeyRelease: + { + // rjf: determine flags + OS_EventFlags flags = 0; + if(evt.xkey.state & ShiftMask) { flags |= OS_EventFlag_Shift; } + if(evt.xkey.state & ControlMask) { flags |= OS_EventFlag_Ctrl; } + if(evt.xkey.state & Mod1Mask) { flags |= OS_EventFlag_Alt; } + + // rjf: map keycode -> keysym + U32 keysym = XLookupKeysym(&evt.xkey, 0); + + // rjf: map keysym -> OS_Key + OS_Key key = OS_Key_Null; + switch(keysym) + { + default: + { + if(0){} + else if(XK_F1 <= keysym && keysym <= XK_F24) { key = (OS_Key)(OS_Key_F1 + (keysym - XK_F1)); } + else if('0' <= keysym && keysym <= '9') { key = OS_Key_0 + (keysym-'0'); } + }break; + case XK_Escape:{key = OS_Key_Esc;};break; + case '-':{key = OS_Key_Minus;}break; + case '=':{key = OS_Key_Equal;}break; + case '[':{key = OS_Key_LeftBracket;}break; + case ']':{key = OS_Key_RightBracket;}break; + case ';':{key = OS_Key_Semicolon;}break; + case '\'':{key = OS_Key_Quote;}break; + case '.':{key = OS_Key_Period;}break; + case ',':{key = OS_Key_Comma;}break; + case '/':{key = OS_Key_Slash;}break; + case '\\':{key = OS_Key_BackSlash;}break; + case 'a':case 'A':{key = OS_Key_A;}break; + case 'b':case 'B':{key = OS_Key_B;}break; + case 'c':case 'C':{key = OS_Key_C;}break; + case 'd':case 'D':{key = OS_Key_D;}break; + case 'e':case 'E':{key = OS_Key_E;}break; + case 'f':case 'F':{key = OS_Key_F;}break; + case 'g':case 'G':{key = OS_Key_G;}break; + case 'h':case 'H':{key = OS_Key_H;}break; + case 'i':case 'I':{key = OS_Key_I;}break; + case 'j':case 'J':{key = OS_Key_J;}break; + case 'k':case 'K':{key = OS_Key_K;}break; + case 'l':case 'L':{key = OS_Key_L;}break; + case 'm':case 'M':{key = OS_Key_M;}break; + case 'n':case 'N':{key = OS_Key_N;}break; + case 'o':case 'O':{key = OS_Key_O;}break; + case 'p':case 'P':{key = OS_Key_P;}break; + case 'q':case 'Q':{key = OS_Key_Q;}break; + case 'r':case 'R':{key = OS_Key_R;}break; + case 's':case 'S':{key = OS_Key_S;}break; + case 't':case 'T':{key = OS_Key_T;}break; + case 'u':case 'U':{key = OS_Key_U;}break; + case 'v':case 'V':{key = OS_Key_V;}break; + case 'w':case 'W':{key = OS_Key_W;}break; + case 'x':case 'X':{key = OS_Key_X;}break; + case 'y':case 'Y':{key = OS_Key_Y;}break; + case 'z':case 'Z':{key = OS_Key_Z;}break; + case ' ':{key = OS_Key_Space;}break; + } + + // rjf: push event + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xclient.window); + OS_Event *e = os_event_list_push_new(arena, &evts, evt.type == KeyPress ? OS_EventKind_Press : OS_EventKind_Release); + e->window.u64[0] = (U64)window; + e->flags = flags; + e->key = key; + }break; + + //- rjf: mouse button presses/releases + case ButtonPress: + case ButtonRelease: + { + // rjf: determine flags + OS_EventFlags flags = 0; + if(evt.xbutton.state & ShiftMask) { flags |= OS_EventFlag_Shift; } + if(evt.xbutton.state & ControlMask) { flags |= OS_EventFlag_Ctrl; } + if(evt.xbutton.state & Mod1Mask) { flags |= OS_EventFlag_Alt; } + + // rjf: map button -> OS_Key + OS_Key key = OS_Key_Null; + switch(evt.xbutton.button) + { + default:{}break; + case Button1:{key = OS_Key_LeftMouseButton;}break; + case Button2:{key = OS_Key_MiddleMouseButton;}break; + case Button3:{key = OS_Key_RightMouseButton;}break; + } + + // rjf: push event + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xclient.window); + OS_Event *e = os_event_list_push_new(arena, &evts, evt.type == ButtonPress ? OS_EventKind_Press : OS_EventKind_Release); + e->window.u64[0] = (U64)window; + e->flags = flags; + e->key = key; + }break; + + //- rjf: mouse motion + case MotionNotify: + { + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xclient.window); + OS_Event *e = os_event_list_push_new(arena, &evts, OS_EventKind_MouseMove); + e->window.u64[0] = (U64)window; + e->pos.x = (F32)evt.xmotion.x; + e->pos.y = (F32)evt.xmotion.y; + }break; + + //- rjf: window focus/unfocus + case FocusIn: + case FocusOut: + { + + }break; + + //- rjf: client messages + case ClientMessage: + { + if((Atom)evt.xclient.data.l[0] == os_lnx_gfx_state->wm_delete_window_atom) + { + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xclient.window); + OS_Event *e = os_event_list_push_new(arena, &evts, OS_EventKind_WindowClose); + e->window.u64[0] = (U64)window; + } + else if((Atom)evt.xclient.data.l[0] == os_lnx_gfx_state->wm_sync_request_atom) + { + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xclient.window); + if(window != 0) + { + window->counter_value = 0; + window->counter_value |= evt.xclient.data.l[2]; + window->counter_value |= (evt.xclient.data.l[3] << 32); + XSyncValue value; + XSyncIntToValue(&value, window->counter_value); + XSyncSetCounter(os_lnx_gfx_state->display, window->counter_xid, value); + } + } + }break; + } + } + return evts; } internal OS_EventFlags os_get_event_flags(void) { - -} - -internal B32 -os_key_is_down(OS_Key key) -{ - + return 0; } internal Vec2F32 os_mouse_from_window(OS_Handle handle) { - + return v2f32(0, 0); } //////////////////////////////// diff --git a/src/os/gfx/linux/os_gfx_linux.h b/src/os/gfx/linux/os_gfx_linux.h index 5c2193b3..4ac97ab3 100644 --- a/src/os/gfx/linux/os_gfx_linux.h +++ b/src/os/gfx/linux/os_gfx_linux.h @@ -10,5 +10,47 @@ #include #include #include +#include +#include + +//////////////////////////////// +//~ rjf: Window State + +typedef struct OS_LNX_Window OS_LNX_Window; +struct OS_LNX_Window +{ + OS_LNX_Window *next; + OS_LNX_Window *prev; + Window window; + XID counter_xid; + U64 counter_value; +}; + +//////////////////////////////// +//~ rjf: State Bundle + +typedef struct OS_LNX_GfxState OS_LNX_GfxState; +struct OS_LNX_GfxState +{ + Arena *arena; + Display *display; + OS_LNX_Window *first_window; + OS_LNX_Window *last_window; + OS_LNX_Window *free_window; + Atom wm_delete_window_atom; + Atom wm_sync_request_atom; + Atom wm_sync_request_counter_atom; + OS_GfxInfo gfx_info; +}; + +//////////////////////////////// +//~ rjf: Globals + +global OS_LNX_GfxState *os_lnx_gfx_state = 0; + +//////////////////////////////// +//~ rjf: Helpers + +internal OS_LNX_Window *os_lnx_window_from_x11window(Window window); #endif // OS_GFX_LINUX_H diff --git a/src/os/gfx/os_gfx.c b/src/os/gfx/os_gfx.c index 4e957a88..d006ab02 100644 --- a/src/os/gfx/os_gfx.c +++ b/src/os/gfx/os_gfx.c @@ -1,228 +1,261 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Generated Code - -#include "generated/os_gfx.meta.c" - -//////////////////////////////// -//~ rjf: Event Functions (Helpers, Implemented Once) - -internal String8List -os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags) -{ - String8List result = {0}; - String8 flag_strs[] = - { - str8_lit("Ctrl"), - str8_lit("Shift"), - str8_lit("Alt"), - }; - str8_list_from_flags(arena, &result, flags, flag_strs, ArrayCount(flag_strs)); - return result; -} - -internal U32 -os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key) -{ - U32 result = 0; - - // rjf: special-case map - local_persist read_only struct {U32 character; OS_Key key; OS_EventFlags flags;} map[] = - { - {'!', OS_Key_1, OS_EventFlag_Shift}, - {'@', OS_Key_2, OS_EventFlag_Shift}, - {'#', OS_Key_3, OS_EventFlag_Shift}, - {'$', OS_Key_4, OS_EventFlag_Shift}, - {'%', OS_Key_5, OS_EventFlag_Shift}, - {'^', OS_Key_6, OS_EventFlag_Shift}, - {'&', OS_Key_7, OS_EventFlag_Shift}, - {'*', OS_Key_8, OS_EventFlag_Shift}, - {'(', OS_Key_9, OS_EventFlag_Shift}, - {')', OS_Key_0, OS_EventFlag_Shift}, - {'_', OS_Key_Minus, OS_EventFlag_Shift}, - {'_', OS_Key_Minus, OS_EventFlag_Shift}, - {'-', OS_Key_Minus, 0}, - {'=', OS_Key_Equal, 0}, - {'+', OS_Key_Equal, OS_EventFlag_Shift}, - {'`', OS_Key_Tick, 0}, - {'~', OS_Key_Tick, OS_EventFlag_Shift}, - {'[', OS_Key_LeftBracket, 0}, - {']', OS_Key_RightBracket, 0}, - {'{', OS_Key_LeftBracket, OS_EventFlag_Shift}, - {'}', OS_Key_RightBracket, OS_EventFlag_Shift}, - {'\\', OS_Key_BackSlash, 0}, - {'|', OS_Key_BackSlash, OS_EventFlag_Shift}, - {';', OS_Key_Semicolon, 0}, - {':', OS_Key_Semicolon, OS_EventFlag_Shift}, - {'\'', OS_Key_Quote, 0}, - {'"', OS_Key_Quote, OS_EventFlag_Shift}, - {'.', OS_Key_Period, 0}, - {',', OS_Key_Comma, 0}, - {'<', OS_Key_Period, OS_EventFlag_Shift}, - {'>', OS_Key_Comma, OS_EventFlag_Shift}, - {'/', OS_Key_Slash, 0}, - {'?', OS_Key_Slash, OS_EventFlag_Shift}, - {'a', OS_Key_A, 0}, - {'b', OS_Key_B, 0}, - {'c', OS_Key_C, 0}, - {'d', OS_Key_D, 0}, - {'e', OS_Key_E, 0}, - {'f', OS_Key_F, 0}, - {'g', OS_Key_G, 0}, - {'h', OS_Key_H, 0}, - {'i', OS_Key_I, 0}, - {'j', OS_Key_J, 0}, - {'k', OS_Key_K, 0}, - {'l', OS_Key_L, 0}, - {'m', OS_Key_M, 0}, - {'n', OS_Key_N, 0}, - {'o', OS_Key_O, 0}, - {'p', OS_Key_P, 0}, - {'q', OS_Key_Q, 0}, - {'r', OS_Key_R, 0}, - {'s', OS_Key_S, 0}, - {'t', OS_Key_T, 0}, - {'u', OS_Key_U, 0}, - {'v', OS_Key_V, 0}, - {'w', OS_Key_W, 0}, - {'x', OS_Key_X, 0}, - {'y', OS_Key_Y, 0}, - {'z', OS_Key_Z, 0}, - {'A', OS_Key_A, OS_EventFlag_Shift}, - {'B', OS_Key_B, OS_EventFlag_Shift}, - {'C', OS_Key_C, OS_EventFlag_Shift}, - {'D', OS_Key_D, OS_EventFlag_Shift}, - {'E', OS_Key_E, OS_EventFlag_Shift}, - {'F', OS_Key_F, OS_EventFlag_Shift}, - {'G', OS_Key_G, OS_EventFlag_Shift}, - {'H', OS_Key_H, OS_EventFlag_Shift}, - {'I', OS_Key_I, OS_EventFlag_Shift}, - {'J', OS_Key_J, OS_EventFlag_Shift}, - {'K', OS_Key_K, OS_EventFlag_Shift}, - {'L', OS_Key_L, OS_EventFlag_Shift}, - {'M', OS_Key_M, OS_EventFlag_Shift}, - {'N', OS_Key_N, OS_EventFlag_Shift}, - {'O', OS_Key_O, OS_EventFlag_Shift}, - {'P', OS_Key_P, OS_EventFlag_Shift}, - {'Q', OS_Key_Q, OS_EventFlag_Shift}, - {'R', OS_Key_R, OS_EventFlag_Shift}, - {'S', OS_Key_S, OS_EventFlag_Shift}, - {'T', OS_Key_T, OS_EventFlag_Shift}, - {'U', OS_Key_U, OS_EventFlag_Shift}, - {'V', OS_Key_V, OS_EventFlag_Shift}, - {'W', OS_Key_W, OS_EventFlag_Shift}, - {'X', OS_Key_X, OS_EventFlag_Shift}, - {'Y', OS_Key_Y, OS_EventFlag_Shift}, - {'Z', OS_Key_Z, OS_EventFlag_Shift}, - }; - - // rjf: check numeric - if(OS_Key_0 <= key && key <= OS_Key_9) - { - result = '0' + (key - OS_Key_0); - } - - // rjf: check special-case map - for(U64 idx = 0; idx < ArrayCount(map); idx += 1) - { - if(map[idx].key == key && map[idx].flags == flags) - { - result = map[idx].character; - break; - } - } - - return result; -} - -internal void -os_eat_event(OS_EventList *events, OS_Event *event) -{ - DLLRemove(events->first, events->last, event); - events->count -= 1; -} - -internal B32 -os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key) -{ - B32 result = 0; - for(OS_Event *event = events->first; event != 0; event = event->next) - { - if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && - event->kind == OS_EventKind_Press && event->key == key && event->flags == flags) - { - result = 1; - os_eat_event(events, event); - break; - } - } - return result; -} - -internal B32 -os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key) -{ - B32 result = 0; - for(OS_Event *event = events->first; event != 0; event = event->next) - { - if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && - event->kind == OS_EventKind_Release && event->key == key && event->flags == flags) - { - result = 1; - os_eat_event(events, event); - break; - } - } - return result; -} - -internal B32 -os_text(OS_EventList *events, OS_Handle window, U32 character) -{ - B32 result = 0; - for(OS_Event *event = events->first; event != 0; event = event->next) - { - if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && - event->kind == OS_EventKind_Text && event->character == character) - { - result = 1; - os_eat_event(events, event); - break; - } - } - return result; -} - -internal OS_EventList -os_event_list_copy(Arena *arena, OS_EventList *src) -{ - OS_EventList dst = {0}; - for(OS_Event *s = src->first; s != 0; s = s->next) - { - OS_Event *d = push_array(arena, OS_Event, 1); - MemoryCopyStruct(d, s); - d->strings = str8_list_copy(arena, &s->strings); - DLLPushBack(dst.first, dst.last, d); - dst.count += 1; - } - return dst; -} - -internal void -os_event_list_concat_in_place(OS_EventList *dst, OS_EventList *to_push) -{ - if(dst->last && to_push->first) - { - dst->last->next = to_push->first; - to_push->first->prev = dst->last; - dst->last = to_push->last; - dst->count += to_push->count; - } - else if(!dst->last && to_push->first) - { - MemoryCopyStruct(dst, to_push); - } - MemoryZeroStruct(to_push); -} +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/os_gfx.meta.c" + +//////////////////////////////// +//~ rjf: Event Functions (Helpers, Implemented Once) + +internal String8 +os_string_from_event_kind(OS_EventKind kind) +{ + String8 result = {0}; + switch(kind) + { + case OS_EventKind_Null: + case OS_EventKind_COUNT: + {}break; + case OS_EventKind_Press: {result = str8_lit("Press");}break; + case OS_EventKind_Release: {result = str8_lit("Release");}break; + case OS_EventKind_MouseMove: {result = str8_lit("MouseMove");}break; + case OS_EventKind_Text: {result = str8_lit("Text");}break; + case OS_EventKind_Scroll: {result = str8_lit("Scroll");}break; + case OS_EventKind_WindowLoseFocus: {result = str8_lit("WindowLoseFocus");}break; + case OS_EventKind_WindowClose: {result = str8_lit("WindowClose");}break; + case OS_EventKind_FileDrop: {result = str8_lit("FileDrop");}break; + case OS_EventKind_Wakeup: {result = str8_lit("Wakeup");}break; + } + return result; +} + +internal String8List +os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags) +{ + String8List result = {0}; + String8 flag_strs[] = + { + str8_lit("Ctrl"), + str8_lit("Shift"), + str8_lit("Alt"), + }; + str8_list_from_flags(arena, &result, flags, flag_strs, ArrayCount(flag_strs)); + return result; +} + +internal U32 +os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key) +{ + U32 result = 0; + + // rjf: special-case map + local_persist read_only struct {U32 character; OS_Key key; OS_EventFlags flags;} map[] = + { + {'!', OS_Key_1, OS_EventFlag_Shift}, + {'@', OS_Key_2, OS_EventFlag_Shift}, + {'#', OS_Key_3, OS_EventFlag_Shift}, + {'$', OS_Key_4, OS_EventFlag_Shift}, + {'%', OS_Key_5, OS_EventFlag_Shift}, + {'^', OS_Key_6, OS_EventFlag_Shift}, + {'&', OS_Key_7, OS_EventFlag_Shift}, + {'*', OS_Key_8, OS_EventFlag_Shift}, + {'(', OS_Key_9, OS_EventFlag_Shift}, + {')', OS_Key_0, OS_EventFlag_Shift}, + {'_', OS_Key_Minus, OS_EventFlag_Shift}, + {'_', OS_Key_Minus, OS_EventFlag_Shift}, + {'-', OS_Key_Minus, 0}, + {'=', OS_Key_Equal, 0}, + {'+', OS_Key_Equal, OS_EventFlag_Shift}, + {'`', OS_Key_Tick, 0}, + {'~', OS_Key_Tick, OS_EventFlag_Shift}, + {'[', OS_Key_LeftBracket, 0}, + {']', OS_Key_RightBracket, 0}, + {'{', OS_Key_LeftBracket, OS_EventFlag_Shift}, + {'}', OS_Key_RightBracket, OS_EventFlag_Shift}, + {'\\', OS_Key_BackSlash, 0}, + {'|', OS_Key_BackSlash, OS_EventFlag_Shift}, + {';', OS_Key_Semicolon, 0}, + {':', OS_Key_Semicolon, OS_EventFlag_Shift}, + {'\'', OS_Key_Quote, 0}, + {'"', OS_Key_Quote, OS_EventFlag_Shift}, + {'.', OS_Key_Period, 0}, + {',', OS_Key_Comma, 0}, + {'<', OS_Key_Period, OS_EventFlag_Shift}, + {'>', OS_Key_Comma, OS_EventFlag_Shift}, + {'/', OS_Key_Slash, 0}, + {'?', OS_Key_Slash, OS_EventFlag_Shift}, + {'a', OS_Key_A, 0}, + {'b', OS_Key_B, 0}, + {'c', OS_Key_C, 0}, + {'d', OS_Key_D, 0}, + {'e', OS_Key_E, 0}, + {'f', OS_Key_F, 0}, + {'g', OS_Key_G, 0}, + {'h', OS_Key_H, 0}, + {'i', OS_Key_I, 0}, + {'j', OS_Key_J, 0}, + {'k', OS_Key_K, 0}, + {'l', OS_Key_L, 0}, + {'m', OS_Key_M, 0}, + {'n', OS_Key_N, 0}, + {'o', OS_Key_O, 0}, + {'p', OS_Key_P, 0}, + {'q', OS_Key_Q, 0}, + {'r', OS_Key_R, 0}, + {'s', OS_Key_S, 0}, + {'t', OS_Key_T, 0}, + {'u', OS_Key_U, 0}, + {'v', OS_Key_V, 0}, + {'w', OS_Key_W, 0}, + {'x', OS_Key_X, 0}, + {'y', OS_Key_Y, 0}, + {'z', OS_Key_Z, 0}, + {'A', OS_Key_A, OS_EventFlag_Shift}, + {'B', OS_Key_B, OS_EventFlag_Shift}, + {'C', OS_Key_C, OS_EventFlag_Shift}, + {'D', OS_Key_D, OS_EventFlag_Shift}, + {'E', OS_Key_E, OS_EventFlag_Shift}, + {'F', OS_Key_F, OS_EventFlag_Shift}, + {'G', OS_Key_G, OS_EventFlag_Shift}, + {'H', OS_Key_H, OS_EventFlag_Shift}, + {'I', OS_Key_I, OS_EventFlag_Shift}, + {'J', OS_Key_J, OS_EventFlag_Shift}, + {'K', OS_Key_K, OS_EventFlag_Shift}, + {'L', OS_Key_L, OS_EventFlag_Shift}, + {'M', OS_Key_M, OS_EventFlag_Shift}, + {'N', OS_Key_N, OS_EventFlag_Shift}, + {'O', OS_Key_O, OS_EventFlag_Shift}, + {'P', OS_Key_P, OS_EventFlag_Shift}, + {'Q', OS_Key_Q, OS_EventFlag_Shift}, + {'R', OS_Key_R, OS_EventFlag_Shift}, + {'S', OS_Key_S, OS_EventFlag_Shift}, + {'T', OS_Key_T, OS_EventFlag_Shift}, + {'U', OS_Key_U, OS_EventFlag_Shift}, + {'V', OS_Key_V, OS_EventFlag_Shift}, + {'W', OS_Key_W, OS_EventFlag_Shift}, + {'X', OS_Key_X, OS_EventFlag_Shift}, + {'Y', OS_Key_Y, OS_EventFlag_Shift}, + {'Z', OS_Key_Z, OS_EventFlag_Shift}, + }; + + // rjf: check numeric + if(OS_Key_0 <= key && key <= OS_Key_9) + { + result = '0' + (key - OS_Key_0); + } + + // rjf: check special-case map + for(U64 idx = 0; idx < ArrayCount(map); idx += 1) + { + if(map[idx].key == key && map[idx].flags == flags) + { + result = map[idx].character; + break; + } + } + + return result; +} + +internal void +os_eat_event(OS_EventList *events, OS_Event *event) +{ + DLLRemove(events->first, events->last, event); + events->count -= 1; +} + +internal B32 +os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key) +{ + B32 result = 0; + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && + event->kind == OS_EventKind_Press && event->key == key && event->flags == flags) + { + result = 1; + os_eat_event(events, event); + break; + } + } + return result; +} + +internal B32 +os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key) +{ + B32 result = 0; + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && + event->kind == OS_EventKind_Release && event->key == key && event->flags == flags) + { + result = 1; + os_eat_event(events, event); + break; + } + } + return result; +} + +internal B32 +os_text(OS_EventList *events, OS_Handle window, U32 character) +{ + B32 result = 0; + for(OS_Event *event = events->first; event != 0; event = event->next) + { + if((os_handle_match(event->window, window) || os_handle_match(window, os_handle_zero())) && + event->kind == OS_EventKind_Text && event->character == character) + { + result = 1; + os_eat_event(events, event); + break; + } + } + return result; +} + +internal OS_EventList +os_event_list_copy(Arena *arena, OS_EventList *src) +{ + OS_EventList dst = {0}; + for(OS_Event *s = src->first; s != 0; s = s->next) + { + OS_Event *d = push_array(arena, OS_Event, 1); + MemoryCopyStruct(d, s); + d->strings = str8_list_copy(arena, &s->strings); + DLLPushBack(dst.first, dst.last, d); + dst.count += 1; + } + return dst; +} + +internal void +os_event_list_concat_in_place(OS_EventList *dst, OS_EventList *to_push) +{ + if(dst->last && to_push->first) + { + dst->last->next = to_push->first; + to_push->first->prev = dst->last; + dst->last = to_push->last; + dst->count += to_push->count; + } + else if(!dst->last && to_push->first) + { + MemoryCopyStruct(dst, to_push); + } + MemoryZeroStruct(to_push); +} + +internal OS_Event * +os_event_list_push_new(Arena *arena, OS_EventList *evts, OS_EventKind kind) +{ + OS_Event *evt = push_array(arena, OS_Event, 1); + DLLPushBack(evts->first, evts->last, evt); + evts->count += 1; + evt->timestamp_us = os_now_microseconds(); + evt->kind = kind; + return evt; +} diff --git a/src/os/gfx/os_gfx.h b/src/os/gfx/os_gfx.h index 436657ec..b1fd3045 100644 --- a/src/os/gfx/os_gfx.h +++ b/src/os/gfx/os_gfx.h @@ -106,6 +106,7 @@ struct OS_EventList //////////////////////////////// //~ rjf: Event Functions (Helpers, Implemented Once) +internal String8 os_string_from_event_kind(OS_EventKind kind); internal String8List os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags); internal U32 os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key); internal void os_eat_event(OS_EventList *events, OS_Event *event); @@ -114,6 +115,7 @@ internal B32 os_key_release(OS_EventList *events, OS_Handle window, OS_EventFla internal B32 os_text(OS_EventList *events, OS_Handle window, U32 character); internal OS_EventList os_event_list_copy(Arena *arena, OS_EventList *src); internal void os_event_list_concat_in_place(OS_EventList *dst, OS_EventList *to_push); +internal OS_Event *os_event_list_push_new(Arena *arena, OS_EventList *evts, OS_EventKind kind); //////////////////////////////// //~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) @@ -170,7 +172,6 @@ internal Vec2F32 os_dim_from_monitor(OS_Handle monitor); internal void os_send_wakeup_event(void); internal OS_EventList os_get_events(Arena *arena, B32 wait); internal OS_EventFlags os_get_event_flags(void); -internal B32 os_key_is_down(OS_Key key); internal Vec2F32 os_mouse_from_window(OS_Handle window); //////////////////////////////// diff --git a/src/os/gfx/stub/os_gfx_stub.c b/src/os/gfx/stub/os_gfx_stub.c index 134e6b7d..fddc241b 100644 --- a/src/os/gfx/stub/os_gfx_stub.c +++ b/src/os/gfx/stub/os_gfx_stub.c @@ -202,12 +202,6 @@ os_get_event_flags(void) return f; } -internal B32 -os_key_is_down(OS_Key key) -{ - return 0; -} - internal Vec2F32 os_mouse_from_window(OS_Handle window) { diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index e3a665ee..e53e951e 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -99,13 +99,9 @@ os_w32_window_release(OS_W32_Window *window) internal OS_Event * os_w32_push_event(OS_EventKind kind, OS_W32_Window *window) { - OS_Event *result = push_array(os_w32_event_arena, OS_Event, 1); - DLLPushBack(os_w32_event_list.first, os_w32_event_list.last, result); - result->timestamp_us = os_now_microseconds(); - result->kind = kind; + OS_Event *result = os_event_list_push_new(os_w32_event_arena, &os_w32_event_list, kind); result->window = os_w32_handle_from_window(window); result->flags = os_get_event_flags(); - os_w32_event_list.count += 1; return result; } @@ -1413,18 +1409,6 @@ os_get_event_flags(void) return(flags); } -internal B32 -os_key_is_down(OS_Key key) -{ - B32 result = 0; - { - WPARAM vkey_code = os_w32_vkey_from_os_key(key); - SHORT state = GetAsyncKeyState(vkey_code); - result = !!(state & (0x8000)); - } - return result; -} - internal Vec2F32 os_mouse_from_window(OS_Handle handle) { diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 4357fe0b..52056791 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -5,7 +5,7 @@ //~ rjf: Build Options #define BUILD_TITLE "ryan_scratch" -#define BUILD_CONSOLE_INTERFACE 1 +#define OS_FEATURE_GRAPHICAL 1 //////////////////////////////// //~ rjf: Includes @@ -46,5 +46,28 @@ internal void entry_point(CmdLine *cmdline) { - printf("Hello, World!\n"); + OS_Handle window = os_window_open(v2f32(1280, 720), 0, str8_lit("Window")); + os_window_first_paint(window); + for(B32 quit = 0; !quit;) + { + Temp scratch = scratch_begin(0, 0); + OS_EventList events = os_get_events(scratch.arena, 0); + for(OS_Event *ev = events.first; ev != 0; ev = ev->next) + { + if(ev->kind != OS_EventKind_MouseMove) + { + printf("%.*s (%.*s)\n", str8_varg(os_string_from_event_kind(ev->kind)), str8_varg(os_g_key_display_string_table[ev->key])); + fflush(stdout); + } + } + for(OS_Event *ev = events.first; ev != 0; ev = ev->next) + { + if(ev->kind == OS_EventKind_WindowClose) + { + quit = 1; + break; + } + } + scratch_end(scratch); + } }