fix linux input handling, implement more stuff

it seems to occasionally crash and might be leaking memory currently...
This commit is contained in:
Alex Baines 2020-02-08 15:25:15 +00:00
parent 56f5d78fa2
commit 61ddb8a9d1
2 changed files with 291 additions and 93 deletions

View File

@ -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,18 +344,39 @@ 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){
struct itimerspec its = {}; u64 ev = 1;
timerfd_gettime(linuxvars.step_timer_fd, &its); write(linuxvars.step_event_fd, &ev, sizeof(ev));
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;
}
timerfd_settime(linuxvars.step_timer_fd, 0, &its, NULL);
} }
else{
struct itimerspec its = {};
timerfd_gettime(linuxvars.step_timer_fd, &its);
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0){
its.it_value.tv_nsec = (frame_useconds - diff) * 1000UL;
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
@ -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

View File

@ -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,17 +142,28 @@ system_get_file_list(Arena* arena, String_Const_u8 directory){
} }
closedir(dir); closedir(dir);
result.infos = fip = push_array(arena, File_Info*, result.count); if(result.count > 0) {
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);
for(u32 i = 0; i < result.count - 1; ++i) {
result.infos[i]->next = result.infos[i+1];
}
result.infos[result.count-1]->next = NULL;
*/
} }
qsort(result.infos, result.count, sizeof(File_Info*), (__compar_fn_t)&linux_compare_file_infos);
// TODO: relink in new order?
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));
} }