about to patch linux clipboard
parent
46aaa4ac5b
commit
2f1486c9dd
|
@ -0,0 +1,600 @@
|
|||
From 6d24dc4f80df0816a2c34b2a56026cb10ea1fd79 Mon Sep 17 00:00:00 2001
|
||||
From: insofaras <iaminsofaras@gmail.com>
|
||||
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
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
From 2e9c55181ecb0a0f94c7f1b389f19fd76e856d55 Mon Sep 17 00:00:00 2001
|
||||
From: insofaras <iaminsofaras@gmail.com>
|
||||
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
|
||||
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
22
4ed.cpp
22
4ed.cpp
|
@ -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);
|
||||
|
||||
|
|
16
4ed.h
16
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
114
4ed_gui.cpp
114
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -176,9 +176,11 @@ struct Render_Target{
|
|||
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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
263
linux_4ed.cpp
263
linux_4ed.cpp
|
@ -38,6 +38,8 @@
|
|||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
#include <xmmintrin.h>
|
||||
#include <linux/fs.h>
|
||||
//#include <X11/extensions/XInput2.h>
|
||||
|
@ -52,6 +54,9 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -600,6 +752,20 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
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;
|
||||
|
|
|
@ -946,6 +946,8 @@ Win32LoadSystemCode(){
|
|||
win32vars.system->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"
|
||||
|
|
Loading…
Reference in New Issue