fix linux input handling, implement more stuff
it seems to occasionally crash and might be leaking memory currently...
This commit is contained in:
parent
56f5d78fa2
commit
61ddb8a9d1
|
@ -77,6 +77,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
#define Cursor XCursor
|
#define Cursor XCursor
|
||||||
|
@ -153,10 +154,9 @@ struct Linux_Vars {
|
||||||
Linux_Input_Chunk input;
|
Linux_Input_Chunk input;
|
||||||
|
|
||||||
int epoll;
|
int epoll;
|
||||||
|
int step_event_fd;
|
||||||
int step_timer_fd;
|
int step_timer_fd;
|
||||||
u64 last_step_time;
|
u64 last_step_time;
|
||||||
b32 is_full_screen;
|
|
||||||
b32 should_be_full_screen;
|
|
||||||
|
|
||||||
Application_Mouse_Cursor cursor;
|
Application_Mouse_Cursor cursor;
|
||||||
XCursor hidden_cursor;
|
XCursor hidden_cursor;
|
||||||
|
@ -195,7 +195,8 @@ global Render_Target render_target;
|
||||||
|
|
||||||
typedef i32 Epoll_Kind;
|
typedef i32 Epoll_Kind;
|
||||||
enum {
|
enum {
|
||||||
EPOLL_FRAME_TIMER,
|
EPOLL_STEP_EVENT,
|
||||||
|
EPOLL_STEP_TIMER,
|
||||||
EPOLL_X11,
|
EPOLL_X11,
|
||||||
EPOLL_X11_INTERNAL,
|
EPOLL_X11_INTERNAL,
|
||||||
EPOLL_CLI_PIPE,
|
EPOLL_CLI_PIPE,
|
||||||
|
@ -207,7 +208,8 @@ enum {
|
||||||
// If per-event data is needed, container_of can be used on data.ptr
|
// If per-event data is needed, container_of can be used on data.ptr
|
||||||
// to access the containing struct and all its other members.
|
// to access the containing struct and all its other members.
|
||||||
|
|
||||||
internal Epoll_Kind epoll_tag_frame_timer = EPOLL_FRAME_TIMER;
|
internal Epoll_Kind epoll_tag_step_event = EPOLL_STEP_EVENT;
|
||||||
|
internal Epoll_Kind epoll_tag_step_timer = EPOLL_STEP_TIMER;
|
||||||
internal Epoll_Kind epoll_tag_x11 = EPOLL_X11;
|
internal Epoll_Kind epoll_tag_x11 = EPOLL_X11;
|
||||||
internal Epoll_Kind epoll_tag_x11_internal = EPOLL_X11_INTERNAL;
|
internal Epoll_Kind epoll_tag_x11_internal = EPOLL_X11_INTERNAL;
|
||||||
internal Epoll_Kind epoll_tag_cli_pipe = EPOLL_CLI_PIPE;
|
internal Epoll_Kind epoll_tag_cli_pipe = EPOLL_CLI_PIPE;
|
||||||
|
@ -342,19 +344,40 @@ internal void
|
||||||
linux_schedule_step(){
|
linux_schedule_step(){
|
||||||
u64 now = system_now_time();
|
u64 now = system_now_time();
|
||||||
u64 diff = (now - linuxvars.last_step_time);
|
u64 diff = (now - linuxvars.last_step_time);
|
||||||
|
if (diff > (u64)frame_useconds){
|
||||||
|
u64 ev = 1;
|
||||||
|
write(linuxvars.step_event_fd, &ev, sizeof(ev));
|
||||||
|
}
|
||||||
|
else{
|
||||||
struct itimerspec its = {};
|
struct itimerspec its = {};
|
||||||
timerfd_gettime(linuxvars.step_timer_fd, &its);
|
timerfd_gettime(linuxvars.step_timer_fd, &its);
|
||||||
|
|
||||||
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0){
|
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0){
|
||||||
if(diff > (u64)frame_useconds) {
|
|
||||||
its.it_value.tv_nsec = 1;
|
|
||||||
} else {
|
|
||||||
its.it_value.tv_nsec = (frame_useconds - diff) * 1000UL;
|
its.it_value.tv_nsec = (frame_useconds - diff) * 1000UL;
|
||||||
}
|
|
||||||
timerfd_settime(linuxvars.step_timer_fd, 0, &its, NULL);
|
timerfd_settime(linuxvars.step_timer_fd, 0, &its, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
linux_set_wm_state(Atom one, Atom two, int mode){
|
||||||
|
//NOTE(inso): this will only work after the window has been mapped
|
||||||
|
|
||||||
|
enum { STATE_REMOVE, STATE_ADD, STATE_TOGGLE };
|
||||||
|
|
||||||
|
XEvent e = {};
|
||||||
|
e.xany.type = ClientMessage;
|
||||||
|
e.xclient.message_type = linuxvars.atom__NET_WM_STATE;
|
||||||
|
e.xclient.format = 32;
|
||||||
|
e.xclient.window = linuxvars.win;
|
||||||
|
e.xclient.data.l[0] = mode;
|
||||||
|
e.xclient.data.l[1] = one;
|
||||||
|
e.xclient.data.l[2] = two;
|
||||||
|
e.xclient.data.l[3] = 1L;
|
||||||
|
|
||||||
|
XSendEvent(linuxvars.dpy,
|
||||||
|
RootWindow(linuxvars.dpy, 0),
|
||||||
|
0, SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
||||||
|
}
|
||||||
|
|
||||||
internal int
|
internal int
|
||||||
linux_get_xsettings_dpi(Display* dpy, int screen){
|
linux_get_xsettings_dpi(Display* dpy, int screen){
|
||||||
|
@ -770,7 +793,7 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {
|
||||||
render_target.height = h;
|
render_target.height = h;
|
||||||
|
|
||||||
XSetWindowAttributes swa = {};
|
XSetWindowAttributes swa = {};
|
||||||
swa.backing_store = NotUseful;
|
swa.backing_store = WhenMapped;
|
||||||
swa.event_mask = StructureNotifyMask;
|
swa.event_mask = StructureNotifyMask;
|
||||||
swa.bit_gravity = NorthWestGravity;
|
swa.bit_gravity = NorthWestGravity;
|
||||||
swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi.screen), vi.visual, AllocNone);
|
swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi.screen), vi.visual, AllocNone);
|
||||||
|
@ -1036,6 +1059,25 @@ linux_keycode_init(Display* dpy){
|
||||||
XFree(syms);
|
XFree(syms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal String_Const_u8
|
||||||
|
linux_filter_text(Arena* arena, u8* buf, int len) {
|
||||||
|
u8* const result = push_array(arena, u8, len);
|
||||||
|
u8* const endp = buf + len;
|
||||||
|
u8* outp = result;
|
||||||
|
|
||||||
|
for(int i = 0; i < len; ++i) {
|
||||||
|
u8 c = buf[i];
|
||||||
|
|
||||||
|
if(c == '\r') {
|
||||||
|
*outp++ = '\n';
|
||||||
|
} else if(c > 127 || (' ' <= c && c <= '~') || c == '\t') {
|
||||||
|
*outp++ = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCu8(result, outp - result);
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
linux_handle_x11_events() {
|
linux_handle_x11_events() {
|
||||||
static XEvent prev_event = {};
|
static XEvent prev_event = {};
|
||||||
|
@ -1053,12 +1095,6 @@ linux_handle_x11_events() {
|
||||||
case KeyPress: {
|
case KeyPress: {
|
||||||
should_step = true;
|
should_step = true;
|
||||||
|
|
||||||
/*
|
|
||||||
b32 is_hold = (prev_event.type == KeyRelease &&
|
|
||||||
prev_event.xkey.time == event.xkey.time &&
|
|
||||||
prev_event.xkey.keycode == event.xkey.keycode);
|
|
||||||
*/
|
|
||||||
|
|
||||||
Input_Modifier_Set_Fixed* mods = &linuxvars.input.pers.modifiers;
|
Input_Modifier_Set_Fixed* mods = &linuxvars.input.pers.modifiers;
|
||||||
block_zero_struct(mods);
|
block_zero_struct(mods);
|
||||||
|
|
||||||
|
@ -1072,9 +1108,9 @@ linux_handle_x11_events() {
|
||||||
|
|
||||||
Status status;
|
Status status;
|
||||||
KeySym keysym = NoSymbol;
|
KeySym keysym = NoSymbol;
|
||||||
u8 buff[256] = {};
|
u8 buf[256] = {};
|
||||||
|
|
||||||
int len = Xutf8LookupString(linuxvars.xic, &event.xkey, (char*)buff, sizeof(buff) - 1, &keysym, &status);
|
int len = Xutf8LookupString(linuxvars.xic, &event.xkey, (char*)buf, sizeof(buf) - 1, &keysym, &status);
|
||||||
|
|
||||||
if (status == XBufferOverflow){
|
if (status == XBufferOverflow){
|
||||||
//TODO(inso): handle properly
|
//TODO(inso): handle properly
|
||||||
|
@ -1083,27 +1119,82 @@ linux_handle_x11_events() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keysym == XK_ISO_Left_Tab){
|
if (keysym == XK_ISO_Left_Tab){
|
||||||
//text = '\t';
|
printf("left tab? [%.*s]\n", len, buf);
|
||||||
add_modifier(mods, KeyCode_Shift);
|
add_modifier(mods, KeyCode_Shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
Key_Code key = keycode_lookup_table[(u8)event.xkey.keycode];
|
Key_Code key = keycode_lookup_table[(u8)event.xkey.keycode];
|
||||||
printf("key [%d] = %s\n", event.xkey.keycode, key_code_name[key]);
|
printf("key [%d] = %s\n", event.xkey.keycode, key_code_name[key]);
|
||||||
|
|
||||||
|
Input_Event* key_event = NULL;
|
||||||
if(key) {
|
if(key) {
|
||||||
Input_Event *ev = push_input_event(linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
key_event = push_input_event(linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
||||||
ev->kind = InputEventKind_KeyStroke;
|
key_event->kind = InputEventKind_KeyStroke;
|
||||||
ev->key.code = key;
|
key_event->key.code = key;
|
||||||
ev->key.modifiers = copy_modifier_set(linuxvars.frame_arena, mods);
|
key_event->key.modifiers = copy_modifier_set(linuxvars.frame_arena, mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Input_Event* text_event = NULL;
|
||||||
if(status == XLookupChars || status == XLookupBoth) {
|
if(status == XLookupChars || status == XLookupBoth) {
|
||||||
u8* ptr = push_array_write(linuxvars.frame_arena, u8, len, buff);
|
String_Const_u8 str = linux_filter_text(linuxvars.frame_arena, buf, len);
|
||||||
Input_Event* ev = push_input_event(linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
if(str.size) {
|
||||||
ev->kind = InputEventKind_TextInsert;
|
text_event = push_input_event(linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
||||||
ev->text.string = SCu8(ptr, len);
|
text_event->kind = InputEventKind_TextInsert;
|
||||||
|
text_event->text.string = str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(key_event && text_event) {
|
||||||
|
key_event->key.first_dependent_text = text_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case KeyRelease: {
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case MotionNotify: {
|
||||||
|
linuxvars.input.pers.mouse = { event.xmotion.x, event.xmotion.y };
|
||||||
|
should_step = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ButtonPress: {
|
||||||
|
should_step = true;
|
||||||
|
switch(event.xbutton.button) {
|
||||||
|
case Button1: {
|
||||||
|
linuxvars.input.trans.mouse_l_press = true;
|
||||||
|
linuxvars.input.pers.mouse_l = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Button3: {
|
||||||
|
linuxvars.input.trans.mouse_r_press = true;
|
||||||
|
linuxvars.input.pers.mouse_r = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Button4: {
|
||||||
|
linuxvars.input.trans.mouse_wheel = -100;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Button5: {
|
||||||
|
linuxvars.input.trans.mouse_wheel = +100;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ButtonRelease: {
|
||||||
|
should_step = true;
|
||||||
|
switch(event.xbutton.button) {
|
||||||
|
case Button1: {
|
||||||
|
linuxvars.input.trans.mouse_l_release = true;
|
||||||
|
linuxvars.input.pers.mouse_l = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Button3: {
|
||||||
|
linuxvars.input.trans.mouse_r_release = true;
|
||||||
|
linuxvars.input.pers.mouse_r = false;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MappingNotify: {
|
case MappingNotify: {
|
||||||
|
@ -1114,15 +1205,36 @@ linux_handle_x11_events() {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ConfigureNotify: {
|
case ConfigureNotify: {
|
||||||
should_step = true;
|
|
||||||
i32 w = event.xconfigure.width;
|
i32 w = event.xconfigure.width;
|
||||||
i32 h = event.xconfigure.height;
|
i32 h = event.xconfigure.height;
|
||||||
|
|
||||||
if (w != render_target.width || h != render_target.height){
|
if (w != render_target.width || h != render_target.height){
|
||||||
|
should_step = true;
|
||||||
render_target.width = w;
|
render_target.width = w;
|
||||||
render_target.height = h;
|
render_target.height = h;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case ClientMessage: {
|
||||||
|
Atom atom = event.xclient.data.l[0];
|
||||||
|
|
||||||
|
// Window X button clicked
|
||||||
|
if(atom == linuxvars.atom_WM_DELETE_WINDOW) {
|
||||||
|
should_step = true;
|
||||||
|
linuxvars.input.trans.trying_to_kill = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify WM that we're still responding (don't grey our window out).
|
||||||
|
else if(atom == linuxvars.atom__NET_WM_PING) {
|
||||||
|
event.xclient.window = DefaultRootWindow(linuxvars.dpy);
|
||||||
|
XSendEvent(
|
||||||
|
linuxvars.dpy,
|
||||||
|
event.xclient.window,
|
||||||
|
False,
|
||||||
|
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||||
|
&event);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1148,7 +1260,16 @@ linux_epoll_process(struct epoll_event* events, int num_events) {
|
||||||
//XProcessInternalConnection(linuxvars.dpy, fd);
|
//XProcessInternalConnection(linuxvars.dpy, fd);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case EPOLL_FRAME_TIMER: {
|
case EPOLL_STEP_EVENT: {
|
||||||
|
u64 ev;
|
||||||
|
int ret;
|
||||||
|
do {
|
||||||
|
ret = read(linuxvars.step_event_fd, &ev, 8);
|
||||||
|
} while (ret != -1 || errno != EAGAIN);
|
||||||
|
do_step = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case EPOLL_STEP_TIMER: {
|
||||||
u64 count;
|
u64 count;
|
||||||
int ret;
|
int ret;
|
||||||
do {
|
do {
|
||||||
|
@ -1346,13 +1467,17 @@ main(int argc, char **argv){
|
||||||
e.events = EPOLLIN | EPOLLET;
|
e.events = EPOLLIN | EPOLLET;
|
||||||
|
|
||||||
//linuxvars.inotify_fd = inotify_init1(IN_NONBLOCK);
|
//linuxvars.inotify_fd = inotify_init1(IN_NONBLOCK);
|
||||||
|
linuxvars.step_event_fd = eventfd(0, EFD_NONBLOCK);
|
||||||
linuxvars.step_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
linuxvars.step_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||||
linuxvars.epoll = epoll_create(16);
|
linuxvars.epoll = epoll_create(16);
|
||||||
|
|
||||||
e.data.ptr = &epoll_tag_x11;
|
e.data.ptr = &epoll_tag_x11;
|
||||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, ConnectionNumber(linuxvars.dpy), &e);
|
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, ConnectionNumber(linuxvars.dpy), &e);
|
||||||
|
|
||||||
e.data.ptr = &epoll_tag_frame_timer;
|
e.data.ptr = &epoll_tag_step_event;
|
||||||
|
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_event_fd, &e);
|
||||||
|
|
||||||
|
e.data.ptr = &epoll_tag_step_timer;
|
||||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_timer_fd, &e);
|
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_timer_fd, &e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1367,10 +1492,9 @@ main(int argc, char **argv){
|
||||||
system_mutex_acquire(linuxvars.global_frame_mutex);
|
system_mutex_acquire(linuxvars.global_frame_mutex);
|
||||||
|
|
||||||
linux_schedule_step();
|
linux_schedule_step();
|
||||||
|
|
||||||
b32 first_step = true;
|
b32 first_step = true;
|
||||||
b32 keep_running = true;
|
|
||||||
for (;keep_running;){
|
for (;;) {
|
||||||
|
|
||||||
if (XEventsQueued(linuxvars.dpy, QueuedAlready)){
|
if (XEventsQueued(linuxvars.dpy, QueuedAlready)){
|
||||||
linux_handle_x11_events();
|
linux_handle_x11_events();
|
||||||
|
@ -1395,7 +1519,9 @@ main(int argc, char **argv){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
linuxvars.last_step_time = system_now_time();
|
u64 now = system_now_time();
|
||||||
|
printf(" ***** STEP DIFF = %.2f\n", (now - linuxvars.last_step_time) / 1000000.0);
|
||||||
|
linuxvars.last_step_time = now;
|
||||||
|
|
||||||
// NOTE(allen): Frame Clipboard Input
|
// NOTE(allen): Frame Clipboard Input
|
||||||
// Request clipboard contents from X11 on first step, or every step if they don't have XFixes notification ability.
|
// Request clipboard contents from X11 on first step, or every step if they don't have XFixes notification ability.
|
||||||
|
@ -1410,32 +1536,31 @@ main(int argc, char **argv){
|
||||||
linuxvars.received_new_clipboard = false;
|
linuxvars.received_new_clipboard = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fill the rest of it
|
|
||||||
input.trying_to_kill = !keep_running;
|
|
||||||
input.dt = frame_useconds/1000000.f;
|
|
||||||
input.events = linuxvars.input.trans.event_list;
|
|
||||||
input.first_step = first_step;
|
input.first_step = first_step;
|
||||||
|
input.dt = frame_useconds/1000000.f; // variable?
|
||||||
|
input.events = linuxvars.input.trans.event_list;
|
||||||
|
input.trying_to_kill = linuxvars.input.trans.trying_to_kill;
|
||||||
|
|
||||||
|
input.mouse.out_of_window = false;
|
||||||
|
input.mouse.p = linuxvars.input.pers.mouse;
|
||||||
|
input.mouse.l = linuxvars.input.pers.mouse_l;
|
||||||
|
input.mouse.r = linuxvars.input.pers.mouse_r;
|
||||||
|
input.mouse.press_l = linuxvars.input.trans.mouse_l_press;
|
||||||
|
input.mouse.release_l = linuxvars.input.trans.mouse_l_release;
|
||||||
|
input.mouse.press_r = linuxvars.input.trans.mouse_r_press;
|
||||||
|
input.mouse.release_r = linuxvars.input.trans.mouse_r_release;
|
||||||
|
input.mouse.wheel = linuxvars.input.trans.mouse_wheel;
|
||||||
|
|
||||||
// NOTE(allen): Application Core Update
|
// NOTE(allen): Application Core Update
|
||||||
// render_target.buffer.pos = 0;
|
|
||||||
Application_Step_Result result = {};
|
Application_Step_Result result = {};
|
||||||
if (app.step != 0){
|
if (app.step != 0){
|
||||||
result = app.step(&linuxvars.tctx, &render_target, base_ptr, &input);
|
result = app.step(&linuxvars.tctx, &render_target, base_ptr, &input);
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
//LOG("app.step == 0 -- skipping\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(allen): Finish the Loop
|
// NOTE(allen): Finish the Loop
|
||||||
if (result.perform_kill){
|
if (result.perform_kill){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// TODO
|
|
||||||
#if 0
|
|
||||||
else if (!keep_running && !linuxvars.keep_running){
|
|
||||||
linuxvars.keep_running = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// NOTE(NAME): Switch to New Title
|
// NOTE(NAME): Switch to New Title
|
||||||
if (result.has_new_title){
|
if (result.has_new_title){
|
||||||
|
@ -1462,3 +1587,6 @@ main(int argc, char **argv){
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(inso): to prevent me continuously messing up indentation
|
||||||
|
// vim: et:ts=4:sts=4:sw=4
|
||||||
|
|
|
@ -53,11 +53,53 @@ system_get_path(Arena* arena, System_Path_Code path_code){
|
||||||
|
|
||||||
internal String_Const_u8
|
internal String_Const_u8
|
||||||
system_get_canonical(Arena* arena, String_Const_u8 name){
|
system_get_canonical(Arena* arena, String_Const_u8 name){
|
||||||
LINUX_FN_DEBUG("%.*s", (int)name.size, name.str);
|
|
||||||
// TODO(andrew): Resolve symlinks ?
|
// first remove redundant ../, //, ./ parts
|
||||||
// TODO(andrew): Resolve . and .. in paths
|
|
||||||
// TODO(andrew): Use realpath(3)
|
const u8* input = (u8*) strndupa((char*)name.str, name.size);
|
||||||
return name;
|
u8* output = push_array(arena, u8, name.size + 1);
|
||||||
|
|
||||||
|
const u8* p = input;
|
||||||
|
u8* q = output;
|
||||||
|
|
||||||
|
while(*p) {
|
||||||
|
|
||||||
|
// not a slash - copy char
|
||||||
|
if(p[0] != '/') {
|
||||||
|
*q++ = *p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// two slashes in a row, skip one.
|
||||||
|
if(p[1] == '/') {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
else if(p[1] == '.') {
|
||||||
|
|
||||||
|
// skip "/./" or trailing "/."
|
||||||
|
if(p[2] == '/' || p[2] == '\0') {
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we encounter "/../" or trailing "/..", remove last directory instead
|
||||||
|
else if(p[2] == '.' && (p[3] == '/' || p[3] == '\0')) {
|
||||||
|
while(q > output && *--q != '/'){};
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
*q++ = *p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*q++ = *p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LINUX_FN_DEBUG("[%.*s] -> [%.*s]", (int)name.size, name.str, (int)(q - output), output);
|
||||||
|
|
||||||
|
// TODO: use realpath at this point to resolve symlinks?
|
||||||
|
return SCu8(output, q - output);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal File_List
|
internal File_List
|
||||||
|
@ -100,16 +142,27 @@ system_get_file_list(Arena* arena, String_Const_u8 directory){
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
|
if(result.count > 0) {
|
||||||
result.infos = fip = push_array(arena, File_Info*, result.count);
|
result.infos = fip = push_array(arena, File_Info*, result.count);
|
||||||
|
|
||||||
for(File_Info* f = head; f; f = f->next) {
|
for(File_Info* f = head; f; f = f->next) {
|
||||||
*fip++ = f;
|
*fip++ = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(inso): I want to sort them like this (. files lower), but it looks like
|
||||||
|
// the sorting is done on the custom-layer side (lister), so this is pointless.
|
||||||
|
// TODO(inso): add linux-specific custom layer code?
|
||||||
|
|
||||||
|
/*
|
||||||
qsort(result.infos, result.count, sizeof(File_Info*), (__compar_fn_t)&linux_compare_file_infos);
|
qsort(result.infos, result.count, sizeof(File_Info*), (__compar_fn_t)&linux_compare_file_infos);
|
||||||
|
|
||||||
|
for(u32 i = 0; i < result.count - 1; ++i) {
|
||||||
|
result.infos[i]->next = result.infos[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: relink in new order?
|
result.infos[result.count-1]->next = NULL;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -200,7 +253,7 @@ system_get_proc(System_Library handle, char* proc_name){
|
||||||
|
|
||||||
internal u64
|
internal u64
|
||||||
system_now_time(void){
|
system_now_time(void){
|
||||||
LINUX_FN_DEBUG();
|
//LINUX_FN_DEBUG();
|
||||||
struct timespec time;
|
struct timespec time;
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &time);
|
clock_gettime(CLOCK_MONOTONIC_RAW, &time);
|
||||||
return linux_u64_from_timespec(time);
|
return linux_u64_from_timespec(time);
|
||||||
|
@ -232,23 +285,23 @@ system_wake_up_timer_release(Plat_Handle handle){
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
system_wake_up_timer_set(Plat_Handle handle, u32 time_milliseconds){
|
system_wake_up_timer_set(Plat_Handle handle, u32 time_milliseconds){
|
||||||
LINUX_FN_DEBUG("%d", time_milliseconds);
|
LINUX_FN_DEBUG("%u", time_milliseconds);
|
||||||
Linux_Object* object = handle_to_object(handle);
|
Linux_Object* object = handle_to_object(handle);
|
||||||
|
|
||||||
if (object->kind == LinuxObjectKind_Timer){
|
if (object->kind == LinuxObjectKind_Timer){
|
||||||
if(object->timer.fd == -1) {
|
if(object->timer.fd == -1) {
|
||||||
object->timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
object->timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||||
|
|
||||||
|
struct epoll_event ev;
|
||||||
|
ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
|
||||||
|
ev.data.ptr = &object->timer.epoll_tag;
|
||||||
|
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, object->timer.fd, &ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct itimerspec it = {};
|
struct itimerspec it = {};
|
||||||
it.it_value.tv_sec = time_milliseconds / 1000;
|
it.it_value.tv_sec = time_milliseconds / 1000;
|
||||||
it.it_value.tv_nsec = (time_milliseconds % 1000) * UINT64_C(1000000);
|
it.it_value.tv_nsec = (time_milliseconds % 1000) * UINT64_C(1000000);
|
||||||
|
timerfd_settime(object->timer.fd, 0, &it, NULL);
|
||||||
struct epoll_event ev;
|
|
||||||
ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
|
|
||||||
ev.data.ptr = &object->timer.epoll_tag;
|
|
||||||
|
|
||||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, object->timer.fd, &ev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -461,7 +514,7 @@ system_thread_free(System_Thread thread){
|
||||||
internal i32
|
internal i32
|
||||||
system_thread_get_id(void){
|
system_thread_get_id(void){
|
||||||
pid_t id = syscall(__NR_gettid);
|
pid_t id = syscall(__NR_gettid);
|
||||||
LINUX_FN_DEBUG("%d", id);
|
//LINUX_FN_DEBUG("%d", id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,14 +540,14 @@ system_mutex_make(void){
|
||||||
Linux_Object* object = linux_alloc_object(LinuxObjectKind_Mutex);
|
Linux_Object* object = linux_alloc_object(LinuxObjectKind_Mutex);
|
||||||
pthread_mutex_init(&object->mutex, NULL);
|
pthread_mutex_init(&object->mutex, NULL);
|
||||||
*(Linux_Object**)&result = object;
|
*(Linux_Object**)&result = object;
|
||||||
LINUX_FN_DEBUG("%p", object);
|
//LINUX_FN_DEBUG("%p", object);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
system_mutex_acquire(System_Mutex mutex){
|
system_mutex_acquire(System_Mutex mutex){
|
||||||
Linux_Object* object = *(Linux_Object**)&mutex;
|
Linux_Object* object = *(Linux_Object**)&mutex;
|
||||||
LINUX_FN_DEBUG("%p", object);
|
//LINUX_FN_DEBUG("%p", object);
|
||||||
Assert(object->kind == LinuxObjectKind_Mutex);
|
Assert(object->kind == LinuxObjectKind_Mutex);
|
||||||
pthread_mutex_lock(&object->mutex);
|
pthread_mutex_lock(&object->mutex);
|
||||||
}
|
}
|
||||||
|
@ -502,7 +555,7 @@ system_mutex_acquire(System_Mutex mutex){
|
||||||
internal void
|
internal void
|
||||||
system_mutex_release(System_Mutex mutex){
|
system_mutex_release(System_Mutex mutex){
|
||||||
Linux_Object* object = *(Linux_Object**)&mutex;
|
Linux_Object* object = *(Linux_Object**)&mutex;
|
||||||
LINUX_FN_DEBUG("%p", object);
|
//LINUX_FN_DEBUG("%p", object);
|
||||||
Assert(object->kind == LinuxObjectKind_Mutex);
|
Assert(object->kind == LinuxObjectKind_Mutex);
|
||||||
pthread_mutex_unlock(&object->mutex);
|
pthread_mutex_unlock(&object->mutex);
|
||||||
}
|
}
|
||||||
|
@ -510,7 +563,7 @@ system_mutex_release(System_Mutex mutex){
|
||||||
internal void
|
internal void
|
||||||
system_mutex_free(System_Mutex mutex){
|
system_mutex_free(System_Mutex mutex){
|
||||||
Linux_Object* object = *(Linux_Object**)&mutex;
|
Linux_Object* object = *(Linux_Object**)&mutex;
|
||||||
LINUX_FN_DEBUG("%p", object);
|
//LINUX_FN_DEBUG("%p", object);
|
||||||
Assert(object->kind == LinuxObjectKind_Mutex);
|
Assert(object->kind == LinuxObjectKind_Mutex);
|
||||||
pthread_mutex_destroy(&object->mutex);
|
pthread_mutex_destroy(&object->mutex);
|
||||||
linux_free_object(object);
|
linux_free_object(object);
|
||||||
|
@ -520,7 +573,7 @@ internal System_Condition_Variable
|
||||||
system_condition_variable_make(void){
|
system_condition_variable_make(void){
|
||||||
System_Condition_Variable result = {};
|
System_Condition_Variable result = {};
|
||||||
Linux_Object* object = linux_alloc_object(LinuxObjectKind_ConditionVariable);
|
Linux_Object* object = linux_alloc_object(LinuxObjectKind_ConditionVariable);
|
||||||
LINUX_FN_DEBUG("%p", object);
|
//LINUX_FN_DEBUG("%p", object);
|
||||||
pthread_cond_init(&object->condition_variable, NULL);
|
pthread_cond_init(&object->condition_variable, NULL);
|
||||||
*(Linux_Object**)&result = object;
|
*(Linux_Object**)&result = object;
|
||||||
return result;
|
return result;
|
||||||
|
@ -530,7 +583,7 @@ internal void
|
||||||
system_condition_variable_wait(System_Condition_Variable cv, System_Mutex mutex){
|
system_condition_variable_wait(System_Condition_Variable cv, System_Mutex mutex){
|
||||||
Linux_Object* cv_object = *(Linux_Object**)&cv;
|
Linux_Object* cv_object = *(Linux_Object**)&cv;
|
||||||
Linux_Object* mutex_object = *(Linux_Object**)&mutex;
|
Linux_Object* mutex_object = *(Linux_Object**)&mutex;
|
||||||
LINUX_FN_DEBUG("%p / %p", cv_object, mutex_object);
|
//LINUX_FN_DEBUG("%p / %p", cv_object, mutex_object);
|
||||||
Assert(cv_object->kind == LinuxObjectKind_ConditionVariable);
|
Assert(cv_object->kind == LinuxObjectKind_ConditionVariable);
|
||||||
Assert(mutex_object->kind == LinuxObjectKind_Mutex);
|
Assert(mutex_object->kind == LinuxObjectKind_Mutex);
|
||||||
pthread_cond_wait(&cv_object->condition_variable, &mutex_object->mutex);
|
pthread_cond_wait(&cv_object->condition_variable, &mutex_object->mutex);
|
||||||
|
@ -539,7 +592,7 @@ system_condition_variable_wait(System_Condition_Variable cv, System_Mutex mutex)
|
||||||
internal void
|
internal void
|
||||||
system_condition_variable_signal(System_Condition_Variable cv){
|
system_condition_variable_signal(System_Condition_Variable cv){
|
||||||
Linux_Object* object = *(Linux_Object**)&cv;
|
Linux_Object* object = *(Linux_Object**)&cv;
|
||||||
LINUX_FN_DEBUG("%p", object);
|
//LINUX_FN_DEBUG("%p", object);
|
||||||
Assert(object->kind == LinuxObjectKind_ConditionVariable);
|
Assert(object->kind == LinuxObjectKind_ConditionVariable);
|
||||||
pthread_cond_signal(&object->condition_variable);
|
pthread_cond_signal(&object->condition_variable);
|
||||||
}
|
}
|
||||||
|
@ -547,7 +600,7 @@ system_condition_variable_signal(System_Condition_Variable cv){
|
||||||
internal void
|
internal void
|
||||||
system_condition_variable_free(System_Condition_Variable cv){
|
system_condition_variable_free(System_Condition_Variable cv){
|
||||||
Linux_Object* object = *(Linux_Object**)&cv;
|
Linux_Object* object = *(Linux_Object**)&cv;
|
||||||
LINUX_FN_DEBUG("%p", object);
|
//LINUX_FN_DEBUG("%p", object);
|
||||||
Assert(object->kind == LinuxObjectKind_ConditionVariable);
|
Assert(object->kind == LinuxObjectKind_ConditionVariable);
|
||||||
pthread_cond_destroy(&object->condition_variable);
|
pthread_cond_destroy(&object->condition_variable);
|
||||||
linux_free_object(object);
|
linux_free_object(object);
|
||||||
|
@ -559,7 +612,7 @@ system_memory_allocate(u64 size, String_Const_u8 location){
|
||||||
void* result = mmap(
|
void* result = mmap(
|
||||||
NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
// TODO(andrew): Allocation tracking?
|
// TODO(andrew): Allocation tracking?
|
||||||
LINUX_FN_DEBUG("%" PRIu64 ", %.*s %p", size, (int)location.size, location.str, result);
|
//LINUX_FN_DEBUG("%" PRIu64 ", %.*s %p", size, (int)location.size, location.str, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,7 +629,7 @@ system_memory_set_protection(void* ptr, u64 size, u32 flags){
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
system_memory_free(void* ptr, u64 size){
|
system_memory_free(void* ptr, u64 size){
|
||||||
LINUX_FN_DEBUG("%p / %ld", ptr, size);
|
//LINUX_FN_DEBUG("%p / %ld", ptr, size);
|
||||||
munmap(ptr, size);
|
munmap(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,21 +653,38 @@ system_show_mouse_cursor(i32 show){
|
||||||
|
|
||||||
internal b32
|
internal b32
|
||||||
system_set_fullscreen(b32 full_screen){
|
system_set_fullscreen(b32 full_screen){
|
||||||
LINUX_FN_DEBUG("%d", full_screen);
|
linux_set_wm_state(linuxvars.atom__NET_WM_STATE_FULLSCREEN, 0, full_screen);
|
||||||
|
|
||||||
linuxvars.should_be_full_screen = full_screen;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal b32
|
internal b32
|
||||||
system_is_fullscreen(void){
|
system_is_fullscreen(void){
|
||||||
LINUX_FN_DEBUG();
|
b32 result = 0;
|
||||||
return linuxvars.is_full_screen;
|
|
||||||
|
// NOTE(inso): This will get the "true" state of fullscreen,
|
||||||
|
// even if it was toggled outside of 4coder.
|
||||||
|
// (e.g. super-F11 on some WMs sets fullscreen for any window/program)
|
||||||
|
|
||||||
|
Atom type, *prop;
|
||||||
|
unsigned long nitems, pad;
|
||||||
|
int fmt;
|
||||||
|
int ret = XGetWindowProperty(linuxvars.dpy,
|
||||||
|
linuxvars.win,
|
||||||
|
linuxvars.atom__NET_WM_STATE,
|
||||||
|
0, 32, False, XA_ATOM,
|
||||||
|
&type, &fmt, &nitems, &pad,
|
||||||
|
(unsigned char**)&prop);
|
||||||
|
|
||||||
|
if(ret == Success && prop){
|
||||||
|
result = *prop == linuxvars.atom__NET_WM_STATE_FULLSCREEN;
|
||||||
|
XFree((unsigned char*)prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Input_Modifier_Set
|
internal Input_Modifier_Set
|
||||||
system_get_keyboard_modifiers(Arena* arena){
|
system_get_keyboard_modifiers(Arena* arena){
|
||||||
LINUX_FN_DEBUG();
|
LINUX_FN_DEBUG();
|
||||||
// TODO:
|
return(copy_modifier_set(arena, &linuxvars.input.pers.modifiers));
|
||||||
//return(copy_modifier_set(arena, &linuxvars.input_chunk.pers.modifiers));
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue