From 2f1486c9dd98420e1e80fc4798807ea44e73927a Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Mon, 22 Feb 2016 22:14:23 -0500 Subject: [PATCH] about to patch linux clipboard --- ..._file_list-a-bit-add-clipboard-paste.patch | 600 ++++++++++++++++++ ...02-22-patch-02-get-file-list-working.patch | 102 +++ 4coder_custom.cpp | 3 + 4coder_string.h | 18 +- 4ed.cpp | 26 +- 4ed.h | 16 +- 4ed_file.cpp | 8 +- 4ed_file_view.cpp | 4 + 4ed_gui.cpp | 114 +++- 4ed_linux_keyboard.cpp | 72 ++- 4ed_mem.cpp | 3 +- 4ed_rendering.h | 410 ++++++------ 4ed_system.h | 3 + linux_4ed.cpp | 267 +++++++- vc120.pdb | Bin 102400 -> 102400 bytes win32_4ed.cpp | 2 + 16 files changed, 1356 insertions(+), 292 deletions(-) create mode 100644 0001-fix-set_file_list-a-bit-add-clipboard-paste.patch create mode 100644 2016-02-22-patch-02-get-file-list-working.patch diff --git a/0001-fix-set_file_list-a-bit-add-clipboard-paste.patch b/0001-fix-set_file_list-a-bit-add-clipboard-paste.patch new file mode 100644 index 00000000..338cc514 --- /dev/null +++ b/0001-fix-set_file_list-a-bit-add-clipboard-paste.patch @@ -0,0 +1,600 @@ +From 6d24dc4f80df0816a2c34b2a56026cb10ea1fd79 Mon Sep 17 00:00:00 2001 +From: insofaras +Date: Mon, 22 Feb 2016 21:22:52 +0000 +Subject: [PATCH] fix set_file_list a bit + add clipboard paste + +--- + code/linux_4ed.cpp | 493 +++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 310 insertions(+), 183 deletions(-) + +diff --git a/code/linux_4ed.cpp b/code/linux_4ed.cpp +index cea1099..af37526 100644 +--- a/code/linux_4ed.cpp ++++ b/code/linux_4ed.cpp +@@ -72,7 +72,11 @@ struct Linux_Vars{ + Mouse_State mouse_data; + + String clipboard_contents; +- ++ String clipboard_outgoing; ++ ++ Atom atom_CLIPBOARD; ++ Atom atom_UTF8_STRING; ++ + void *app_code; + void *custom; + +@@ -89,6 +93,8 @@ struct Linux_Vars{ + Font_Load_System fnt; + }; + ++#define LINUX_MAX_PASTE_CHARS 0x10000L ++ + globalvar Linux_Vars linuxvars; + globalvar Application_Memory memory_vars; + globalvar Exchange exchange_vars; +@@ -180,6 +186,21 @@ Sys_Free_Memory_Sig(system_free_memory){ + LinuxFreeMemory(block); + } + ++internal void ++LinuxStringDup(String* str, void* data, size_t size){ ++ if(str->memory_size < size){ ++ if(str->str){ ++ LinuxFreeMemory(str->str); ++ } ++ str->memory_size = size; ++ str->str = (char*)LinuxGetMemory(size); ++ //TODO(inso): handle alloc failure case ++ } ++ ++ str->size = size; ++ memcpy(str->str, data, size); ++} ++ + #if (defined(_BSD_SOURCE) || defined(_SVID_SOURCE)) + #define TimeBySt + #endif +@@ -231,9 +252,11 @@ Sys_Set_File_List_Sig(system_set_file_list){ + i32 count, file_count, size, required_size; + + terminate_with_null(&directory); ++ + d = opendir(directory.str); + if (d){ + count = 0; ++ file_count = 0; + for (entry = readdir(d); + entry != 0; + entry = readdir(d)){ +@@ -242,7 +265,6 @@ Sys_Set_File_List_Sig(system_set_file_list){ + for (size = 0; fname[size]; ++size); + count += size + 1; + } +- closedir(d); + + required_size = count + file_count * sizeof(File_Info); + if (file_list->block_size < required_size){ +@@ -253,33 +275,41 @@ Sys_Set_File_List_Sig(system_set_file_list){ + file_list->infos = (File_Info*)file_list->block; + cursor = (char*)(file_list->infos + file_count); + +- d = opendir(directory.str); +- if (d){ +- info_ptr = file_list->infos; +- for (entry = readdir(d); +- entry != 0; +- entry = readdir(d), ++info_ptr){ +- fname = entry->d_name; +- cursor_start = cursor; +- for (; *fname; ) *cursor++ = *fname++; ++ rewinddir(d); ++ info_ptr = file_list->infos; ++ for (entry = readdir(d); ++ entry != 0; ++ entry = readdir(d), ++info_ptr){ ++ fname = entry->d_name; ++ cursor_start = cursor; ++ for (; *fname; ) *cursor++ = *fname++; + +- // TODO(allen): detect file/folder status +- // (also make sure this even GETS folders!!!) +- info_ptr->folder = 0; +- info_ptr->filename.str = cursor_start; +- info_ptr->filename.size = (i32)(cursor - cursor_start); +- *cursor++ = 0; +- info_ptr->filename.memory_size = info_ptr->filename.size + 1; ++#ifdef _DIRENT_HAVE_D_TYPE ++ if(entry->d_type != DT_UNKNOWN){ ++ info_ptr->folder = entry->d_type == DT_DIR; ++ } else ++#endif ++ { ++ struct stat st; ++ if(lstat(entry->d_name, &st) != -1){ ++ info_ptr->folder = S_ISDIR(st.st_mode); ++ } else { ++ info_ptr->folder = 0; ++ } + } ++ ++ info_ptr->filename.str = cursor_start; ++ info_ptr->filename.size = (i32)(cursor - cursor_start); ++ *cursor++ = 0; ++ info_ptr->filename.memory_size = info_ptr->filename.size + 1; + } + closedir(d); + } +- closedir(d); + } + + Sys_Post_Clipboard_Sig(system_post_clipboard){ +- // TODO(allen): Implement +- AllowLocal(str); ++ LinuxStringDup(&linuxvars.clipboard_outgoing, str.str, str.size); ++ XSetSelectionOwner(linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, linuxvars.XWindow, CurrentTime); + } + + Sys_CLI_Call_Sig(system_cli_call){ +@@ -573,6 +603,8 @@ LinuxLoadSystemCode(){ + linuxvars.system->internal_sentinel = internal_sentinel; + linuxvars.system->internal_get_thread_states = internal_get_thread_states; + linuxvars.system->internal_debug_message = internal_debug_message; ++ ++ linuxvars.system->slash = '/'; + } + + internal void +@@ -591,7 +623,7 @@ LinuxRedrawTarget(){ + system_acquire_lock(RENDER_LOCK); + launch_rendering(&linuxvars.target); + system_release_lock(RENDER_LOCK); +- glFlush(); ++// glFlush(); + glXSwapBuffers(linuxvars.XDisplay, linuxvars.XWindow); + } + +@@ -1258,70 +1290,76 @@ main(int argc, char **argv) + } + } + ++ if (!window_setup_success){ ++ fprintf(stderr, "Error creating window."); ++ exit(1); ++ } ++ + XSetICFocus(linuxvars.input_context); +- +- if (window_setup_success){ +- linuxvars.app.init(linuxvars.system, &linuxvars.target, +- &memory_vars, &exchange_vars, &linuxvars.key_codes, +- linuxvars.clipboard_contents, current_directory, +- linuxvars.custom_api); + +- LinuxResizeTarget(WinWidth, WinHeight); ++ linuxvars.atom_CLIPBOARD = XInternAtom(linuxvars.XDisplay, "CLIPBOARD", False); ++ linuxvars.atom_UTF8_STRING = XInternAtom(linuxvars.XDisplay, "UTF8_STRING", False); + +- Atom WM_DELETE_WINDOW = XInternAtom(linuxvars.XDisplay, "WM_DELETE_WINDOW", False); +- if(WM_DELETE_WINDOW != None){ +- XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, &WM_DELETE_WINDOW, 1); +- } ++ Atom WM_DELETE_WINDOW = XInternAtom(linuxvars.XDisplay, "WM_DELETE_WINDOW", False); ++ if(WM_DELETE_WINDOW != None){ ++ XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, &WM_DELETE_WINDOW, 1); ++ } + +- b32 keep_running = 1; ++ linuxvars.app.init(linuxvars.system, &linuxvars.target, ++ &memory_vars, &exchange_vars, &linuxvars.key_codes, ++ linuxvars.clipboard_contents, current_directory, ++ linuxvars.custom_api); + +- while(keep_running) ++ LinuxResizeTarget(WinWidth, WinHeight); ++ b32 keep_running = 1; ++ ++ while(keep_running) ++ { ++ XEvent PrevEvent = {}; ++ ++ while(XPending(linuxvars.XDisplay)) + { +- XEvent PrevEvent = {}; +- +- while(XPending(linuxvars.XDisplay)) +- { +- XEvent Event; +- XNextEvent(linuxvars.XDisplay, &Event); +- +- if (XFilterEvent(&Event, None) == True){ +- continue; +- } +- +- switch (Event.type){ +- case KeyPress: { +- b32 is_hold = +- PrevEvent.type == KeyRelease && +- PrevEvent.xkey.time == Event.xkey.time && +- PrevEvent.xkey.keycode == Event.xkey.keycode; +- +- b8 mods[CONTROL_KEY_COUNT] = {}; +- if(Event.xkey.state & ShiftMask) mods[CONTROL_KEY_SHIFT] = 1; +- if(Event.xkey.state & ControlMask) mods[CONTROL_KEY_CONTROL] = 1; +- if(Event.xkey.state & LockMask) mods[CONTROL_KEY_CAPS] = 1; +- if(Event.xkey.state & Mod1Mask) mods[CONTROL_KEY_ALT] = 1; +- // NOTE(inso): mod5 == AltGr +- // if(Event.xkey.state & Mod5Mask) mods[CONTROL_KEY_ALT] = 1; +- +- KeySym keysym = NoSymbol; +- char buff[32], no_caps_buff[32]; +- +- // NOTE(inso): Turn ControlMask off like the win32 code does. +- if(mods[CONTROL_KEY_CONTROL] && !mods[CONTROL_KEY_ALT]){ +- Event.xkey.state &= ~(ControlMask); +- } +- +- // TODO(inso): Use one of the Xutf8LookupString funcs to allow for non-ascii chars +- XLookupString(&Event.xkey, buff, sizeof(buff), &keysym, NULL); +- +- Event.xkey.state &= ~LockMask; +- XLookupString(&Event.xkey, no_caps_buff, sizeof(no_caps_buff), NULL, NULL); +- +- u8 key = keycode_lookup(Event.xkey.keycode); +- +- if(key){ +- push_key(key, 0, 0, &mods, is_hold); +- } else { ++ XEvent Event; ++ XNextEvent(linuxvars.XDisplay, &Event); ++ ++ if (XFilterEvent(&Event, None) == True){ ++ continue; ++ } ++ ++ switch (Event.type){ ++ case KeyPress: { ++ b32 is_hold = ++ PrevEvent.type == KeyRelease && ++ PrevEvent.xkey.time == Event.xkey.time && ++ PrevEvent.xkey.keycode == Event.xkey.keycode; ++ ++ b8 mods[CONTROL_KEY_COUNT] = {}; ++ if(Event.xkey.state & ShiftMask) mods[CONTROL_KEY_SHIFT] = 1; ++ if(Event.xkey.state & ControlMask) mods[CONTROL_KEY_CONTROL] = 1; ++ if(Event.xkey.state & LockMask) mods[CONTROL_KEY_CAPS] = 1; ++ if(Event.xkey.state & Mod1Mask) mods[CONTROL_KEY_ALT] = 1; ++ // NOTE(inso): mod5 == AltGr ++ // if(Event.xkey.state & Mod5Mask) mods[CONTROL_KEY_ALT] = 1; ++ ++ KeySym keysym = NoSymbol; ++ char buff[32], no_caps_buff[32]; ++ ++ // NOTE(inso): Turn ControlMask off like the win32 code does. ++ if(mods[CONTROL_KEY_CONTROL] && !mods[CONTROL_KEY_ALT]){ ++ Event.xkey.state &= ~(ControlMask); ++ } ++ ++ // TODO(inso): Use one of the Xutf8LookupString funcs to allow for non-ascii chars ++ XLookupString(&Event.xkey, buff, sizeof(buff), &keysym, NULL); ++ ++ Event.xkey.state &= ~LockMask; ++ XLookupString(&Event.xkey, no_caps_buff, sizeof(no_caps_buff), NULL, NULL); ++ ++ u8 key = keycode_lookup(Event.xkey.keycode); ++ ++ if(key){ ++ push_key(key, 0, 0, &mods, is_hold); ++ } else { + key = buff[0] & 0xFF; + if(key < 128){ + u8 no_caps_key = no_caps_buff[0] & 0xFF; +@@ -1331,113 +1369,202 @@ main(int argc, char **argv) + } else { + push_key(0, 0, 0, &mods, is_hold); + } +- } +- }break; +- +- case MotionNotify: { +- linuxvars.mouse_data.x = Event.xmotion.x; +- linuxvars.mouse_data.y = Event.xmotion.y; +- }break; +- +- case ButtonPress: { +- switch(Event.xbutton.button){ +- case Button1: { +- linuxvars.mouse_data.left_button_pressed = 1; +- linuxvars.mouse_data.left_button = 1; +- } break; +- case Button3: { +- linuxvars.mouse_data.right_button_pressed = 1; +- linuxvars.mouse_data.right_button = 1; +- } break; +- } +- }break; +- +- case ButtonRelease: { +- switch(Event.xbutton.button){ +- case Button1: { +- linuxvars.mouse_data.left_button_released = 1; +- linuxvars.mouse_data.left_button = 0; +- } break; +- case Button3: { +- linuxvars.mouse_data.right_button_released = 1; +- linuxvars.mouse_data.right_button = 0; +- } break; +- } +- }break; +- +- case EnterNotify: { +- linuxvars.mouse_data.out_of_window = 0; +- }break; +- +- case LeaveNotify: { +- linuxvars.mouse_data.out_of_window = 1; +- }break; +- +- case FocusIn: +- case FocusOut: { +- linuxvars.mouse_data.left_button = 0; +- linuxvars.mouse_data.right_button = 0; +- }break; +- +- case ConfigureNotify: { +- i32 w = Event.xconfigure.width, h = Event.xconfigure.height; +- +- if(w != linuxvars.target.width || h != linuxvars.target.height){ +- LinuxResizeTarget(Event.xconfigure.width, Event.xconfigure.height); +- } +- }break; +- +- case MappingNotify: { +- if(Event.xmapping.request == MappingModifier || Event.xmapping.request == MappingKeyboard){ +- XRefreshKeyboardMapping(&Event.xmapping); +- keycode_init(linuxvars.XDisplay, &linuxvars.key_codes); +- } +- }break; +- +- case ClientMessage: { +- if ((Atom)Event.xclient.data.l[0] == WM_DELETE_WINDOW) { +- keep_running = false; +- } +- }break; +- } +- +- PrevEvent = Event; ++ } ++ }break; ++ ++ case MotionNotify: { ++ linuxvars.mouse_data.x = Event.xmotion.x; ++ linuxvars.mouse_data.y = Event.xmotion.y; ++ }break; ++ ++ case ButtonPress: { ++ switch(Event.xbutton.button){ ++ case Button1: { ++ linuxvars.mouse_data.left_button_pressed = 1; ++ linuxvars.mouse_data.left_button = 1; ++ } break; ++ case Button3: { ++ linuxvars.mouse_data.right_button_pressed = 1; ++ linuxvars.mouse_data.right_button = 1; ++ } break; ++ } ++ }break; ++ ++ case ButtonRelease: { ++ switch(Event.xbutton.button){ ++ case Button1: { ++ linuxvars.mouse_data.left_button_released = 1; ++ linuxvars.mouse_data.left_button = 0; ++ } break; ++ case Button3: { ++ linuxvars.mouse_data.right_button_released = 1; ++ linuxvars.mouse_data.right_button = 0; ++ } break; ++ } ++ }break; ++ ++ case EnterNotify: { ++ linuxvars.mouse_data.out_of_window = 0; ++ }break; ++ ++ case LeaveNotify: { ++ linuxvars.mouse_data.out_of_window = 1; ++ }break; ++ ++ case FocusIn: ++ case FocusOut: { ++ linuxvars.mouse_data.left_button = 0; ++ linuxvars.mouse_data.right_button = 0; ++ }break; ++ ++ case ConfigureNotify: { ++ i32 w = Event.xconfigure.width, h = Event.xconfigure.height; ++ ++ if(w != linuxvars.target.width || h != linuxvars.target.height){ ++ LinuxResizeTarget(Event.xconfigure.width, Event.xconfigure.height); ++ } ++ }break; ++ ++ case MappingNotify: { ++ if(Event.xmapping.request == MappingModifier || Event.xmapping.request == MappingKeyboard){ ++ XRefreshKeyboardMapping(&Event.xmapping); ++ keycode_init(linuxvars.XDisplay, &linuxvars.key_codes); ++ } ++ }break; ++ ++ case ClientMessage: { ++ if ((Atom)Event.xclient.data.l[0] == WM_DELETE_WINDOW) { ++ keep_running = false; ++ } ++ }break; ++ ++ // NOTE(inso): Someone wants us to give them the clipboard data. ++ case SelectionRequest: { ++ XSelectionRequestEvent request = Event.xselectionrequest; ++ ++ XSelectionEvent response = {}; ++ response.type = SelectionNotify; ++ response.requestor = request.requestor; ++ response.selection = request.selection; ++ response.target = request.target; ++ response.time = request.time; ++ response.property = None; ++ ++ //TODO(inso): handle TARGETS negotiation instead of requiring UTF8_STRING ++ if ( ++ linuxvars.clipboard_outgoing.size && ++ request.target == linuxvars.atom_UTF8_STRING && ++ request.selection == linuxvars.atom_CLIPBOARD && ++ request.property != None && ++ request.display && ++ request.requestor ++ ){ ++ XChangeProperty( ++ request.display, ++ request.requestor, ++ request.property, ++ request.target, ++ 8, ++ PropModeReplace, ++ (unsigned char*)linuxvars.clipboard_outgoing.str, ++ linuxvars.clipboard_outgoing.size ++ ); ++ ++ response.property = request.property; ++ } ++ ++ XSendEvent(request.display, request.requestor, True, 0, (XEvent*)&response); ++ ++ }break; ++ ++ // NOTE(inso): Another program is now the clipboard owner. ++ case SelectionClear: { ++ if(Event.xselectionclear.selection == linuxvars.atom_CLIPBOARD){ ++ linuxvars.clipboard_outgoing.size = 0; ++ } ++ }break; ++ ++ // NOTE(inso): A program is giving us the clipboard data we asked for. ++ case SelectionNotify: { ++ XSelectionEvent* e = (XSelectionEvent*)&Event; ++ if( ++ e->selection == linuxvars.atom_CLIPBOARD && ++ e->target == linuxvars.atom_UTF8_STRING && ++ e->property != None ++ ){ ++ Atom type; ++ int fmt; ++ unsigned long nitems, bytes_left; ++ u8 *data; ++ ++ XGetWindowProperty( ++ linuxvars.XDisplay, ++ linuxvars.XWindow, ++ linuxvars.atom_CLIPBOARD, ++ 0L, ++ LINUX_MAX_PASTE_CHARS/4L, ++ False, ++ linuxvars.atom_UTF8_STRING, ++ &type, ++ &fmt, ++ &nitems, ++ &bytes_left, ++ &data ++ ); ++ ++ LinuxStringDup(&linuxvars.clipboard_contents, data, nitems); ++ ++ XFree(data); ++ } ++ }break; + } + +- b32 redraw = 1; +- +- Key_Input_Data input_data; +- Mouse_State mouse; +- Application_Step_Result result; +- +- input_data = linuxvars.key_data; +- mouse = linuxvars.mouse_data; +- +- result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; +- result.redraw = redraw; +- result.lctrl_lalt_is_altgr = 0; +- +- linuxvars.app.step(linuxvars.system, +- &linuxvars.key_codes, +- &input_data, +- &mouse, +- &linuxvars.target, +- &memory_vars, +- &exchange_vars, +- linuxvars.clipboard_contents, +- 1, linuxvars.first, redraw, +- &result); +- +- if (result.redraw){ +- LinuxRedrawTarget(); +- } ++ PrevEvent = Event; ++ } + +- linuxvars.key_data = {}; +- linuxvars.mouse_data.left_button_pressed = 0; +- linuxvars.mouse_data.left_button_released = 0; +- linuxvars.mouse_data.right_button_pressed = 0; +- linuxvars.mouse_data.right_button_released = 0; ++ // FIXME(inso): is getting the clipboard every frame a bad idea? ++ XConvertSelection( ++ linuxvars.XDisplay, ++ linuxvars.atom_CLIPBOARD, ++ linuxvars.atom_UTF8_STRING, ++ linuxvars.atom_CLIPBOARD, ++ linuxvars.XWindow, ++ CurrentTime ++ ); ++ ++ b32 redraw = 1; ++ ++ Key_Input_Data input_data; ++ Mouse_State mouse; ++ Application_Step_Result result; ++ ++ input_data = linuxvars.key_data; ++ mouse = linuxvars.mouse_data; ++ ++ result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; ++ result.redraw = redraw; ++ result.lctrl_lalt_is_altgr = 0; ++ ++ linuxvars.app.step(linuxvars.system, ++ &linuxvars.key_codes, ++ &input_data, ++ &mouse, ++ &linuxvars.target, ++ &memory_vars, ++ &exchange_vars, ++ linuxvars.clipboard_contents, ++ 1, linuxvars.first, redraw, ++ &result); ++ ++ if (result.redraw){ ++ LinuxRedrawTarget(); + } ++ ++ linuxvars.key_data = {}; ++ linuxvars.mouse_data.left_button_pressed = 0; ++ linuxvars.mouse_data.left_button_released = 0; ++ linuxvars.mouse_data.right_button_pressed = 0; ++ linuxvars.mouse_data.right_button_released = 0; + } + } + +-- +1.9.1 + diff --git a/2016-02-22-patch-02-get-file-list-working.patch b/2016-02-22-patch-02-get-file-list-working.patch new file mode 100644 index 00000000..e916d317 --- /dev/null +++ b/2016-02-22-patch-02-get-file-list-working.patch @@ -0,0 +1,102 @@ +From 2e9c55181ecb0a0f94c7f1b389f19fd76e856d55 Mon Sep 17 00:00:00 2001 +From: insofaras +Date: Tue, 23 Feb 2016 02:01:26 +0000 +Subject: [PATCH] get file list working + +--- + code/4ed_color_view.cpp | 11 ++++++----- + code/linux_4ed.cpp | 12 ++++++++---- + 2 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/code/4ed_color_view.cpp b/code/4ed_color_view.cpp +index 391d891..2b170a6 100644 +--- a/code/4ed_color_view.cpp ++++ b/code/4ed_color_view.cpp +@@ -1429,11 +1429,12 @@ do_checkbox_list_option(i32 id, UI_State *state, UI_Layout *layout, String text, + + + internal b32 +-do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 is_folder, String extra){ ++do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 is_folder, String extra, char slash){ + b32 result = 0; + Style *style = state->style; + i16 font_id = style->font_id; + i32 character_h = get_font_info(state->font_set, font_id)->height; ++ char slash_buf[2] = { slash, 0 }; + + i32_Rect box = layout_rect(layout, character_h*2); + Widget_ID wid = make_id(state, id); +@@ -1456,7 +1457,7 @@ do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 + draw_rectangle(target, inner, back); + i32 x = inner.x0, y = box.y0 + character_h/2; + x = draw_string(target, font_id, filename, x, y, fore); +- if (is_folder) x = draw_string(target, font_id, "\\", x, y, fore); ++ if (is_folder) x = draw_string(target, font_id, slash_buf, x, y, fore); + draw_string(target, font_id, extra, x, y, pop); + draw_margin(target, box, inner, outline); + } +@@ -1522,13 +1523,13 @@ do_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, + } + + if ((is_folder || !has_filter || ext_match) && name_match){ +- if (do_file_option(100+i, state, layout, filename, is_folder, message)){ ++ if (do_file_option(100+i, state, layout, filename, is_folder, message, system->slash)){ + result = 1; + hot_directory_clean_end(hot_dir); + append(&hot_dir->string, filename); + if (is_folder){ + *new_dir = 1; +- append(&hot_dir->string, "\\"); ++ append(&hot_dir->string, system->slash); + } + else{ + *selected = 1; +@@ -1572,7 +1573,7 @@ do_live_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layo + } + + if (filename_match(*string, &absolutes, file->name.live_name, 1)){ +- if (do_file_option(100+i, state, layout, file->name.live_name, 0, message)){ ++ if (do_file_option(100+i, state, layout, file->name.live_name, 0, message, system->slash)){ + result = 1; + *selected = 1; + copy(string, file->name.source_path); +diff --git a/code/linux_4ed.cpp b/code/linux_4ed.cpp +index af37526..1fa7a54 100644 +--- a/code/linux_4ed.cpp ++++ b/code/linux_4ed.cpp +@@ -303,6 +303,9 @@ Sys_Set_File_List_Sig(system_set_file_list){ + *cursor++ = 0; + info_ptr->filename.memory_size = info_ptr->filename.size + 1; + } ++ ++ file_list->count = file_count; ++ + closedir(d); + } + } +@@ -1497,7 +1500,7 @@ main(int argc, char **argv) + unsigned long nitems, bytes_left; + u8 *data; + +- XGetWindowProperty( ++ int result = XGetWindowProperty( + linuxvars.XDisplay, + linuxvars.XWindow, + linuxvars.atom_CLIPBOARD, +@@ -1512,9 +1515,10 @@ main(int argc, char **argv) + &data + ); + +- LinuxStringDup(&linuxvars.clipboard_contents, data, nitems); +- +- XFree(data); ++ if(result == Success && fmt == 8){ ++ LinuxStringDup(&linuxvars.clipboard_contents, data, nitems); ++ XFree(data); ++ } + } + }break; + } +-- +1.9.1 + diff --git a/4coder_custom.cpp b/4coder_custom.cpp index bef35e1c..a5f04c0c 100644 --- a/4coder_custom.cpp +++ b/4coder_custom.cpp @@ -247,6 +247,9 @@ extern "C" GET_BINDING_DATA(get_bindings){ bind(context, '\t', MDFR_CTRL, cmdid_auto_tab_range); bind(context, '\t', MDFR_SHIFT, cmdid_auto_tab_line_at_cursor); + bind_me(context, '\n', MDFR_SHIFT, write_and_auto_tab); + bind_me(context, ' ', MDFR_SHIFT, cmdid_write_character); + end_map(context); diff --git a/4coder_string.h b/4coder_string.h index 98dc3d39..eac3de03 100644 --- a/4coder_string.h +++ b/4coder_string.h @@ -174,8 +174,8 @@ FCPP_LINK int reverse_seek_slash(String str, int start_pos); inline bool get_front_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, reverse_seek_slash(dir) + 1)); } inline bool get_path_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, 0, reverse_seek_slash(dir) + 1)); } inline void truncate_to_path_of_directory(String *dir) { dir->size = reverse_seek_slash(*dir) + 1; } -FCPP_LINK bool set_last_folder(String *dir, char *folder_name); -FCPP_LINK bool set_last_folder(String *dir, String folder_name); +FCPP_LINK bool set_last_folder(String *dir, char *folder_name, char slash); +FCPP_LINK bool set_last_folder(String *dir, String folder_name, char slash); FCPP_LINK String file_extension(String str); FCPP_LINK String file_extension_slowly(char *str); FCPP_LINK bool remove_last_folder(String *str); @@ -980,12 +980,15 @@ reverse_seek_slash(String str){ } FCPP_LINK bool -set_last_folder(String *dir, char *folder_name){ +set_last_folder(String *dir, char *folder_name, char slash){ + char str[2]; bool result = 0; int size = reverse_seek_slash(*dir) + 1; dir->size = size; + str[0] = slash; + str[1] = 0; if (append(dir, folder_name)){ - if (append(dir, (char*)"\\")){ + if (append(dir, str)){ result = 1; } } @@ -996,12 +999,15 @@ set_last_folder(String *dir, char *folder_name){ } FCPP_LINK bool -set_last_folder(String *dir, String folder_name){ +set_last_folder(String *dir, String folder_name, char slash){ + char str[2]; bool result = 0; int size = reverse_seek_slash(*dir) + 1; dir->size = size; + str[0] = slash; + str[1] = 0; if (append(dir, folder_name)){ - if (append(dir, (char*)"\\")){ + if (append(dir, str)){ result = 1; } } diff --git a/4ed.cpp b/4ed.cpp index f22d66b1..210c2dc3 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1496,7 +1496,7 @@ COMMAND_DECL(move_up){ REQ_FILE_VIEW(view); REQ_FILE(file, view); USE_FONT_SET(font_set); - + f32 font_height = (f32)get_font_info(font_set, view->style->font_id)->height; f32 cy = view_get_cursor_y(view)-font_height; f32 px = view->preferred_x; @@ -1541,33 +1541,27 @@ COMMAND_DECL(page_down){ ProfileMomentFunction(); REQ_FILE_VIEW(view); - real32 height = view_compute_height(view); - real32 max_target_y = view_compute_max_target_y(view); - real32 cursor_y = view_get_cursor_y(view); + f32 height = view_compute_height(view); + f32 max_target_y = view_compute_max_target_y(view); view->target_y += height; if (view->target_y > max_target_y) view->target_y = max_target_y; - - if (view->target_y >= cursor_y){ - view->cursor = - view_compute_cursor_from_xy(view, 0, view->target_y); - } + + view->cursor = view_compute_cursor_from_xy( + view, 0, view->target_y + (height - view->font_height)*.5f); } COMMAND_DECL(page_up){ ProfileMomentFunction(); REQ_FILE_VIEW(view); - real32 height = view_compute_height(view); - real32 cursor_y = view_get_cursor_y(view); + f32 height = view_compute_height(view); view->target_y -= height; if (view->target_y < 0) view->target_y = 0; - if (view->target_y + height <= cursor_y){ - view->cursor = - view_compute_cursor_from_xy(view, 0, view->target_y + height - view->font_height); - } + view->cursor = view_compute_cursor_from_xy( + view, 0, view->target_y + (height - view->font_height)*.5f); } inline void @@ -3004,7 +2998,7 @@ App_Init_Sig(app_init){ panel_init(&panels[0]); String hdbase = make_fixed_width_string(vars->hot_dir_base_); - hot_directory_init(&vars->hot_directory, hdbase, current_directory); + hot_directory_init(&vars->hot_directory, hdbase, current_directory, system->slash); vars->mini_str = make_string((char*)vars->mini_buffer, 0, 512); diff --git a/4ed.h b/4ed.h index 8590881c..ce063968 100644 --- a/4ed.h +++ b/4ed.h @@ -111,14 +111,14 @@ struct Plat_Settings{ typedef App_Read_Command_Line_Sig(App_Read_Command_Line); #define App_Init_Sig(name) void \ - name(System_Functions *system, \ - Render_Target *target, \ - Application_Memory *memory, \ - Exchange *exchange, \ - Key_Codes *codes, \ - String clipboard, \ - String current_directory, \ - Custom_API api) +name(System_Functions *system, \ + Render_Target *target, \ + Application_Memory *memory, \ + Exchange *exchange, \ + Key_Codes *codes, \ + String clipboard, \ + String current_directory, \ + Custom_API api) typedef App_Init_Sig(App_Init); diff --git a/4ed_file.cpp b/4ed_file.cpp index d4efe7fc..ea0c7014 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -251,21 +251,23 @@ struct Working_Set{ struct Hot_Directory{ String string; File_List file_list; + char slash; }; internal void -hot_directory_init(Hot_Directory *hot_directory, String base, String dir){ +hot_directory_init(Hot_Directory *hot_directory, String base, String dir, char slash){ hot_directory->string = base; hot_directory->string.str[255] = 0; hot_directory->string.size = 0; copy(&hot_directory->string, dir); - append(&hot_directory->string, "\\"); + append(&hot_directory->string, slash); + hot_directory->slash = slash; } internal void hot_directory_clean_end(Hot_Directory *hot_directory){ String *str = &hot_directory->string; - if (str->size != 0 && str->str[str->size-1] != '\\'){ + if (str->size != 0 && str->str[str->size-1] != hot_directory->slash){ str->size = reverse_seek_slash(*str) + 1; str->str[str->size] = 0; } diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 53eb2077..aeb9e232 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -3239,6 +3239,9 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t #endif if (view->widget.type != FWIDG_NONE){ +#if 1 + ui_render(target, view->gui_target); +#else UI_Style ui_style = get_ui_style_upper(style); i32_Rect widg_rect = view_widget_rect(view, view->font_height); @@ -3307,6 +3310,7 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t } ui_finish_frame(&view->widget.state, &state, &layout, widg_rect, 0, 0); +#endif } draw_file_bar(view, &bar, target); diff --git a/4ed_gui.cpp b/4ed_gui.cpp index 13bf6cf0..2af8d4a5 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -9,6 +9,118 @@ // TOP +enum GUI_Piece_Type{ + gui_type_text_input, + gui_type_number_input, + gui_type_label, + gui_type_slider +}; + +struct GUI_Piece_Header{ + i32 type; + i32 padding; +}; + +// TODO(allen): Inline string for prompt? +struct GUI_Piece_Text_Input{ + String *dest; + f32_Rect rect; + String prompt; +}; + +struct GUI_Piece_Number_Input{ + i32 *dest; + f32_Rect rect; + String prompt; +}; + +struct GUI_Piece_Label{ + f32_Rect rect; + String text; +}; + +struct GUI_Piece_Slider{ + i32 *dest; + f32_Rect rect; + i32 max; +}; + +struct GUI_Layout_Engine{ + i32_Rect region; + i32 x, y; +}; + +struct GUI_Target{ + Partition push_buffer; + GUI_Layout_Engine layout; +}; + +internal void +refresh_gui(GUI_Target *target, i32_Rect region){ + target->push_buffer.pos = 0; + target->layout.region = region; + target->layout.x = 0; + target->layout.y = 0; +} + +internal void +push_gui_item(GUI_Target *target, GUI_Piece_Header header, void *item, i32 size){ + GUI_Piece_Header *ptr; + i32 total_size; + + Assert(sizeof(header) == 8); + + total_size = sizeof(header) + size; + total_size = ((total_size + 7) & ~7); + + ptr = (GUI_Piece_Header*)push_block(&target->push_buffer, size); + if (ptr){ + *ptr = header; + memcpy(ptr + 1, item, size); + } + else{ + Assert(!"bad situation"); + } +} + +internal void +push_gui_text_in(GUI_Target *target, String prompt, String *dest){ + GUI_Piece_Header header = {}; + GUI_Piece_Text_Input item = {}; + + header.type = gui_type_text_input; + item.dest = dest; + item.rect = gui_layout(target); // ?? what do we need here? + item.prompt = prompt; + + push_gui_item(target, header, &item, sizeof(item)); +} + +internal void +push_gui_number_in(GUI_Target *target, String prompt, i32 *dest){ + GUI_Piece_Header header = {}; + GUI_Piece_Number_Input item = {}; + + header.type = gui_type_number_input; + item.dest = dest; + item.rect = gui_layout(target); // ?? what do we need here? + item.prompt = prompt; + + push_gui_item(target, header, &item, sizeof(item)); +} + +internal void +push_gui_label(GUI_Target *target, String text){ + GUI_Piece_Header header = {}; + GUI_Piece_Label item = {}; + + header.type = gui_type_label; + item.rect = gui_layout(target); // ?? what do we need here? + item.text = text; + + push_gui_item(target, header, &item, sizeof(item)); +} + struct Single_Line_Input_Step{ b8 hit_newline; b8 hit_ctrl_newline; @@ -87,7 +199,7 @@ app_single_line_input_core(System_Functions *system, } if (match.filename.str){ if (match.is_folder){ - set_last_folder(mode.string, match.filename); + set_last_folder(mode.string, match.filename, mode.hot_directory->slash); hot_directory_set(system, mode.hot_directory, *mode.string, working_set); result.hit_newline = 0; } diff --git a/4ed_linux_keyboard.cpp b/4ed_linux_keyboard.cpp index ba418ad4..e1e9b670 100644 --- a/4ed_linux_keyboard.cpp +++ b/4ed_linux_keyboard.cpp @@ -15,7 +15,8 @@ internal void keycode_init(Display* dpy, Key_Codes *codes){ set_dynamic_key_names(codes); - /* NOTE(inso): these are for XInput, currently not used. +#if 0 + // NOTE(inso): these are for XInput, currently not used. keycode_lookup_table[KEY_BACKSPACE] = codes->back; keycode_lookup_table[KEY_DELETE] = codes->del; @@ -29,26 +30,61 @@ keycode_init(Display* dpy, Key_Codes *codes){ keycode_lookup_table[KEY_PAGEUP] = codes->page_up; keycode_lookup_table[KEY_PAGEDOWN] = codes->page_down; keycode_lookup_table[KEY_ESC] = codes->esc; - */ +#endif -#define XK_(x) XK_##x -#define XKEY(x) keycode_lookup_table[XKeysymToKeycode(dpy, XK_(x))] + // NOTE(inso): This looks a bit dumb, but it's the best way I can think of to do it, since: + // KeySyms are the type representing "virtual" keys, like XK_BackSpace, but they are 32-bit ints. + // KeyCodes are guaranteed to fit in 1 byte (and therefore the keycode_lookup_table) but + // have dynamic numbers assigned by the XServer. + // There is XKeysymToKeycode, but it only returns 1 KeyCode for a KeySym. I have my capslock + // 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. - XKEY(BackSpace) = codes->back; - XKEY(Delete) = codes->del; - XKEY(Up) = codes->up; - XKEY(Down) = codes->down; - XKEY(Left) = codes->left; - XKEY(Right) = codes->right; - XKEY(Insert) = codes->insert; - XKEY(Home) = codes->home; - XKEY(End) = codes->end; - XKEY(Page_Up) = codes->page_up; - XKEY(Page_Down) = codes->page_down; - XKEY(Escape) = codes->esc; + struct SymMapping { + KeySym sym; + Code code; + } sym_table[] = { + { XK_BackSpace, codes->back }, + { XK_Delete, codes->del }, + { XK_Up, codes->up }, + { XK_Down, codes->down }, + { XK_Left, codes->left }, + { XK_Right, codes->right }, + { XK_Insert, codes->insert }, + { XK_Home, codes->home }, + { XK_End, codes->end }, + { XK_Page_Up, codes->page_up }, + { XK_Page_Down, codes->page_down }, + { XK_Escape, codes->esc } + }; -#undef XKEY -#undef XK_ + const int table_size = sizeof(sym_table) / sizeof(struct SymMapping); + + int key_min, key_max, syms_per_code; + XDisplayKeycodes(dpy, &key_min, &key_max); + + int key_count = (key_max - key_min) + 1; + + KeySym* syms = XGetKeyboardMapping( + dpy, + key_min, + key_count, + &syms_per_code + ); + + if(!syms) return; + + int key = key_min; + for(int i = 0; i < key_count * syms_per_code; ++i){ + for(int j = 0; j < table_size; ++j){ + if(sym_table[j].sym == syms[i]){ + keycode_lookup_table[key + (i/syms_per_code)] = sym_table[j].code; + break; + } + } + } + + XFree(syms); } diff --git a/4ed_mem.cpp b/4ed_mem.cpp index 64a4219e..84120e7d 100644 --- a/4ed_mem.cpp +++ b/4ed_mem.cpp @@ -65,7 +65,8 @@ partition_allocate(Partition *data, i32 size){ inline void partition_align(Partition *data, u32 boundary){ - data->pos = (data->pos + (boundary - 1)) & (~boundary); + --boundary; + data->pos = (data->pos + boundary) & (~boundary); } inline void* diff --git a/4ed_rendering.h b/4ed_rendering.h index fefc7488..f3e6f3e3 100644 --- a/4ed_rendering.h +++ b/4ed_rendering.h @@ -1,204 +1,206 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 17.12.2014 - * - * Rendering layer for project codename "4ed" - * - */ - -// TOP - -#ifndef FRED_RENDERING_H -#define FRED_RENDERING_H - -internal void* -part_alloc(int size, void *context){ - Partition *part = (Partition*)context; - void *result = push_block(part, size); - return(result); -} - -internal void -part_free(void *ptr, void *context){ -} - -#define STBTT_malloc part_alloc -#define STBTT_free part_free - -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" - -struct Glyph_Data{ - b32 exists; -}; - -struct Render_Font{ - char name_[24]; - String name; - b32 loaded; - - Glyph_Data glyphs[256]; - stbtt_packedchar chardata[256]; - float advance_data[256]; - i32 height, ascent, descent, line_skip; - i32 advance; - u32 tex; - i32 tex_width, tex_height; -}; - -struct Render_Target; - -#define Draw_Push_Clip_Sig(name) void name(Render_Target *target, i32_Rect clip_box) -typedef Draw_Push_Clip_Sig(Draw_Push_Clip); - -#define Draw_Pop_Clip_Sig(name) void name(Render_Target *target) -typedef Draw_Pop_Clip_Sig(Draw_Pop_Clip); - -enum Render_Piece_Type{ - piece_type_rectangle, - piece_type_outline, - piece_type_gradient, - piece_type_glyph, - piece_type_mono_glyph, - piece_type_mono_glyph_advance, - piece_type_change_clip -}; - -struct Render_Piece_Header{ - i32 type; -}; - -struct Render_Piece_Rectangle{ - f32_Rect rect; - u32 color; -}; - -struct Render_Piece_Gradient{ - f32_Rect rect; - u32 left_color, right_color; -}; - -struct Render_Piece_Glyph{ - Vec2 pos; - u32 color; - i16 font_id; - u8 character; -}; - -struct Render_Piece_Glyph_Advance{ - Vec2 pos; - u32 color; - f32 advance; - i16 font_id; - u8 character; -}; - -struct Render_Piece_Change_Clip{ - i32_Rect box; -}; - -struct Render_Piece_Combined{ - Render_Piece_Header header; - union{ - Render_Piece_Rectangle rectangle; - Render_Piece_Gradient gradient; - Render_Piece_Glyph glyph; - Render_Piece_Glyph_Advance glyph_advance; - }; -}; - -#define Draw_Push_Piece_Sig(name) void name(Render_Target *target, Render_Piece_Combined piece) -typedef Draw_Push_Piece_Sig(Draw_Push_Piece); - -#define Font_Load_Sig(name) i32 name( \ - Render_Font *font_out, \ - char *filename, \ - i32 pt_size, \ - i32 tab_width) -typedef Font_Load_Sig(Font_Load); - -#define Font_Info_Load_Sig(name) i32 name( \ - Partition *partition, \ - char *filename, \ - i32 pt_size, \ - i32 *height, \ - i32 *advance) -typedef Font_Info_Load_Sig(Font_Info_Load); - -#define Release_Font_Sig(name) void name(Render_Font *font) -typedef Release_Font_Sig(Release_Font); - -struct Font_Table_Entry{ - u32 hash; - String name; - i16 font_id; -}; - -struct Font_Info{ - Render_Font *font; - String filename; - String name; - i32 height, advance; - i32 pt_size; -}; - -struct Font_Slot{ - Font_Slot *next, *prev; - i16 font_id; - u8 padding[14]; -}; - -struct Font_Set{ - Font_Info *info; - Font_Table_Entry *entries; - u32 count, max; - - void *font_block; - Font_Slot free_slots; - Font_Slot used_slots; - - Font_Info_Load *font_info_load; - Font_Load *font_load; - Release_Font *release_font; - - b8 *font_used_flags; - i16 used_this_frame; - i16 live_max; -}; - -struct Render_Target{ - void *handle; - void *context; - i32_Rect clip_boxes[5]; - i32 clip_top; - i32 width, height; - i32 bound_texture; - u32 color; - - byte *push_buffer; - i32 size, max; - - Font_Set font_set; - Partition *partition; - - Draw_Push_Clip *push_clip; - Draw_Pop_Clip *pop_clip; - Draw_Push_Piece *push_piece; -}; - -inline i32_Rect -rect_from_target(Render_Target *target){ - return i32R(0, 0, target->width, target->height); -} - -inline Font_Info* -get_font_info(Font_Set *set, i16 font_id){ - Font_Info *result = set->info + font_id - 1; - return(result); -} - -#endif - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 17.12.2014 + * + * Rendering layer for project codename "4ed" + * + */ + +// TOP + +#ifndef FRED_RENDERING_H +#define FRED_RENDERING_H + +internal void* +part_alloc(int size, void *context){ + Partition *part = (Partition*)context; + void *result = push_block(part, size); + return(result); +} + +internal void +part_free(void *ptr, void *context){ +} + +#define STBTT_malloc part_alloc +#define STBTT_free part_free + +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" + +struct Glyph_Data{ + b32 exists; +}; + +struct Render_Font{ + char name_[24]; + String name; + b32 loaded; + + Glyph_Data glyphs[256]; + stbtt_packedchar chardata[256]; + float advance_data[256]; + i32 height, ascent, descent, line_skip; + i32 advance; + u32 tex; + i32 tex_width, tex_height; +}; + +struct Render_Target; + +#define Draw_Push_Clip_Sig(name) void name(Render_Target *target, i32_Rect clip_box) +typedef Draw_Push_Clip_Sig(Draw_Push_Clip); + +#define Draw_Pop_Clip_Sig(name) void name(Render_Target *target) +typedef Draw_Pop_Clip_Sig(Draw_Pop_Clip); + +enum Render_Piece_Type{ + piece_type_rectangle, + piece_type_outline, + piece_type_gradient, + piece_type_glyph, + piece_type_mono_glyph, + piece_type_mono_glyph_advance, + piece_type_change_clip +}; + +struct Render_Piece_Header{ + i32 type; +}; + +struct Render_Piece_Rectangle{ + f32_Rect rect; + u32 color; +}; + +struct Render_Piece_Gradient{ + f32_Rect rect; + u32 left_color, right_color; +}; + +struct Render_Piece_Glyph{ + Vec2 pos; + u32 color; + i16 font_id; + u8 character; +}; + +struct Render_Piece_Glyph_Advance{ + Vec2 pos; + u32 color; + f32 advance; + i16 font_id; + u8 character; +}; + +struct Render_Piece_Change_Clip{ + i32_Rect box; +}; + +struct Render_Piece_Combined{ + Render_Piece_Header header; + union{ + Render_Piece_Rectangle rectangle; + Render_Piece_Gradient gradient; + Render_Piece_Glyph glyph; + Render_Piece_Glyph_Advance glyph_advance; + }; +}; + +#define Draw_Push_Piece_Sig(name) void name(Render_Target *target, Render_Piece_Combined piece) +typedef Draw_Push_Piece_Sig(Draw_Push_Piece); + +#define Font_Load_Sig(name) i32 name( \ + Render_Font *font_out, \ + char *filename, \ + i32 pt_size, \ + i32 tab_width) +typedef Font_Load_Sig(Font_Load); + +#define Font_Info_Load_Sig(name) i32 name( \ + Partition *partition, \ + char *filename, \ + i32 pt_size, \ + i32 *height, \ + i32 *advance) +typedef Font_Info_Load_Sig(Font_Info_Load); + +#define Release_Font_Sig(name) void name(Render_Font *font) +typedef Release_Font_Sig(Release_Font); + +struct Font_Table_Entry{ + u32 hash; + String name; + i16 font_id; +}; + +struct Font_Info{ + Render_Font *font; + String filename; + String name; + i32 height, advance; + i32 pt_size; +}; + +struct Font_Slot{ + Font_Slot *next, *prev; + i16 font_id; + u8 padding[14]; +}; + +struct Font_Set{ + Font_Info *info; + Font_Table_Entry *entries; + u32 count, max; + + void *font_block; + Font_Slot free_slots; + Font_Slot used_slots; + + Font_Info_Load *font_info_load; + Font_Load *font_load; + Release_Font *release_font; + + b8 *font_used_flags; + i16 used_this_frame; + i16 live_max; +}; + +struct Render_Target{ + void *handle; + void *context; + i32_Rect clip_boxes[5]; + i32 clip_top; + i32 width, height; + i32 bound_texture; + u32 color; + + // TODO(allen): change this to a Partition + byte *push_buffer; + i32 size, max; + + // TODO(allen): rename this to font_partition + Font_Set font_set; + Partition *partition; + + Draw_Push_Clip *push_clip; + Draw_Pop_Clip *pop_clip; + Draw_Push_Piece *push_piece; +}; + +inline i32_Rect +rect_from_target(Render_Target *target){ + return i32R(0, 0, target->width, target->height); +} + +inline Font_Info* +get_font_info(Font_Set *set, i16 font_id){ + Font_Info *result = set->info + font_id - 1; + return(result); +} + +#endif + +// BOTTOM + diff --git a/4ed_system.h b/4ed_system.h index c5bb77e8..8f89545d 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -185,6 +185,9 @@ struct System_Functions{ INTERNAL_System_Sentinel *internal_sentinel; INTERNAL_System_Get_Thread_States *internal_get_thread_states; INTERNAL_System_Debug_Message *internal_debug_message; + + // non-function details + char slash; }; #define FileNameMax (1 << 9) diff --git a/linux_4ed.cpp b/linux_4ed.cpp index b3b174e5..cea1099a 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include //#include @@ -52,6 +54,9 @@ #include #include +#include +#include +#include struct Linux_Vars{ Display *XDisplay; @@ -88,8 +93,10 @@ globalvar Linux_Vars linuxvars; globalvar Application_Memory memory_vars; globalvar Exchange exchange_vars; -internal -Sys_Get_Memory_Sig(system_get_memory_){ +#define LinuxGetMemory(size) LinuxGetMemory_(size, __LINE__, __FILE__) + +internal void* +LinuxGetMemory_(i32 size, i32 line_number, char *file_name){ // TODO(allen): Implement without stdlib.h void *result = 0; @@ -116,8 +123,8 @@ Sys_Get_Memory_Sig(system_get_memory_){ return(result); } -internal -Sys_Free_Memory_Sig(system_free_memory){ +internal void +LinuxFreeMemory(void *block){ // TODO(allen): Implement without stdlib.h if (block){ @@ -138,6 +145,41 @@ Sys_Free_Memory_Sig(system_free_memory){ } } +internal Partition +LinuxScratchPartition(i32 size){ + Partition part; + void *data; + data = LinuxGetMemory(size); + part = partition_open(data, size); + return(part); +} + +internal void +LinuxScratchPartitionGrow(Partition *part, i32 new_size){ + void *data; + if (new_size > part->max){ + data = LinuxGetMemory(new_size); + memcpy(data, part->base, part->pos); + LinuxFreeMemory(part->base); + part->base = (u8*)data; + } +} + +internal void +LinuxScratchPartitionDouble(Partition *part){ + LinuxScratchPartitionGrow(part, part->max*2); +} + +internal +Sys_Get_Memory_Sig(system_get_memory_){ + return(LinuxGetMemory_(size, line_number, file_name)); +} + +internal +Sys_Free_Memory_Sig(system_free_memory){ + LinuxFreeMemory(block); +} + #if (defined(_BSD_SOURCE) || defined(_SVID_SOURCE)) #define TimeBySt #endif @@ -170,6 +212,7 @@ Sys_File_Time_Stamp_Sig(system_file_time_stamp){ } // TODO(allen): DOES THIS AGREE WITH THE FILESTAMP TIMES? +// NOTE(inso): I don't think so, CLOCK_MONOTONIC is an arbitrary number Sys_Time_Sig(system_time){ struct timespec spec; u64 result; @@ -326,15 +369,21 @@ INTERNAL_Sys_Debug_Message_Sig(internal_debug_message){ DIRECTORY_HAS_FILE_SIG(system_directory_has_file){ int result = 0; - // TODO(allen): Implement - AllowLocal(dir); - AllowLocal(filename); + + //TODO(inso): implement + char buff[PATH_MAX] = {}; + memcpy(buff, dir.str, dir.size); + printf("Has file %s\n", buff); + return(result); } DIRECTORY_CD_SIG(system_directory_cd){ int result = 0; // TODO(allen): Implement + + printf("Dir CD: %.*s\n", dir->size, dir->str); + AllowLocal(dir); AllowLocal(rel_path); return(result); @@ -343,6 +392,8 @@ DIRECTORY_CD_SIG(system_directory_cd){ 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); } @@ -350,8 +401,57 @@ Sys_File_Can_Be_Made(system_file_can_be_made){ internal Sys_Load_File_Sig(system_load_file){ Data result = {}; - // TODO(allen): Implement - AllowLocal(filename); + struct stat info = {}; + int fd; + u8 *ptr, *read_ptr; + size_t bytes_to_read; + ssize_t num; + + fd = open(filename, O_RDONLY); + if(fd < 0){ + perror("sys_open_file: open"); + goto out; + } + if(fstat(fd, &info) < 0){ + perror("sys_open_file: stat"); + goto out; + } + if(info.st_size <= 0){ + printf("st_size < 0: %ld\n", info.st_size); + goto out; + } + + ptr = (u8*)LinuxGetMemory(info.st_size); + if(!ptr){ + puts("null pointer from LGM"); + goto out; + } + + read_ptr = ptr; + bytes_to_read = info.st_size; + + do { + num = read(fd, read_ptr, bytes_to_read); + if(num < 0){ + if(errno == EINTR){ + continue; + } else { + //TODO(inso): error handling + perror("sys_load_file: read"); + LinuxFreeMemory(ptr); + goto out; + } + } else { + bytes_to_read -= num; + read_ptr += num; + } + } while(bytes_to_read); + + result.size = info.st_size; + result.data = ptr; + +out: + if(fd >= 0) close(fd); return(result); } @@ -370,8 +470,46 @@ Sys_Save_File_Sig(system_save_file){ // a little better now that they're starting to settle // into their places. +#include "system_shared.cpp" +#include "4ed_rendering.cpp" + internal Font_Load_Sig(system_draw_font_load){ + Font_Load_Parameters *params; + + system_acquire_lock(FONT_LOCK); + params = linuxvars.fnt.free_param.next; + fnt__remove(params); + fnt__insert(&linuxvars.fnt.used_param, params); + system_release_lock(FONT_LOCK); + + if (linuxvars.fnt.part.base == 0){ + linuxvars.fnt.part = LinuxScratchPartition(Mbytes(8)); + } + + b32 done = 0; + while(!(done = + draw_font_load( + linuxvars.fnt.part.base, + linuxvars.fnt.part.max, + font_out, + filename, + pt_size, + tab_width + ) + )){ + //FIXME(inso): This is an infinite loop if the fonts aren't found! + // Figure out how draw_font_load can fail + + printf("draw_font_load failed, %d\n", linuxvars.fnt.part.max); + LinuxScratchPartitionDouble(&linuxvars.fnt.part); + } + + system_acquire_lock(FONT_LOCK); + fnt__remove(params); + fnt__insert(&linuxvars.fnt.free_param, params); + system_release_lock(FONT_LOCK); + return(0); } @@ -437,9 +575,6 @@ LinuxLoadSystemCode(){ linuxvars.system->internal_debug_message = internal_debug_message; } -#include "system_shared.cpp" -#include "4ed_rendering.cpp" - internal void LinuxLoadRenderCode(){ linuxvars.target.push_clip = draw_push_clip; @@ -484,6 +619,20 @@ ctxErrorHandler( Display *dpy, XErrorEvent *ev ) return 0; } +#if FRED_INTERNAL +static void gl_log( + GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam +){ + printf("GL DEBUG: %s\n", message); +} +#endif + internal GLXContext InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc, b32 &IsLegacy) { @@ -510,9 +659,12 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc, { int context_attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 2, - GLX_CONTEXT_MINOR_VERSION_ARB, 1, - //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, +#if FRED_INTERNAL + GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_DEBUG_BIT_ARB, +#endif None }; @@ -599,7 +751,21 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc, printf("GL_RENDERER: %s\n", Renderer); printf("GL_VERSION: %s\n", Version); printf("GL_EXTENSIONS: %s\n", Extensions); - + +#if FRED_INTERNAL + PFNGLDEBUGMESSAGECALLBACKARBPROC gl_dbg_callback = (PFNGLDEBUGMESSAGECALLBACKARBPROC)glXGetProcAddress((const GLubyte*)"glDebugMessageCallback"); + if(gl_dbg_callback){ + puts("enabling gl debug"); + gl_dbg_callback(&gl_log, 0); + glEnable(GL_DEBUG_OUTPUT); + } +#endif + + glEnable(GL_TEXTURE_2D); + glEnable(GL_SCISSOR_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + return(ctx); } @@ -831,7 +997,8 @@ InitializeXInput(Display *dpy, Window XWindow) EnterWindowMask | LeaveWindowMask | PointerMotionMask | FocusChangeMask | - StructureNotifyMask + StructureNotifyMask | + MappingNotify ); result.input_method = XOpenIM(dpy, 0, 0, 0); @@ -894,11 +1061,11 @@ static void push_key(u8 code, u8 chr, u8 chr_nocaps, b8 (*mods)[CONTROL_KEY_COUN } if(*count < KEY_INPUT_BUFFER_SIZE){ - linuxvars.key_data.press[*count].keycode = code; - linuxvars.key_data.press[*count].character = chr; - linuxvars.key_data.press[*count].character_no_caps_lock = chr_nocaps; + data[*count].keycode = code; + data[*count].character = chr; + data[*count].character_no_caps_lock = chr_nocaps; - memcpy(linuxvars.key_data.press[*count].modifiers, *mods, sizeof(*mods)); + memcpy(data[*count].modifiers, *mods, sizeof(*mods)); ++(*count); } @@ -1012,10 +1179,7 @@ main(int argc, char **argv) Font_Load_Parameters params[8]; sysshared_init_font_params(&linuxvars.fnt, params, ArrayCount(params)); - linuxvars.app.init(linuxvars.system, &linuxvars.target, - &memory_vars, &exchange_vars, &linuxvars.key_codes, - linuxvars.clipboard_contents, current_directory, - linuxvars.custom_api); + // NOTE(allen): Here begins the linux screen setup stuff. // Behold the true nature of this wonderful OS: @@ -1028,7 +1192,6 @@ main(int argc, char **argv) WinWidth = 800; WinHeight = 600; - if(linuxvars.XDisplay && GLXSupportsModernContexts(linuxvars.XDisplay)) { int XScreenCount = ScreenCount(linuxvars.XDisplay); @@ -1098,9 +1261,21 @@ main(int argc, char **argv) XSetICFocus(linuxvars.input_context); if (window_setup_success){ + linuxvars.app.init(linuxvars.system, &linuxvars.target, + &memory_vars, &exchange_vars, &linuxvars.key_codes, + linuxvars.clipboard_contents, current_directory, + linuxvars.custom_api); + LinuxResizeTarget(WinWidth, WinHeight); - - for(;;) + + Atom WM_DELETE_WINDOW = XInternAtom(linuxvars.XDisplay, "WM_DELETE_WINDOW", False); + if(WM_DELETE_WINDOW != None){ + XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, &WM_DELETE_WINDOW, 1); + } + + b32 keep_running = 1; + + while(keep_running) { XEvent PrevEvent = {}; @@ -1115,7 +1290,6 @@ main(int argc, char **argv) switch (Event.type){ case KeyPress: { - b32 is_press = Event.type == KeyPress; b32 is_hold = PrevEvent.type == KeyRelease && PrevEvent.xkey.time == Event.xkey.time && @@ -1127,25 +1301,35 @@ main(int argc, char **argv) if(Event.xkey.state & LockMask) mods[CONTROL_KEY_CAPS] = 1; if(Event.xkey.state & Mod1Mask) mods[CONTROL_KEY_ALT] = 1; // NOTE(inso): mod5 == AltGr - if(Event.xkey.state & Mod5Mask) mods[CONTROL_KEY_ALT] = 1; + // if(Event.xkey.state & Mod5Mask) mods[CONTROL_KEY_ALT] = 1; KeySym keysym = NoSymbol; - char buff[32]; + char buff[32], no_caps_buff[32]; - // NOTE(inso): We only want XLookupString to consider shift / capslock mods - Event.xkey.state &= (ShiftMask | LockMask); + // NOTE(inso): Turn ControlMask off like the win32 code does. + if(mods[CONTROL_KEY_CONTROL] && !mods[CONTROL_KEY_ALT]){ + Event.xkey.state &= ~(ControlMask); + } // TODO(inso): Use one of the Xutf8LookupString funcs to allow for non-ascii chars XLookupString(&Event.xkey, buff, sizeof(buff), &keysym, NULL); + Event.xkey.state &= ~LockMask; + XLookupString(&Event.xkey, no_caps_buff, sizeof(no_caps_buff), NULL, NULL); + u8 key = keycode_lookup(Event.xkey.keycode); if(key){ - push_key(0, 0, key, &mods, is_hold); + push_key(key, 0, 0, &mods, is_hold); } else { key = buff[0] & 0xFF; if(key < 128){ - push_key(key, key, key, &mods, is_hold); + u8 no_caps_key = no_caps_buff[0] & 0xFF; + if(key == '\r') key = '\n'; + if(no_caps_key == '\r') no_caps_key = '\n'; + push_key(key, key, no_caps_key, &mods, is_hold); + } else { + push_key(0, 0, 0, &mods, is_hold); } } }break; @@ -1202,6 +1386,19 @@ main(int argc, char **argv) LinuxResizeTarget(Event.xconfigure.width, Event.xconfigure.height); } }break; + + case MappingNotify: { + if(Event.xmapping.request == MappingModifier || Event.xmapping.request == MappingKeyboard){ + XRefreshKeyboardMapping(&Event.xmapping); + keycode_init(linuxvars.XDisplay, &linuxvars.key_codes); + } + }break; + + case ClientMessage: { + if ((Atom)Event.xclient.data.l[0] == WM_DELETE_WINDOW) { + keep_running = false; + } + }break; } PrevEvent = Event; diff --git a/vc120.pdb b/vc120.pdb index e566bf90f3c0ad2bb4d4db4c493ec04d7d6f3d82..a7482707455be535b068c0582b68d03ca99b3704 100644 GIT binary patch delta 566 zcmZozz}B#UZGs9T(?(T(ZuM{%28JID+Dr^U0HYJ2d>GB3puIVodnpSuL&S^Cf&%aP zCo2f>FfkLjeE}1r3VXB+1H*m?=FRhiOnE0I za47IGa0q~ugMfe_0|OrevuFX3tqjCK(>`w2NDv4`v3%fWW7-%#v5DNh@ SHxTn}4-8;j&A+UGQ2_wZw0L9y delta 437 zcmZozz}B#UZGs9T<3?3}ZguW728JIDu1pL-0HYJ2d>GB3;JP`QdnpUE#R1OEf&%aP zCo2f>F*8Vff^#Mra4=rk%xR#`y4fK00@ox59z~7-kdX`w0-_8I8bCULm4V?5&>Ary zn;D4tr|Tv#Dzox|lxz-l@D|$cAHbNvJ1K!internal_sentinel = INTERNAL_system_sentinel; win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; win32vars.system->internal_debug_message = INTERNAL_system_debug_message; + + win32vars.system->slash = '\\'; } #include "system_shared.cpp"