From 772adc67a32d5045176351124886dd0d280422e6 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 7 Nov 2017 16:35:26 -0500 Subject: [PATCH] mac layer almost finished --- 4coder_API/types.h | 10 +- 4coder_default_bindings.cpp | 1 + 4coder_default_include.cpp | 16 +- 4coder_lib/4coder_table.h | 4 +- 4ed_command.cpp | 24 +- meta/4ed_build.cpp | 3 +- platform_all/4ed_system_shared.cpp | 1 - platform_linux/linux_4ed.cpp | 8 +- platform_mac/mac_4ed.cpp | 226 +++++++++---- platform_mac/mac_4ed.m | 338 +++++++++++++++++--- platform_mac/mac_4ed_file_track.cpp | 15 + platform_mac/osx_objective_c_to_cpp_links.h | 23 +- platform_win32/win32_4ed.cpp | 2 +- project.4coder | 7 + 14 files changed, 550 insertions(+), 128 deletions(-) diff --git a/4coder_API/types.h b/4coder_API/types.h index 1755c23b..78add0d9 100644 --- a/4coder_API/types.h +++ b/4coder_API/types.h @@ -35,6 +35,7 @@ ENUM(int32_t, Key_Modifier_Index){ MDFR_SHIFT_INDEX, MDFR_CONTROL_INDEX, MDFR_ALT_INDEX, + MDFR_COMMAND_INDEX, MDFR_CAPS_INDEX, MDFR_HOLD_INDEX, @@ -46,10 +47,11 @@ ENUM(int32_t, Key_Modifier_Index){ Flags can be combined with bit or to specify a state with multiple modifiers.) */ ENUM(uint32_t, Key_Modifier_Flag){ /* DOC(MDFR_NONE specifies that no modifiers are pressed.) */ - MDFR_NONE = 0x0, - MDFR_CTRL = 0x1, - MDFR_ALT = 0x2, - MDFR_SHIFT = 0x4, + MDFR_NONE = 0x0, + MDFR_CTRL = 0x1, + MDFR_ALT = 0x2, + MDFR_COMMAND = 0x4, + MDFR_SHIFT = 0x8, }; /* DOC(A Command_ID is used as a name for commands implemented internally in 4coder.) */ diff --git a/4coder_default_bindings.cpp b/4coder_default_bindings.cpp index 4ebb26ed..0214cbb2 100644 --- a/4coder_default_bindings.cpp +++ b/4coder_default_bindings.cpp @@ -163,6 +163,7 @@ default_keys(Bind_Helper *context){ bind(context, key_back, MDFR_CTRL, backspace_word); bind(context, key_del, MDFR_CTRL, delete_word); bind(context, key_back, MDFR_ALT, snipe_token_or_word); + bind(context, key_del, MDFR_ALT, snipe_token_or_word_right); bind(context, ' ', MDFR_CTRL, set_mark); bind(context, 'a', MDFR_CTRL, replace_in_range); diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp index ff82f67f..daaac17f 100644 --- a/4coder_default_include.cpp +++ b/4coder_default_include.cpp @@ -130,13 +130,25 @@ CUSTOM_COMMAND_SIG(snipe_token_or_word){ View_Summary view = get_active_view(app, access); Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); - int32_t pos1 = buffer_boundary_seek(app, &buffer, view.cursor.pos, 0, BoundaryToken | BoundaryWhitespace); - int32_t pos2 = buffer_boundary_seek(app, &buffer, pos1, 1, BoundaryToken | BoundaryWhitespace); + int32_t pos1 = buffer_boundary_seek(app, &buffer, view.cursor.pos, false, BoundaryToken | BoundaryWhitespace); + int32_t pos2 = buffer_boundary_seek(app, &buffer, pos1, true, BoundaryToken | BoundaryWhitespace); Range range = make_range(pos1, pos2); buffer_replace_range(app, &buffer, range.start, range.end, 0, 0); } +CUSTOM_COMMAND_SIG(snipe_token_or_word_right){ + uint32_t access = AccessOpen; + + View_Summary view = get_active_view(app, access); + Buffer_Summary buffer = get_buffer(app, view.buffer_id, access); + + int32_t pos2 = buffer_boundary_seek(app, &buffer, view.cursor.pos, true, BoundaryToken | BoundaryWhitespace); + int32_t pos1 = buffer_boundary_seek(app, &buffer, pos2, false, BoundaryToken | BoundaryWhitespace); + + Range range = make_range(pos1, pos2); + buffer_replace_range(app, &buffer, range.start, range.end, 0, 0); +} // // Line Manipulation diff --git a/4coder_lib/4coder_table.h b/4coder_lib/4coder_table.h index e04df977..ccefbd1d 100644 --- a/4coder_lib/4coder_table.h +++ b/4coder_lib/4coder_table.h @@ -62,8 +62,8 @@ struct Table{ static i32_4tech table_required_mem_size(i32_4tech table_size, i32_4tech item_size){ - i32_4tech hash_size = ((table_size * sizeof(u32_4tech)) + 7) & ~7; - i32_4tech mem_size = hash_size + table_size * item_size; + i32_4tech hash_size = ((table_size*sizeof(u32_4tech)) + 7) & ~7; + i32_4tech mem_size = hash_size + table_size*item_size; return(mem_size); } diff --git a/4ed_command.cpp b/4ed_command.cpp index 0d6d3590..a3a20e84 100644 --- a/4ed_command.cpp +++ b/4ed_command.cpp @@ -168,27 +168,29 @@ internal Command_Binding map_extract(Command_Map *map, Key_Event_Data key){ Command_Binding bind = {0}; - b32 ctrl = key.modifiers[MDFR_CONTROL_INDEX]; - b32 alt = key.modifiers[MDFR_ALT_INDEX]; - b32 shift = key.modifiers[MDFR_SHIFT_INDEX]; - u8 command = MDFR_NONE; + b32 ctrl = key.modifiers[MDFR_CONTROL_INDEX]; + b32 alt = key.modifiers[MDFR_ALT_INDEX]; + b32 command = key.modifiers[MDFR_COMMAND_INDEX]; + b32 shift = key.modifiers[MDFR_SHIFT_INDEX]; - if (shift) command |= MDFR_SHIFT; - if (ctrl) command |= MDFR_CTRL; - if (alt) command |= MDFR_ALT; + u8 mod_flags = MDFR_NONE; + if (ctrl) mod_flags |= MDFR_CTRL; + if (command) mod_flags |= MDFR_COMMAND; + if (alt) mod_flags |= MDFR_ALT; + if (shift) mod_flags |= MDFR_SHIFT; Key_Code code = key.character_no_caps_lock; if (code == 0){ code = key.keycode; - map_find(map, code, command, &bind); + map_find(map, code, mod_flags, &bind); } else{ if (code != '\n' && code != '\t' && code != ' '){ - command &= ~(MDFR_SHIFT); + mod_flags &= ~(MDFR_SHIFT); } - map_find(map, code, command, &bind); + map_find(map, code, mod_flags, &bind); if (bind.function == 0){ - map_get_vanilla_keyboard_default(map, command, &bind); + map_get_vanilla_keyboard_default(map, mod_flags, &bind); } } diff --git a/meta/4ed_build.cpp b/meta/4ed_build.cpp index 6f460736..edb044ea 100644 --- a/meta/4ed_build.cpp +++ b/meta/4ed_build.cpp @@ -319,8 +319,9 @@ build(u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, c "-Wno-write-strings -Wno-deprecated-declarations " \ "-Wno-comment -Wno-switch -Wno-null-dereference " -#define GCC_LIBS \ +#define GCC_LIBS \ "-framework Cocoa -framework QuartzCore " \ +"-framework CoreServices " \ "-framework OpenGL -framework IOKit -lfreetype" #else diff --git a/platform_all/4ed_system_shared.cpp b/platform_all/4ed_system_shared.cpp index a64fd53a..2b395c47 100644 --- a/platform_all/4ed_system_shared.cpp +++ b/platform_all/4ed_system_shared.cpp @@ -490,7 +490,6 @@ private_draw_glyph_mono(System_Functions *system, Render_Target *t, Render_Font internal void launch_rendering(System_Functions *system, Render_Target *t){ - DBG_POINT(); char *cursor = t->push_buffer; char *cursor_end = cursor + t->size; diff --git a/platform_linux/linux_4ed.cpp b/platform_linux/linux_4ed.cpp index eb8b751c..15d4bb2c 100644 --- a/platform_linux/linux_4ed.cpp +++ b/platform_linux/linux_4ed.cpp @@ -905,12 +905,7 @@ LinuxKeycodeInit(Display* dpy){ int key_count = (key_max - key_min) + 1; - KeySym* syms = XGetKeyboardMapping( - dpy, - key_min, - key_count, - &syms_per_code - ); + KeySym* syms = XGetKeyboardMapping(dpy, key_min, key_count, &syms_per_code); if (!syms) return; @@ -1824,6 +1819,7 @@ main(int argc, char **argv){ linuxvars.input.clipboard = null_string; } + // HACK(allen): THIS SHIT IS FUCKED (happens on mac too) b32 keep_running = linuxvars.keep_running; app.step(&sysfunc, &target, &memory_vars, &linuxvars.input, &result); diff --git a/platform_mac/mac_4ed.cpp b/platform_mac/mac_4ed.cpp index 90e1835f..18687d79 100644 --- a/platform_mac/mac_4ed.cpp +++ b/platform_mac/mac_4ed.cpp @@ -11,14 +11,6 @@ #define IS_PLAT_LAYER -#include - -#if 0 -#define DBG_POINT() fprintf(stdout, "%s\n", __FILE__ ":" LINE_STR ":") -#else -#define DBG_POINT() -#endif - #include "4ed_defines.h" #include "4coder_API/version.h" @@ -87,6 +79,9 @@ struct OSX_Vars{ Application_Step_Input input; String clipboard_contents; b32 keep_running; + + b32 has_prev_time; + u64 prev_time_u; }; //////////////////////////////// @@ -162,7 +157,8 @@ Sys_Is_Fullscreen_Sig(system_is_fullscreen){ // HACK(allen): Why does this work differently from the win32 version!? internal Sys_Send_Exit_Signal_Sig(system_send_exit_signal){ - osx_objc.running = false; + DBG_POINT(); + osxvars.keep_running = false; } #include "4ed_coroutine_functions.cpp" @@ -193,31 +189,108 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ // CLI // +// HACK(allen): ALMOST an exact duplicate from the Linux version. Just epoll doesn't port. deduplicate. internal Sys_CLI_Call_Sig(system_cli_call){ - // b32 #(char *path, char *script_name, CLI_Handles *cli_out) - NotImplemented; + i32 pipe_fds[2]; + if (pipe(pipe_fds) == -1){ + DBG_POINT(); + return 0; + } + + i32 child_pid = fork(); + if (child_pid == -1){ + DBG_POINT(); + return 0; + } + + enum { PIPE_FD_READ, PIPE_FD_WRITE }; + + // child + if (child_pid == 0){ + close(pipe_fds[PIPE_FD_READ]); + dup2(pipe_fds[PIPE_FD_WRITE], STDOUT_FILENO); + dup2(pipe_fds[PIPE_FD_WRITE], STDERR_FILENO); + + if (chdir(path) == -1){ + DBG_POINT(); + exit(1); + } + + char* argv[] = { "sh", "-c", script_name, NULL }; + + if (execv("/bin/sh", argv) == -1){ + DBG_POINT(); + } + exit(1); + } + else{ + close(pipe_fds[PIPE_FD_WRITE]); + + *(pid_t*)&cli_out->proc = child_pid; + *(int*)&cli_out->out_read = pipe_fds[PIPE_FD_READ]; + *(int*)&cli_out->out_write = pipe_fds[PIPE_FD_WRITE]; + + // TODO(allen): Getting updates when there is new something new on the pipe!? + } + return(true); } internal Sys_CLI_Begin_Update_Sig(system_cli_begin_update){ - // void #(CLI_Handles *cli) - NotImplemented; + // NOTE(inso): I don't think anything needs to be done here. } internal Sys_CLI_Update_Step_Sig(system_cli_update_step){ - // b32 #(CLI_Handles *cli, char *dest, u32 max, u32 *amount) - NotImplemented; - return(0); + i32 pipe_read_fd = *(i32*)&cli->out_read; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(pipe_read_fd, &fds); + + struct timeval tv = {}; + + size_t space_left = max; + char* ptr = dest; + + while (space_left > 0 && select(pipe_read_fd + 1, &fds, NULL, NULL, &tv) == 1){ + ssize_t num = read(pipe_read_fd, ptr, space_left); + if (num == -1){ + DBG_POINT(); + } else if (num == 0){ + // NOTE(inso): EOF + break; + } else { + ptr += num; + space_left -= num; + } + } + + *amount = (ptr - dest); + return((ptr - dest) > 0); } internal Sys_CLI_End_Update_Sig(system_cli_end_update){ - // b32 #(CLI_Handles *cli) - NotImplemented; - return(false); + pid_t pid = *(pid_t*)&cli->proc; + b32 close_me = false; + + int status; + if (pid && waitpid(pid, &status, WNOHANG) > 0){ + close_me = true; + + cli->exit = WEXITSTATUS(status); + + //struct epoll_event e = {}; + //epoll_ctl(linuxvars.epoll, EPOLL_CTL_DEL, *(int*)&cli->out_read, &e); + + close(*(int*)&cli->out_read); + close(*(int*)&cli->out_write); + } + + return(close_me); } #include "4ed_font_data.h" @@ -230,17 +303,20 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ external void* osx_allocate(umem size){ - DBG_POINT(); void *result = system_memory_allocate(size); return(result); } +external void +osx_free(void *ptr, umem size){ + system_memory_free(ptr, size); +} + external void osx_resize(int width, int height){ - DBG_POINT(); osx_objc.width = width; osx_objc.height = height; - + if (width > 0 && height > 0){ glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); @@ -260,7 +336,7 @@ osx_push_key(Key_Code code, Key_Code chr, Key_Code chr_nocaps, b8 *mods) if (count < KEY_INPUT_BUFFER_SIZE){ Key_Event_Data *data = osxvars.input.keys.keys; - + data[count].keycode = code; data[count].character = chr; data[count].character_no_caps_lock = chr_nocaps; @@ -273,7 +349,6 @@ osx_push_key(Key_Code code, Key_Code chr, Key_Code chr_nocaps, b8 *mods) external void osx_character_input(u32 code, OSX_Keyboard_Modifiers modifier_flags){ - DBG_POINT(); Key_Code c = 0; switch (code){ // TODO(allen): Find the canonical list of these things. @@ -283,34 +358,36 @@ osx_character_input(u32 code, OSX_Keyboard_Modifiers modifier_flags){ case 0xF702: c = key_left; break; case 0xF703: c = key_right; break; case 0x001B: c = key_esc; break; - + case 0xF704: c = key_f1; break; case 0xF705: c = key_f2; break; case 0xF706: c = key_f3; break; case 0xF707: c = key_f4; break; - + case 0xF708: c = key_f5; break; case 0xF709: c = key_f6; break; case 0xF70A: c = key_f7; break; case 0xF70B: c = key_f8; break; - + case 0xF70C: c = key_f9; break; case 0xF70D: c = key_f10; break; case 0xF70E: c = key_f11; break; case 0xF70F: c = key_f12; break; - + case 0xF710: c = key_f13; break; case 0xF711: c = key_f14; break; case 0xF712: c = key_f15; break; case 0xF713: c = key_f16; break; } - + fprintf(stdout, "INPUT: %c\n", (char)code); + b8 mods[MDFR_INDEX_COUNT] = {0}; - if (modifier_flags.shift) mods[MDFR_SHIFT_INDEX] = 1; - if (modifier_flags.command) mods[MDFR_CONTROL_INDEX] = 1; - if (modifier_flags.caps) mods[MDFR_CAPS_INDEX] = 1; - if (modifier_flags.control) mods[MDFR_ALT_INDEX] = 1; + if (modifier_flags.shift) mods[MDFR_SHIFT_INDEX] = true; + if (modifier_flags.control) mods[MDFR_CONTROL_INDEX] = true; + if (modifier_flags.option) mods[MDFR_ALT_INDEX] = true; + if (modifier_flags.command) mods[MDFR_COMMAND_INDEX] = true; + if (modifier_flags.caps) mods[MDFR_CAPS_INDEX] = true; if (c != 0){ osx_push_key(c, 0, 0, mods); @@ -319,16 +396,17 @@ osx_character_input(u32 code, OSX_Keyboard_Modifiers modifier_flags){ if (code == '\r'){ code = '\n'; } + Key_Code chr = code; Key_Code nocaps = code; if (modifier_flags.caps){ - if ('a' <= nocaps && nocaps <= 'z'){ - nocaps += 'A' - 'a'; + if ('a' <= chr && chr <= 'z'){ + chr += 'A' - 'a'; } - else if ('A' <= nocaps && nocaps <= 'Z'){ - nocaps += 'a' - 'A'; + else if ('A' <= chr && chr <= 'Z'){ + chr += 'a' - 'A'; } } - osx_push_key(code, code, nocaps, mods); + osx_push_key(code, chr, nocaps, mods); } else{ osx_push_key(0, 0, 0, mods); @@ -337,21 +415,20 @@ osx_character_input(u32 code, OSX_Keyboard_Modifiers modifier_flags){ external void osx_mouse(i32 mx, i32 my, u32 type){ - DBG_POINT(); osxvars.input.mouse.x = mx; - osxvars.input.mouse.y = my; + osxvars.input.mouse.y = osx_objc.height - my; if (type == MouseType_Press){ osxvars.input.mouse.press_l = true; osxvars.input.mouse.l = true; } if (type == MouseType_Release){ + osxvars.input.mouse.release_l = true; osxvars.input.mouse.l = false; } } external void osx_mouse_wheel(float dx, float dy){ - DBG_POINT(); if (dy > 0){ osxvars.input.mouse.wheel = 1; } @@ -361,16 +438,38 @@ osx_mouse_wheel(float dx, float dy){ } external void -osx_step(){ +osx_try_to_close(void){ + system_send_exit_signal(); +} + +external void +osx_step(void){ Application_Step_Result result = {}; result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; result.trying_to_kill = !osxvars.keep_running; - osxvars.input.clipboard = null_string; - - app.step(&sysfunc, &target, &memory_vars, &osxvars.input, &result); - launch_rendering(&sysfunc, &target); - + if (osx_objc.has_clipboard_item){ + //void *clipboard_data; + //umem clipboard_size, clipboard_max; + osxvars.input.clipboard = make_string(osx_objc.clipboard_data, (i32)osx_objc.clipboard_size); + } + else{ + osxvars.input.clipboard = null_string; + } + + osxvars.input.dt = 1.f/60.f; + if (osxvars.has_prev_time){ + u64 time_u = system_now_time(); + u64 time_elapsed_u = time_u - osxvars.prev_time_u; + osxvars.input.dt = time_elapsed_u/1000000.f; + osxvars.prev_time_u = time_u; + } + else{ + osxvars.has_prev_time = true; + osxvars.prev_time_u = system_now_time(); + } + + Application_Step_Input frame_input = osxvars.input; osxvars.input.first_step = false; osxvars.input.keys = null_key_input_data; osxvars.input.mouse.press_l = false; @@ -378,6 +477,20 @@ osx_step(){ osxvars.input.mouse.press_r = false; osxvars.input.mouse.release_r = false; osxvars.input.mouse.wheel = 0; + + // HACK(allen): THIS SHIT IS FUCKED (happens on linux too) + b32 keep_running = osxvars.keep_running; + + app.step(&sysfunc, &target, &memory_vars, &frame_input, &result); + + if (result.perform_kill){ + osx_close_app(); + } + else if (!keep_running && !osxvars.keep_running){ + osxvars.keep_running = true; + } + + launch_rendering(&sysfunc, &target); } external void @@ -387,7 +500,7 @@ osx_init(){ // // OpenGL Init // - + typedef PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackProc; GLXLOAD(glDebugMessageCallback); @@ -403,7 +516,7 @@ osx_init(){ glEnable(GL_SCISSOR_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + // // System Linkage // @@ -425,7 +538,7 @@ osx_init(){ memset(&custom_api, 0, sizeof(custom_api)); memory_init(); - + osxvars.keep_running = true; osxvars.input.first_step = true; @@ -470,7 +583,7 @@ osx_init(){ DBG_POINT(); coroutines_init(); - + // // Font System Init // @@ -492,20 +605,19 @@ osx_init(){ String curdir = make_string(cwd, size); terminate_with_null(&curdir); replace_char(&curdir, '\\', '/'); - + DBG_POINT(); - + String clipboard_string = {0}; if (osx_objc.has_clipboard_item){ clipboard_string = make_string(osx_objc.clipboard_data, osx_objc.clipboard_size); } - + DBG_POINT(); - fprintf(stdout, "%p\n", app.init); - + LOG("Initializing application variables\n"); app.init(&sysfunc, &target, &memory_vars, clipboard_string, curdir, custom_api); - + DBG_POINT(); } diff --git a/platform_mac/mac_4ed.m b/platform_mac/mac_4ed.m index 95876af7..18ba823f 100644 --- a/platform_mac/mac_4ed.m +++ b/platform_mac/mac_4ed.m @@ -9,7 +9,9 @@ // TOP +#define inline internal #include "4ed_defines.h" +#undef inline #include "4coder_API/version.h" #include "4coder_API/keycodes.h" @@ -22,12 +24,20 @@ #include "osx_objective_c_to_cpp_links.h" +#include #import #import #import #import #import +#include +#include +#include +#include + +#include + void osx_post_to_clipboard(char *str){ NSPasteboard *board = [NSPasteboard generalPasteboard]; @@ -117,10 +127,16 @@ static DISPLINK_SIG(osx_display_link); osx_mouse_wheel(dx, dy); } +- (BOOL)windowShouldClose:(NSWindow*)sender{ + osx_try_to_close(); + return(NO); +} + - (CVReturn)getFrameForTime:(const CVTimeStamp*)time{ @autoreleasepool { if (osx_objc.running){ + osx_objc.has_clipboard_item = false; NSPasteboard *board = [NSPasteboard generalPasteboard]; if (board.changeCount != osx_objc.prev_clipboard_change_count){ if (!osx_objc.just_posted_to_clipboard){ @@ -169,8 +185,7 @@ static DISPLINK_SIG(osx_display_link); - (void)init_gl { - if(osx_objc.running) - { + if(osx_objc.running){ return; } @@ -190,10 +205,9 @@ static DISPLINK_SIG(osx_display_link); }; NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; - if(format == nil) - { - fprintf(stderr, "Error creating OpenGLPixelFormat\n"); - exit(1); + if(format == nil){ + fprintf(stderr, "Error creating OpenGLPixelFormat\n"); + exit(1); } NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil]; @@ -286,55 +300,297 @@ DISPLINK_SIG(osx_display_link){ } @end +typedef struct File_Table_Entry{ + u64 hash; + void *name; + i32 fd; +} File_Table_Entry; + typedef struct File_Change_Queue{ - char *buffer; - char *read_ptr; - char *write_ptr; - char *end; + i32 kq; + + File_Table_Entry *table; + i32 table_count; + i32 table_size; } File_Change_Queue; static File_Change_Queue file_change_queue = {0}; -void -osx_add_file_listener(char *file_name){ - NotImplemented; +void* +osx_file_name_prefixed_length(char *name){ + i32 len = 0; + for (; name[len] != 0; ++len); + char *name_stored = (char*)malloc(4 + l_round_up_u32(len, 4)); + *(i32*)name_stored = len; + memcpy(name_stored + 4, name, len); + return(name_stored); +} + +b32 +osx_name_prefixed_match(void *a, void *b){ + b32 result = false; + i32 *len_a = (i32*)a; + i32 *len_b = (i32*)b; + if (*len_a == *len_b){ + char *str_a = (char*)(len_a + 1); + char *str_b = (char*)(len_b + 1); + if (strncmp(str_a, str_b, *len_a) == 0){ + result = true; + } + } + return(result); +} + +File_Table_Entry* +osx_file_listener_lookup_and_return_pointer(u64 hash, void *name){ + File_Table_Entry *result = 0; + i32 index = (i32)(hash % file_change_queue.table_size); + i32 first_index = index; + + for (;;){ + File_Table_Entry *entry = &file_change_queue.table[index]; + if (entry->hash == hash){ + if (osx_name_prefixed_match(name, entry->name)){ + result = entry; + break; + } + } + if (entry->name == 0){ + break; + } + + index = (index + 1)%file_change_queue.table_size; + if (index == first_index){ + break; + } + } + + return(result); +} + +b32 +osx_file_listener_lookup(u64 hash, void *name, i32 *fd_out){ + b32 found = false; + File_Table_Entry *entry = osx_file_listener_lookup_and_return_pointer(hash, name); + if (entry != 0){ + found = true; + if (fd_out != 0){ + *fd_out = entry->fd; + } + } + return(found); +} + +b32 +osx_file_listener_lookup_and_delete(u64 hash, void *name, i32 *fd_out){ + b32 found = false; + File_Table_Entry *entry = osx_file_listener_lookup_and_return_pointer(hash, name); + if (entry != 0){ + found = true; + if (fd_out != 0){ + *fd_out = entry->fd; + } + memset(entry, 0, sizeof(*entry)); + entry->name = (void*)1; + } + return(found); +} + +typedef struct Hash_Result{ + b32 is_in_table; + b32 was_already_in_table; +} Hash_Result; + +u64 +osx_file_hash(void *name){ + u32 count = *(u32*)(name); + char *str = (char*)name + 4; + u64 hash = 0; + u64 state = count; + u64 inc = 1 + 2*count; + for (u32 i = 0; i <= count; ++i){ + u64 old_state = state; + state = state*6364136223846783005ULL + inc; + u32 xorshifted = ((old_state >> 18u) ^ old_state) >> 27u; + u32 rot = old_state >> 59u; + hash = (hash << 3) + (hash & 1) + ((xorshifted >> rot) | (xorshifted << ((-rot) & 31))); + if (i < count){ + inc = 1 + 2*(((inc - 1) << 7) | (u8)str[i]); + } + } + return(hash); +} + +Hash_Result +osx_file_listener_hash(u64 hash, void *name, i32 fd){ + Hash_Result result = {0}; + if (osx_file_listener_lookup(hash, name, 0)){ + result.is_in_table = true; + result.was_already_in_table = true; + } + else if (file_change_queue.table_count * 6 < file_change_queue.table_size * 5){ + i32 index = (i32)(hash % file_change_queue.table_size); + i32 first_index = index; + + for (;;){ + File_Table_Entry *entry = &file_change_queue.table[index]; + if (entry->name == 0 || entry->name == (void*)1){ + entry->hash = hash; + entry->name = name; + entry->fd = fd; + result.is_in_table = true; + ++file_change_queue.table_count; + break; + } + + index = (index + 1)%file_change_queue.table_size; + if (index == first_index){ + break; + } + } + + if (!result.is_in_table){ + fprintf(stdout, "file change listener table error: could not find a free slot in the table\n"); + } + } + + return(result); +} + +Hash_Result +osx_file_listener_hash_bundled(File_Table_Entry entry){ + Hash_Result result = osx_file_listener_hash(entry.hash, entry.name, entry.fd); + return(result); } void -osx_remove_file_listener(char *file_name){ - NotImplemented; +osx_file_listener_grow_table(i32 table_size){ + if (file_change_queue.table_size < table_size){ + File_Table_Entry *old_table = file_change_queue.table; + i32 old_size = file_change_queue.table_size; + + file_change_queue.table = (File_Table_Entry*)osx_allocate(table_size*sizeof(File_Table_Entry)); + memset(file_change_queue.table, 0, table_size*sizeof(File_Table_Entry)); + file_change_queue.table_size = table_size; + + for (i32 i = 0; i < old_size; ++i){ + void *name = file_change_queue.table[i].name; + if (name != 0 && name != (void*)1){ + osx_file_listener_hash_bundled(file_change_queue.table[i]); + } + } + + if (old_table != 0){ + osx_free(old_table, old_size*sizeof(File_Table_Entry)); + } + } } void -block_split_copy(void *dst, void *src1, i32 size1, void *src2, i32 size2){ - memcpy(dst, src1, size1); - memcpy((u8*)dst + size1, src2, size2); +osx_file_listener_double_table(){ + osx_file_listener_grow_table(file_change_queue.table_size*2); +} + +b32 +osx_file_listener_hash_always(u64 hash, void *name, i32 fd){ + b32 was_already_in_table = false; + Hash_Result result = osx_file_listener_hash(hash, name, fd); + if (result.was_already_in_table){ + was_already_in_table = true; + } + else if (!result.is_in_table){ + osx_file_listener_double_table(); + osx_file_listener_hash(hash, name, fd); + } + return(was_already_in_table); +} + +void +osx_file_listener_init(void){ + memset(&file_change_queue, 0, sizeof(file_change_queue)); + file_change_queue.kq = kqueue(); + osx_file_listener_grow_table(1024); +} + +void +osx_add_file_listener(char *dir_name){ + DBG_POINT(); + if (file_change_queue.kq < 0){ + return; + } + + fprintf(stdout, "ADD_FILE_LISTENER: %s\n", dir_name); + + i32 fd = open(dir_name, O_EVTONLY); + if (fd <= 0){ + fprintf(stdout, "could not open fd for %s\n", dir_name); + return; + } + + // TODO(allen): Decide what to do about these darn string mallocs. + void *name_stored = osx_file_name_prefixed_length(dir_name); + + struct kevent new_kevent; + EV_SET(&new_kevent, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_DELETE|NOTE_WRITE, 0, name_stored); + + struct timespec t = {0}; + kevent(file_change_queue.kq, &new_kevent, 1, 0, 0, &t); + + b32 was_already_in_table = osx_file_listener_hash_always(osx_file_hash(name_stored), name_stored, fd); + if (was_already_in_table){ + free(name_stored); + } + + DBG_POINT(); +} + +void +osx_remove_file_listener(char *dir_name){ + void *name = osx_file_name_prefixed_length(dir_name); + i32 fd; + if (osx_file_listener_lookup_and_delete(osx_file_hash(name), name, &fd)){ + close(fd); + } + free(name); } i32 osx_get_file_change_event(char *buffer, i32 max, i32 *size){ - i32 result = 0; - if (file_change_queue.read_ptr != file_change_queue.write_ptr){ - i32 change_size = *(i32*)file_change_queue.read_ptr; - if (max <= change_size){ - char *b1 = file_change_queue.read_ptr + 4; - char *b2 = file_change_queue.buffer; - i32 b1_size = Min(change_size, (i32)(file_change_queue.end - b1)); - i32 b2_size = change_size - b1_size; - block_split_copy(buffer, b1, b1_size, b2, b2_size); - if (b1 < file_change_queue.end){ - file_change_queue.read_ptr = b1 + change_size; - } - else{ - file_change_queue.read_ptr = b2 + b2_size; - } - result = 1; - } - else{ - result = -1; - } - } - return(result); + if (file_change_queue.kq < 0){ + return 0; + } + + i32 result = 0; + struct timespec t = {0}; + struct kevent event_out; + i32 count = kevent(file_change_queue.kq, 0, 0, &event_out, 1, &t); + if (count < 0 || (count > 0 && event_out.flags == EV_ERROR)){ + fprintf(stdout, "count: %4d error: %s\n", count, strerror(errno)); + } + else if (count > 0){ + if (event_out.udata != 0){ + i32 len = *(i32*)event_out.udata; + char *str = (char*)((i32*)event_out.udata + 1); + fprintf(stdout, "got an event for file: %.*s\n", len, str); + if (len <= max){ + *size = len; + memcpy(buffer, str, len); + result = 1; + } + else{ + // TODO(allen): Cache this miss for retrieval??? + // TODO(allen): Better yet, always cache every event on every platform and therefore make two calls per event, but always with enough memory!?? + result = -1; + } + } + } + + return(result); +} + +void +osx_close_app(void){ + [NSApp terminate: nil]; } int @@ -347,6 +603,8 @@ main(int argc, char **argv){ osx_objc.argc = argc; osx_objc.argv = argv; + osx_file_listener_init(); + @autoreleasepool{ NSApplication *app = [NSApplication sharedApplication]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; diff --git a/platform_mac/mac_4ed_file_track.cpp b/platform_mac/mac_4ed_file_track.cpp index b736b429..35c2ef4b 100644 --- a/platform_mac/mac_4ed_file_track.cpp +++ b/platform_mac/mac_4ed_file_track.cpp @@ -19,14 +19,29 @@ init_track_system(File_Track_System *system, Partition *scratch, void *table_mem File_Track_Result add_listener(File_Track_System *system, Partition *scratch, u8 *filename){ File_Track_Result result = FileTrack_Good; +#if 1 +#if 0 + // HACK(allen) HACK(allen) HACK(allen) + char strspace[1024]; + String str = make_fixed_width_string(strspace); + copy(&str, (char*)filename); + remove_last_folder(&str); + --str.size; + terminate_with_null(&str); + osx_add_file_listener(str.str); +#else osx_add_file_listener((char*)filename); +#endif +#endif return(result); } File_Track_Result remove_listener(File_Track_System *system, Partition *scratch, u8 *filename){ File_Track_Result result = FileTrack_Good; +#if 1 osx_remove_file_listener((char*)filename); +#endif return(result); } diff --git a/platform_mac/osx_objective_c_to_cpp_links.h b/platform_mac/osx_objective_c_to_cpp_links.h index e25fac70..77233068 100644 --- a/platform_mac/osx_objective_c_to_cpp_links.h +++ b/platform_mac/osx_objective_c_to_cpp_links.h @@ -12,6 +12,14 @@ #if !defined(OSX_OBJECTIVE_C_TO_CPP_LINKS_H) #define OSX_OBJECTIVE_C_TO_CPP_LINKS_H +#include + +#if 0 +#define DBG_POINT() fprintf(stdout, "%s\n", __FILE__ ":" LINE_STR ":") +#else +#define DBG_POINT() +#endif + typedef enum OSX_Mouse_Event_Type{ MouseType_Move, MouseType_Press, @@ -37,13 +45,13 @@ typedef struct OSX_Objective_C_Vars{ void *clipboard_data; umem clipboard_size, clipboard_max; b32 just_posted_to_clipboard; - + char *clipboard_space; umem clipboard_space_max; - + b32 full_screen; b32 do_toggle; - + i32 argc; char **argv; } OSX_Objective_C_Vars; @@ -54,6 +62,9 @@ extern OSX_Objective_C_Vars osx_objc; external void* osx_allocate(umem size); +external void +osx_free(void *ptr, umem size); + external void osx_resize(int width, int height); @@ -66,6 +77,9 @@ osx_mouse(i32 mx, i32 my, u32 type); external void osx_mouse_wheel(float dx, float dy); +external void +osx_try_to_close(void); + external void osx_step(); @@ -88,6 +102,9 @@ osx_remove_file_listener(char *file_name); external i32 osx_get_file_change_event(char *buffer, i32 max, i32 *size); +external void +osx_close_app(void); + #endif // BOTTOM diff --git a/platform_win32/win32_4ed.cpp b/platform_win32/win32_4ed.cpp index 26d920f8..8aa01333 100644 --- a/platform_win32/win32_4ed.cpp +++ b/platform_win32/win32_4ed.cpp @@ -940,7 +940,7 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ case WM_DESTROY: { win32vars.got_useful_event = true; - win32vars.input_chunk.trans.trying_to_kill = 1; + win32vars.input_chunk.trans.trying_to_kill = true; }break; case WM_4coder_ANIMATE: diff --git a/project.4coder b/project.4coder index 2c59a44b..5fe1c33e 100644 --- a/project.4coder +++ b/project.4coder @@ -14,3 +14,10 @@ fkey_command_linux[2] = {"build_site.sh" , "*site*" , fals fkey_command_linux[3] = {"build_string.sh" , "*compilation*" , true , true }; fkey_command_linux[4] = {"echo build: x86 & ./build.sh -DDEV_BUILD_X86" , "*compilation*", true, true }; fkey_command_linux[12] = {"./package.sh" , "*package*" , false, true }; + +fkey_command_mac[1] = {"echo build: x64 & ./build.sh", "*compilation*" , true , true }; +fkey_command_mac[2] = {"build_site.sh" , "*site*" , false, true }; +fkey_command_mac[3] = {"build_string.sh" , "*compilation*" , true , true }; +fkey_command_mac[4] = {"echo build: x86 & ./build.sh -DDEV_BUILD_X86" , "*compilation*", true, true }; +fkey_command_mac[12] = {"./package.sh" , "*package*" , false, true }; +