fix set_file_list a bit + add clipboard paste

master
insofaras 2016-02-22 21:22:52 +00:00 committed by Allen Webster
parent 2f1486c9dd
commit edd6ead966
1 changed files with 292 additions and 165 deletions

View File

@ -72,7 +72,11 @@ struct Linux_Vars{
Mouse_State mouse_data; Mouse_State mouse_data;
String clipboard_contents; String clipboard_contents;
String clipboard_outgoing;
Atom atom_CLIPBOARD;
Atom atom_UTF8_STRING;
void *app_code; void *app_code;
void *custom; void *custom;
@ -89,6 +93,8 @@ struct Linux_Vars{
Font_Load_System fnt; Font_Load_System fnt;
}; };
#define LINUX_MAX_PASTE_CHARS 0x10000L
globalvar Linux_Vars linuxvars; globalvar Linux_Vars linuxvars;
globalvar Application_Memory memory_vars; globalvar Application_Memory memory_vars;
globalvar Exchange exchange_vars; globalvar Exchange exchange_vars;
@ -180,6 +186,21 @@ Sys_Free_Memory_Sig(system_free_memory){
LinuxFreeMemory(block); 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)) #if (defined(_BSD_SOURCE) || defined(_SVID_SOURCE))
#define TimeBySt #define TimeBySt
#endif #endif
@ -231,9 +252,11 @@ Sys_Set_File_List_Sig(system_set_file_list){
i32 count, file_count, size, required_size; i32 count, file_count, size, required_size;
terminate_with_null(&directory); terminate_with_null(&directory);
d = opendir(directory.str); d = opendir(directory.str);
if (d){ if (d){
count = 0; count = 0;
file_count = 0;
for (entry = readdir(d); for (entry = readdir(d);
entry != 0; entry != 0;
entry = readdir(d)){ entry = readdir(d)){
@ -242,7 +265,6 @@ Sys_Set_File_List_Sig(system_set_file_list){
for (size = 0; fname[size]; ++size); for (size = 0; fname[size]; ++size);
count += size + 1; count += size + 1;
} }
closedir(d);
required_size = count + file_count * sizeof(File_Info); required_size = count + file_count * sizeof(File_Info);
if (file_list->block_size < required_size){ 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; file_list->infos = (File_Info*)file_list->block;
cursor = (char*)(file_list->infos + file_count); cursor = (char*)(file_list->infos + file_count);
d = opendir(directory.str); rewinddir(d);
if (d){ info_ptr = file_list->infos;
info_ptr = file_list->infos; for (entry = readdir(d);
for (entry = readdir(d); entry != 0;
entry != 0; entry = readdir(d), ++info_ptr){
entry = readdir(d), ++info_ptr){ fname = entry->d_name;
fname = entry->d_name; cursor_start = cursor;
cursor_start = cursor; for (; *fname; ) *cursor++ = *fname++;
for (; *fname; ) *cursor++ = *fname++;
// TODO(allen): detect file/folder status #ifdef _DIRENT_HAVE_D_TYPE
// (also make sure this even GETS folders!!!) if(entry->d_type != DT_UNKNOWN){
info_ptr->folder = 0; info_ptr->folder = entry->d_type == DT_DIR;
info_ptr->filename.str = cursor_start; } else
info_ptr->filename.size = (i32)(cursor - cursor_start); #endif
*cursor++ = 0; {
info_ptr->filename.memory_size = info_ptr->filename.size + 1; 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);
} }
closedir(d);
} }
Sys_Post_Clipboard_Sig(system_post_clipboard){ Sys_Post_Clipboard_Sig(system_post_clipboard){
// TODO(allen): Implement LinuxStringDup(&linuxvars.clipboard_outgoing, str.str, str.size);
AllowLocal(str); XSetSelectionOwner(linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, linuxvars.XWindow, CurrentTime);
} }
Sys_CLI_Call_Sig(system_cli_call){ Sys_CLI_Call_Sig(system_cli_call){
@ -573,6 +603,8 @@ LinuxLoadSystemCode(){
linuxvars.system->internal_sentinel = internal_sentinel; linuxvars.system->internal_sentinel = internal_sentinel;
linuxvars.system->internal_get_thread_states = internal_get_thread_states; linuxvars.system->internal_get_thread_states = internal_get_thread_states;
linuxvars.system->internal_debug_message = internal_debug_message; linuxvars.system->internal_debug_message = internal_debug_message;
linuxvars.system->slash = '/';
} }
internal void internal void
@ -591,7 +623,7 @@ LinuxRedrawTarget(){
system_acquire_lock(RENDER_LOCK); system_acquire_lock(RENDER_LOCK);
launch_rendering(&linuxvars.target); launch_rendering(&linuxvars.target);
system_release_lock(RENDER_LOCK); system_release_lock(RENDER_LOCK);
glFlush(); // glFlush();
glXSwapBuffers(linuxvars.XDisplay, linuxvars.XWindow); 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); 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); Atom WM_DELETE_WINDOW = XInternAtom(linuxvars.XDisplay, "WM_DELETE_WINDOW", False);
if(WM_DELETE_WINDOW != None){ if(WM_DELETE_WINDOW != None){
XSetWMProtocols(linuxvars.XDisplay, linuxvars.XWindow, &WM_DELETE_WINDOW, 1); 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 = {}; XEvent Event;
XNextEvent(linuxvars.XDisplay, &Event);
while(XPending(linuxvars.XDisplay)) if (XFilterEvent(&Event, None) == True){
{ continue;
XEvent Event; }
XNextEvent(linuxvars.XDisplay, &Event);
if (XFilterEvent(&Event, None) == True){ switch (Event.type){
continue; case KeyPress: {
} b32 is_hold =
PrevEvent.type == KeyRelease &&
PrevEvent.xkey.time == Event.xkey.time &&
PrevEvent.xkey.keycode == Event.xkey.keycode;
switch (Event.type){ b8 mods[CONTROL_KEY_COUNT] = {};
case KeyPress: { if(Event.xkey.state & ShiftMask) mods[CONTROL_KEY_SHIFT] = 1;
b32 is_hold = if(Event.xkey.state & ControlMask) mods[CONTROL_KEY_CONTROL] = 1;
PrevEvent.type == KeyRelease && if(Event.xkey.state & LockMask) mods[CONTROL_KEY_CAPS] = 1;
PrevEvent.xkey.time == Event.xkey.time && if(Event.xkey.state & Mod1Mask) mods[CONTROL_KEY_ALT] = 1;
PrevEvent.xkey.keycode == Event.xkey.keycode; // NOTE(inso): mod5 == AltGr
// if(Event.xkey.state & Mod5Mask) mods[CONTROL_KEY_ALT] = 1;
b8 mods[CONTROL_KEY_COUNT] = {}; KeySym keysym = NoSymbol;
if(Event.xkey.state & ShiftMask) mods[CONTROL_KEY_SHIFT] = 1; char buff[32], no_caps_buff[32];
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; // NOTE(inso): Turn ControlMask off like the win32 code does.
char buff[32], no_caps_buff[32]; if(mods[CONTROL_KEY_CONTROL] && !mods[CONTROL_KEY_ALT]){
Event.xkey.state &= ~(ControlMask);
}
// NOTE(inso): Turn ControlMask off like the win32 code does. // TODO(inso): Use one of the Xutf8LookupString funcs to allow for non-ascii chars
if(mods[CONTROL_KEY_CONTROL] && !mods[CONTROL_KEY_ALT]){ XLookupString(&Event.xkey, buff, sizeof(buff), &keysym, NULL);
Event.xkey.state &= ~(ControlMask);
}
// TODO(inso): Use one of the Xutf8LookupString funcs to allow for non-ascii chars Event.xkey.state &= ~LockMask;
XLookupString(&Event.xkey, buff, sizeof(buff), &keysym, NULL); XLookupString(&Event.xkey, no_caps_buff, sizeof(no_caps_buff), NULL, NULL);
Event.xkey.state &= ~LockMask; u8 key = keycode_lookup(Event.xkey.keycode);
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);
if(key){ } else {
push_key(key, 0, 0, &mods, is_hold);
} else {
key = buff[0] & 0xFF; key = buff[0] & 0xFF;
if(key < 128){ if(key < 128){
u8 no_caps_key = no_caps_buff[0] & 0xFF; u8 no_caps_key = no_caps_buff[0] & 0xFF;
@ -1331,113 +1369,202 @@ main(int argc, char **argv)
} else { } else {
push_key(0, 0, 0, &mods, is_hold); push_key(0, 0, 0, &mods, is_hold);
} }
} }
}break; }break;
case MotionNotify: { case MotionNotify: {
linuxvars.mouse_data.x = Event.xmotion.x; linuxvars.mouse_data.x = Event.xmotion.x;
linuxvars.mouse_data.y = Event.xmotion.y; linuxvars.mouse_data.y = Event.xmotion.y;
}break; }break;
case ButtonPress: { case ButtonPress: {
switch(Event.xbutton.button){ switch(Event.xbutton.button){
case Button1: { case Button1: {
linuxvars.mouse_data.left_button_pressed = 1; linuxvars.mouse_data.left_button_pressed = 1;
linuxvars.mouse_data.left_button = 1; linuxvars.mouse_data.left_button = 1;
} break; } break;
case Button3: { case Button3: {
linuxvars.mouse_data.right_button_pressed = 1; linuxvars.mouse_data.right_button_pressed = 1;
linuxvars.mouse_data.right_button = 1; linuxvars.mouse_data.right_button = 1;
} break; } break;
} }
}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: { case ButtonRelease: {
linuxvars.mouse_data.out_of_window = 0; switch(Event.xbutton.button){
}break; 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 LeaveNotify: { case EnterNotify: {
linuxvars.mouse_data.out_of_window = 1; linuxvars.mouse_data.out_of_window = 0;
}break; }break;
case FocusIn: case LeaveNotify: {
case FocusOut: { linuxvars.mouse_data.out_of_window = 1;
linuxvars.mouse_data.left_button = 0; }break;
linuxvars.mouse_data.right_button = 0;
}break;
case ConfigureNotify: { case FocusIn:
i32 w = Event.xconfigure.width, h = Event.xconfigure.height; case FocusOut: {
linuxvars.mouse_data.left_button = 0;
linuxvars.mouse_data.right_button = 0;
}break;
if(w != linuxvars.target.width || h != linuxvars.target.height){ case ConfigureNotify: {
LinuxResizeTarget(Event.xconfigure.width, Event.xconfigure.height); i32 w = Event.xconfigure.width, h = Event.xconfigure.height;
}
}break;
case MappingNotify: { if(w != linuxvars.target.width || h != linuxvars.target.height){
if(Event.xmapping.request == MappingModifier || Event.xmapping.request == MappingKeyboard){ LinuxResizeTarget(Event.xconfigure.width, Event.xconfigure.height);
XRefreshKeyboardMapping(&Event.xmapping); }
keycode_init(linuxvars.XDisplay, &linuxvars.key_codes); }break;
}
}break;
case ClientMessage: { case MappingNotify: {
if ((Atom)Event.xclient.data.l[0] == WM_DELETE_WINDOW) { if(Event.xmapping.request == MappingModifier || Event.xmapping.request == MappingKeyboard){
keep_running = false; XRefreshKeyboardMapping(&Event.xmapping);
} keycode_init(linuxvars.XDisplay, &linuxvars.key_codes);
}break; }
} }break;
PrevEvent = Event; 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; PrevEvent = Event;
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;
} }
// 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;
} }
} }