linux timing, keyboard input & misc improvements
This commit is contained in:
parent
1f078aa96c
commit
44acf3eb26
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#define FPS 60
|
#define FPS 60
|
||||||
#define frame_useconds (1000000 / FPS)
|
#define frame_useconds (1000000 / FPS)
|
||||||
|
#define frame_nseconds (UINT64_C(1000000000) / FPS)
|
||||||
#define SLASH '/'
|
#define SLASH '/'
|
||||||
#define DLL "so"
|
#define DLL "so"
|
||||||
|
|
||||||
|
@ -121,7 +122,6 @@ struct Linux_Input_Chunk_Transient {
|
||||||
b8 mouse_l_release;
|
b8 mouse_l_release;
|
||||||
b8 mouse_r_press;
|
b8 mouse_r_press;
|
||||||
b8 mouse_r_release;
|
b8 mouse_r_release;
|
||||||
b8 out_of_window;
|
|
||||||
i8 mouse_wheel;
|
i8 mouse_wheel;
|
||||||
b8 trying_to_kill;
|
b8 trying_to_kill;
|
||||||
};
|
};
|
||||||
|
@ -131,6 +131,7 @@ struct Linux_Input_Chunk_Persistent {
|
||||||
Input_Modifier_Set_Fixed modifiers;
|
Input_Modifier_Set_Fixed modifiers;
|
||||||
b8 mouse_l;
|
b8 mouse_l;
|
||||||
b8 mouse_r;
|
b8 mouse_r;
|
||||||
|
b8 mouse_out_of_window;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Linux_Input_Chunk {
|
struct Linux_Input_Chunk {
|
||||||
|
@ -154,9 +155,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 step_pending;
|
||||||
|
|
||||||
XCursor xcursors[APP_MOUSE_CURSOR_COUNT];
|
XCursor xcursors[APP_MOUSE_CURSOR_COUNT];
|
||||||
Application_Mouse_Cursor cursor;
|
Application_Mouse_Cursor cursor;
|
||||||
|
@ -198,7 +199,6 @@ global Render_Target render_target;
|
||||||
|
|
||||||
typedef i32 Epoll_Kind;
|
typedef i32 Epoll_Kind;
|
||||||
enum {
|
enum {
|
||||||
EPOLL_STEP_EVENT,
|
|
||||||
EPOLL_STEP_TIMER,
|
EPOLL_STEP_TIMER,
|
||||||
EPOLL_X11,
|
EPOLL_X11,
|
||||||
EPOLL_X11_INTERNAL,
|
EPOLL_X11_INTERNAL,
|
||||||
|
@ -211,7 +211,6 @@ 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_step_event = EPOLL_STEP_EVENT;
|
|
||||||
internal Epoll_Kind epoll_tag_step_timer = EPOLL_STEP_TIMER;
|
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;
|
||||||
|
@ -322,8 +321,8 @@ linux_system_get_file_list_filter(const struct dirent *dirent) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int
|
internal u64
|
||||||
linux_u64_from_timespec(const struct timespec timespec) {
|
linux_ns_from_timespec(const struct timespec timespec) {
|
||||||
return timespec.tv_nsec + UINT64_C(1000000000) * timespec.tv_sec;
|
return timespec.tv_nsec + UINT64_C(1000000000) * timespec.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,34 +337,40 @@ internal File_Attributes
|
||||||
linux_file_attributes_from_struct_stat(struct stat* file_stat) {
|
linux_file_attributes_from_struct_stat(struct stat* file_stat) {
|
||||||
File_Attributes result = {};
|
File_Attributes result = {};
|
||||||
result.size = file_stat->st_size;
|
result.size = file_stat->st_size;
|
||||||
result.last_write_time = linux_u64_from_timespec(file_stat->st_mtim);
|
result.last_write_time = linux_ns_from_timespec(file_stat->st_mtim);
|
||||||
result.flags = linux_convert_file_attribute_flags(file_stat->st_mode);
|
result.flags = linux_convert_file_attribute_flags(file_stat->st_mode);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
linux_schedule_step(){
|
linux_schedule_step(){
|
||||||
|
if(!__sync_bool_compare_and_swap(&linuxvars.step_pending, 0, 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
struct itimerspec its = {};
|
||||||
write(linuxvars.step_event_fd, &ev, sizeof(ev));
|
|
||||||
}
|
if(diff >= frame_nseconds) {
|
||||||
else{
|
its.it_value.tv_nsec = 1;
|
||||||
struct itimerspec its = {};
|
} else {
|
||||||
timerfd_gettime(linuxvars.step_timer_fd, &its);
|
its.it_value.tv_nsec = frame_nseconds - diff;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timerfd_settime(linuxvars.step_timer_fd, 0, &its, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
enum wm_state_mode {
|
||||||
linux_set_wm_state(Atom one, Atom two, int mode){
|
WM_STATE_DEL = 0,
|
||||||
//NOTE(inso): this will only work after the window has been mapped
|
WM_STATE_ADD = 1,
|
||||||
|
WM_STATE_TOGGLE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
enum { STATE_REMOVE, STATE_ADD, STATE_TOGGLE };
|
internal void
|
||||||
|
linux_set_wm_state(Atom one, Atom two, enum wm_state_mode mode){
|
||||||
|
//NOTE(inso): this will only work after the window has been mapped
|
||||||
|
|
||||||
XEvent e = {};
|
XEvent e = {};
|
||||||
e.xany.type = ClientMessage;
|
e.xany.type = ClientMessage;
|
||||||
|
@ -382,6 +387,16 @@ linux_set_wm_state(Atom one, Atom two, int mode){
|
||||||
0, SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
0, SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
linux_window_maximize(enum wm_state_mode mode){
|
||||||
|
linux_set_wm_state(linuxvars.atom__NET_WM_STATE_MAXIMIZED_HORZ, linuxvars.atom__NET_WM_STATE_MAXIMIZED_VERT, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
linux_window_fullscreen(enum wm_state_mode mode) {
|
||||||
|
linux_set_wm_state(linuxvars.atom__NET_WM_STATE_FULLSCREEN, 0, mode);
|
||||||
|
}
|
||||||
|
|
||||||
internal int
|
internal int
|
||||||
linux_get_xsettings_dpi(Display* dpy, int screen){
|
linux_get_xsettings_dpi(Display* dpy, int screen){
|
||||||
struct XSettingHeader {
|
struct XSettingHeader {
|
||||||
|
@ -498,16 +513,6 @@ linux_thread_proc_start(void* arg) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
linux_window_maximize(b32 enable){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
linux_window_fullscreen_toggle(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "linux_icon.h"
|
#include "linux_icon.h"
|
||||||
internal void
|
internal void
|
||||||
linux_set_icon(Display* d, Window w){
|
linux_set_icon(Display* d, Window w){
|
||||||
|
@ -870,9 +875,9 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings->maximize_window){
|
if (settings->maximize_window){
|
||||||
linux_window_maximize(true);
|
linux_set_wm_state(linuxvars.atom__NET_WM_STATE_MAXIMIZED_HORZ, linuxvars.atom__NET_WM_STATE_MAXIMIZED_VERT, WM_STATE_ADD);
|
||||||
} else if (settings->fullscreen_window){
|
} else if (settings->fullscreen_window){
|
||||||
linux_window_fullscreen_toggle();
|
linux_set_wm_state(linuxvars.atom__NET_WM_STATE_FULLSCREEN, 0, WM_STATE_ADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
XSync(linuxvars.dpy, False);
|
XSync(linuxvars.dpy, False);
|
||||||
|
@ -1093,16 +1098,12 @@ linux_epoll_init(void) {
|
||||||
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_step_event;
|
|
||||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_event_fd, &e);
|
|
||||||
|
|
||||||
e.data.ptr = &epoll_tag_step_timer;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -1244,7 +1245,6 @@ linux_handle_x11_events() {
|
||||||
should_step = true;
|
should_step = true;
|
||||||
|
|
||||||
Input_Modifier_Set_Fixed* mods = &linuxvars.input.pers.modifiers;
|
Input_Modifier_Set_Fixed* mods = &linuxvars.input.pers.modifiers;
|
||||||
block_zero_struct(mods);
|
|
||||||
|
|
||||||
int state = event.xkey.state;
|
int state = event.xkey.state;
|
||||||
set_modifier(mods, KeyCode_Shift, state & ShiftMask);
|
set_modifier(mods, KeyCode_Shift, state & ShiftMask);
|
||||||
|
@ -1276,6 +1276,7 @@ linux_handle_x11_events() {
|
||||||
|
|
||||||
Input_Event* key_event = NULL;
|
Input_Event* key_event = NULL;
|
||||||
if(key) {
|
if(key) {
|
||||||
|
add_modifier(mods, key);
|
||||||
key_event = push_input_event(linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
key_event = push_input_event(linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
||||||
key_event->kind = InputEventKind_KeyStroke;
|
key_event->kind = InputEventKind_KeyStroke;
|
||||||
key_event->key.code = key;
|
key_event->key.code = key;
|
||||||
|
@ -1299,7 +1300,26 @@ linux_handle_x11_events() {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case KeyRelease: {
|
case KeyRelease: {
|
||||||
|
should_step = true;
|
||||||
|
|
||||||
|
Input_Modifier_Set_Fixed* mods = &linuxvars.input.pers.modifiers;
|
||||||
|
|
||||||
|
int state = event.xkey.state;
|
||||||
|
set_modifier(mods, KeyCode_Shift, state & ShiftMask);
|
||||||
|
set_modifier(mods, KeyCode_Control, state & ControlMask);
|
||||||
|
set_modifier(mods, KeyCode_CapsLock, state & LockMask);
|
||||||
|
set_modifier(mods, KeyCode_Alt, state & Mod1Mask);
|
||||||
|
|
||||||
|
Key_Code key = keycode_lookup_table[(u8)event.xkey.keycode];
|
||||||
|
|
||||||
|
Input_Event* key_event = NULL;
|
||||||
|
if(key) {
|
||||||
|
remove_modifier(mods, key);
|
||||||
|
key_event = push_input_event(linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
||||||
|
key_event->kind = InputEventKind_KeyRelease;
|
||||||
|
key_event->key.code = key;
|
||||||
|
key_event->key.modifiers = copy_modifier_set(linuxvars.frame_arena, mods);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MotionNotify: {
|
case MotionNotify: {
|
||||||
|
@ -1352,12 +1372,19 @@ linux_handle_x11_events() {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case FocusIn: {
|
case FocusIn:
|
||||||
XSetICFocus(linuxvars.xic);
|
case FocusOut: {
|
||||||
|
linuxvars.input.pers.mouse_l = false;
|
||||||
|
linuxvars.input.pers.mouse_r = false;
|
||||||
|
block_zero_struct(&linuxvars.input.pers.modifiers);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case FocusOut: {
|
case EnterNotify: {
|
||||||
XUnsetICFocus(linuxvars.xic);
|
linuxvars.input.pers.mouse_out_of_window = 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case LeaveNotify: {
|
||||||
|
linuxvars.input.pers.mouse_out_of_window = 1;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case ConfigureNotify: {
|
case ConfigureNotify: {
|
||||||
|
@ -1453,15 +1480,6 @@ linux_epoll_process(struct epoll_event* events, int num_events) {
|
||||||
//XProcessInternalConnection(linuxvars.dpy, fd);
|
//XProcessInternalConnection(linuxvars.dpy, fd);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
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: {
|
case EPOLL_STEP_TIMER: {
|
||||||
u64 count;
|
u64 count;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1479,7 +1497,7 @@ linux_epoll_process(struct epoll_event* events, int num_events) {
|
||||||
Linux_Object* obj = CastFromMember(Linux_Object, timer.epoll_tag, tag);
|
Linux_Object* obj = CastFromMember(Linux_Object, timer.epoll_tag, tag);
|
||||||
close(obj->timer.fd);
|
close(obj->timer.fd);
|
||||||
obj->timer.fd = -1;
|
obj->timer.fd = -1;
|
||||||
do_step = true;
|
linux_schedule_step();
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1674,9 +1692,7 @@ main(int argc, char **argv){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 now = system_now_time();
|
linuxvars.last_step_time = 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.
|
||||||
|
@ -1697,7 +1713,7 @@ main(int argc, char **argv){
|
||||||
input.events = linuxvars.input.trans.event_list;
|
input.events = linuxvars.input.trans.event_list;
|
||||||
input.trying_to_kill = linuxvars.input.trans.trying_to_kill;
|
input.trying_to_kill = linuxvars.input.trans.trying_to_kill;
|
||||||
|
|
||||||
input.mouse.out_of_window = false;
|
input.mouse.out_of_window = linuxvars.input.pers.mouse_out_of_window;
|
||||||
input.mouse.p = linuxvars.input.pers.mouse;
|
input.mouse.p = linuxvars.input.pers.mouse;
|
||||||
input.mouse.l = linuxvars.input.pers.mouse_l;
|
input.mouse.l = linuxvars.input.pers.mouse_l;
|
||||||
input.mouse.r = linuxvars.input.pers.mouse_r;
|
input.mouse.r = linuxvars.input.pers.mouse_r;
|
||||||
|
@ -1739,6 +1755,7 @@ main(int argc, char **argv){
|
||||||
|
|
||||||
linalloc_clear(linuxvars.frame_arena);
|
linalloc_clear(linuxvars.frame_arena);
|
||||||
block_zero_struct(&linuxvars.input.trans);
|
block_zero_struct(&linuxvars.input.trans);
|
||||||
|
linuxvars.step_pending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -256,7 +256,7 @@ 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_ns_from_timespec(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Plat_Handle
|
internal Plat_Handle
|
||||||
|
@ -275,7 +275,6 @@ system_wake_up_timer_release(Plat_Handle handle){
|
||||||
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) {
|
||||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_DEL, object->timer.fd, NULL);
|
|
||||||
close(object->timer.fd);
|
close(object->timer.fd);
|
||||||
object->timer.fd = -1;
|
object->timer.fd = -1;
|
||||||
}
|
}
|
||||||
|
@ -432,9 +431,6 @@ system_cli_end_update(CLI_Handles* cli){
|
||||||
close_me = true;
|
close_me = true;
|
||||||
close(*(int*)&cli->out_read);
|
close(*(int*)&cli->out_read);
|
||||||
close(*(int*)&cli->out_write);
|
close(*(int*)&cli->out_write);
|
||||||
|
|
||||||
struct epoll_event e = {};
|
|
||||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_DEL, *(int*)&cli->out_read, &e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(close_me);
|
return(close_me);
|
||||||
|
@ -651,7 +647,7 @@ system_show_mouse_cursor(i32 show){
|
||||||
|
|
||||||
internal b32
|
internal b32
|
||||||
system_set_fullscreen(b32 full_screen){
|
system_set_fullscreen(b32 full_screen){
|
||||||
linux_set_wm_state(linuxvars.atom__NET_WM_STATE_FULLSCREEN, 0, full_screen);
|
linux_window_fullscreen(full_screen ? WM_STATE_ADD : WM_STATE_DEL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue