diff --git a/4ed_linux_keyboard.cpp b/4ed_linux_keyboard.cpp index e1e9b670..1a3c1040 100644 --- a/4ed_linux_keyboard.cpp +++ b/4ed_linux_keyboard.cpp @@ -40,6 +40,8 @@ keycode_init(Display* dpy, Key_Codes *codes){ // rebound to esc, so there are two KeyCodes for the XK_Escape KeyCode but XKeysymToKeycode only // gets one of them, hence the need for this crazy lookup which works correctly with rebound keys. + memset(keycode_lookup_table, 0, sizeof(keycode_lookup_table)); + struct SymMapping { KeySym sym; Code code; diff --git a/4ed_system.h b/4ed_system.h index 8f89545d..19cc0e3b 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -31,6 +31,9 @@ typedef Sys_File_Time_Stamp_Sig(System_File_Time_Stamp); #define Sys_Set_File_List_Sig(name) void name(File_List *file_list, String directory) typedef Sys_Set_File_List_Sig(System_Set_File_List); +#define Sys_File_Paths_Equal_Sig(name) b32 name(char *path_a, char *path_b) +typedef Sys_File_Paths_Equal_Sig(System_File_Paths_Equal); + #define Sys_Post_Clipboard_Sig(name) void name(String str) typedef Sys_Post_Clipboard_Sig(System_Post_Clipboard); diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 96c5b9bb..d5e95266 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -60,6 +60,8 @@ #include #include #include +#include +#include //#define FRED_USE_FONTCONFIG 1 @@ -367,38 +369,123 @@ Sys_Set_File_List_Sig(system_set_file_list){ } } +Sys_File_Paths_Equal_Sig(system_file_paths_equal){ + b32 result = 0; + + char* real_a = realpath(path_a, NULL); + if(real_a){ + char* real_b = realpath(path_b, NULL); + if(real_b){ + result = strcmp(real_a, real_b) == 0; + free(real_b); + } + free(real_a); + } + + return result; +} + Sys_Post_Clipboard_Sig(system_post_clipboard){ LinuxStringDup(&linuxvars.clipboard_outgoing, str.str, str.size); XSetSelectionOwner(linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, linuxvars.XWindow, CurrentTime); } + Sys_CLI_Call_Sig(system_cli_call){ // TODO(allen): Implement - DBG_FN; - AllowLocal(path); - AllowLocal(script_name); - AllowLocal(cli_out); + +// fprintf(stderr, "cli call: %s, %s\n", path, script_name); + + int pipe_fds[2]; + if(pipe(pipe_fds) == -1){ + perror("system_cli_call: pipe"); + return 0; + } + + pid_t child_pid = fork(); + if(child_pid == -1){ + perror("system_cli_call: fork"); + 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){ + perror("system_cli_call: chdir"); + exit(1); + }; + + //TODO(inso): do spaces in script_name signify multiple args? + char* argv[] = { "sh", script_name, NULL }; + + if(execv("/bin/sh", argv) == -1){ + perror("system_cli_call: execv"); + } + 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]; + } + + return 1; } Sys_CLI_Begin_Update_Sig(system_cli_begin_update){ - // TODO(allen): Implement - DBG_FN; AllowLocal(cli); } Sys_CLI_Update_Step_Sig(system_cli_update_step){ - // TODO(allen): Implement - DBG_FN; - AllowLocal(cli); - AllowLocal(dest); - AllowLocal(max); - AllowLocal(amount); + + int pipe_read_fd = *(int*)&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){ + perror("system_cli_update_step: read"); + } else if(num == 0){ + // NOTE(inso): EOF + break; + } else { + ptr += num; + space_left -= num; + } + } + + *amount = (ptr - dest); + return (ptr - dest) > 0; } Sys_CLI_End_Update_Sig(system_cli_end_update){ - // TODO(allen): Implement - DBG_FN; - AllowLocal(cli); + pid_t pid = *(pid_t*)&cli->proc; + b32 close_me = 0; + + int status; + if(waitpid(pid, &status, WNOHANG) > 0){ + close_me = 1; + cli->exit = WEXITSTATUS(status); + close(*(int*)&cli->out_read); + close(*(int*)&cli->out_write); + } + + return close_me; } static_assert(sizeof(Plat_Handle) >= sizeof(Linux_Semaphore_Handle), "Plat_Handle not big enough"); @@ -470,7 +557,6 @@ ThreadProc(void* arg){ Sys_Post_Job_Sig(system_post_job){ // TODO(allen): Implement - DBG_FN; AllowLocal(group_id); AllowLocal(job); @@ -513,7 +599,6 @@ Sys_Release_Lock_Sig(system_release_lock){ } Sys_Cancel_Job_Sig(system_cancel_job){ - DBG_FN; AllowLocal(group_id); AllowLocal(job_id); @@ -573,11 +658,16 @@ INTERNAL_Sys_Sentinel_Sig(internal_sentinel){ } INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){ - // TODO(allen): Implement - DBG_FN; - AllowLocal(id); - AllowLocal(running); - AllowLocal(pending); + Work_Queue *queue = exchange_vars.thread.queues + id; + u32 write = queue->write_position; + u32 read = queue->read_position; + if (write < read) write += JOB_ID_WRAP; + *pending = (i32)(write - read); + + Thread_Group *group = linuxvars.groups + id; + for (i32 i = 0; i < group->count; ++i){ + running[i] = (group->threads[i].running != 0); + } } INTERNAL_Sys_Debug_Message_Sig(internal_debug_message){ @@ -585,34 +675,70 @@ INTERNAL_Sys_Debug_Message_Sig(internal_debug_message){ } DIRECTORY_HAS_FILE_SIG(system_directory_has_file){ - int result = 0; + + fprintf(stderr, "system_directory_has_file: %.*s %s\n", dir.size, dir.str, filename); - //TODO(inso): implement + int result = 0; char buff[PATH_MAX] = {}; - memcpy(buff, dir.str, dir.size); - printf("Has file %s\n", buff); + size_t fnamesize = strlen(filename); + + if(fnamesize + dir.size + 1 > PATH_MAX){ + fprintf(stderr, "system_directory_has_file: path too long"); + } else { + memcpy(buff, dir.str, dir.size); + memcpy(buff + dir.size, filename, fnamesize + 1); + struct stat st; + result = stat(buff, &st) == 0 && S_ISREG(st.st_mode); + } return(result); } DIRECTORY_CD_SIG(system_directory_cd){ - int result = 0; - // TODO(allen): Implement + + fprintf(stderr, "system_directory_cd: %.*s %s\n", dir->size, dir->str, rel_path); - printf("Dir CD: %.*s\n", dir->size, dir->str); + b32 result = 0; + i32 old_size; + i32 len; + + if (rel_path[0] != 0){ + if (rel_path[0] == '.' && rel_path[1] == 0){ + result = 1; + } + else if (rel_path[0] == '.' && rel_path[1] == '.' && rel_path[2] == 0){ + result = remove_last_folder(dir); + terminate_with_null(dir); + } + else{ + len = str_size(rel_path); + if (dir->size + len + 1 > dir->memory_size){ + old_size = dir->size; + append_partial(dir, rel_path); + append_partial(dir, "/"); + terminate_with_null(dir); - AllowLocal(dir); - AllowLocal(rel_path); + struct stat st; + if(stat(dir->str, &st) == -1){ + perror("system_directory_cd: stat"); + result = 0; + } else { + result = S_ISDIR(st.st_mode); + } + + if(!result){ + dir->size = old_size; + } + } + } + } + return(result); } internal Sys_File_Can_Be_Made(system_file_can_be_made){ - // TODO(allen): Implement - - printf("File can be made: %s\n", filename); - AllowLocal(filename); - return(0); + return access(filename, W_OK) == 0; } internal @@ -1064,19 +1190,49 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc, printf("GL_VERSION: %s\n", Version); printf("GL_EXTENSIONS: %s\n", Extensions); - //TODO(inso): this should be optional + //TODO(inso): enable vsync if available. this should probably be optional if(strstr(glxExts, "GLX_EXT_swap_control ")){ - PFNGLXSWAPINTERVALEXTPROC glx_swap_interval = + PFNGLXSWAPINTERVALEXTPROC glx_swap_interval_ext = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT"); - if(glx_swap_interval){ - glx_swap_interval(XDisplay, XWindow, 1); + if(glx_swap_interval_ext){ + glx_swap_interval_ext(XDisplay, XWindow, 1); unsigned int swap_val = 0; glXQueryDrawable(XDisplay, XWindow, GLX_SWAP_INTERVAL_EXT, &swap_val); linuxvars.vsync = swap_val == 1; printf("VSync enabled? %d\n", linuxvars.vsync); } + } else if(strstr(glxExts, "GLX_MESA_swap_control ")){ + PFNGLXSWAPINTERVALMESAPROC glx_swap_interval_mesa = + (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalMESA"); + + PFNGLXGETSWAPINTERVALMESAPROC glx_get_swap_interval_mesa = + (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB((const GLubyte*)"glXGetSwapIntervalMESA"); + + if(glx_swap_interval_mesa){ + glx_swap_interval_mesa(1); + if(glx_get_swap_interval_mesa){ + linuxvars.vsync = glx_get_swap_interval_mesa(); + printf("VSync enabled? %d (MESA)\n", linuxvars.vsync); + } else { + // NOTE(inso): assume it worked? + linuxvars.vsync = 1; + puts("VSync enabled? possibly (MESA)"); + } + } + } else if(strstr(glxExts, "GLX_SGI_swap_control ")){ + PFNGLXSWAPINTERVALSGIPROC glx_swap_interval_sgi = + (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalSGI"); + + if(glx_swap_interval_sgi){ + glx_swap_interval_sgi(1); + //NOTE(inso): The SGI one doesn't seem to have a way to confirm we got it... + linuxvars.vsync = 1; + puts("VSync enabled? hopefully (SGI)"); + } + } else { + puts("VSync enabled? nope, no suitable extension"); } #if FRED_INTERNAL diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 326189c3..3cd928c6 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -495,6 +495,17 @@ DIRECTORY_CD_SIG(system_directory_cd){ return(result); } +Sys_File_Paths_Equal_Sig(system_file_paths_equal){ + b32 result = 0; + + // TODO(someone who knows windows): implement me + + AllowLocal(path_a); + AllowLocal(path_b); + + return result; +} + internal Sys_Post_Clipboard_Sig(system_post_clipboard){ if (OpenClipboard(win32vars.window_handle)){