This commit is contained in:
Allen Webster 2016-05-10 13:37:04 -04:00
commit 8ed3faeea8
2 changed files with 183 additions and 153 deletions

View File

@ -2,7 +2,7 @@ CPP_FILES := $(wildcard *.cpp) $(wildcard **/*.cpp)
H_FILES := $(wildcard *.h) $(wildcard **/*.h) H_FILES := $(wildcard *.h) $(wildcard **/*.h)
WARNINGS := -Wno-write-strings WARNINGS := -Wno-write-strings
PLAT_LINKS := -L/usr/local/lib -lX11 -lpthread -lm -lrt -lGL -ldl -lXfixes PLAT_LINKS := -L/usr/local/lib -lX11 -lpthread -lm -lrt -lGL -ldl -lXfixes
FLAGS := -fPIC -fno-threadsafe-statics -pthread -I../foreign -g FLAGS := -fPIC -fno-threadsafe-statics -pthread -I../foreign -g -O0
all: ../4ed_app.so ../4ed all: ../4ed_app.so ../4ed

View File

@ -1292,7 +1292,7 @@ LinuxResizeTarget(i32 width, i32 height){
// NOTE(allen): Thanks to Casey for providing the linux OpenGL launcher. // NOTE(allen): Thanks to Casey for providing the linux OpenGL launcher.
static bool ctxErrorOccurred = false; static bool ctxErrorOccurred = false;
static int XInput2OpCode = 0;
internal int internal int
ctxErrorHandler( Display *dpy, XErrorEvent *ev ) ctxErrorHandler( Display *dpy, XErrorEvent *ev )
{ {
@ -1309,7 +1309,7 @@ static void gl_log(
GLsizei length, GLsizei length,
const GLchar* message, const GLchar* message,
const void* userParam const void* userParam
){ ){
fprintf(stderr, "GL DEBUG: %s\n", message); fprintf(stderr, "GL DEBUG: %s\n", message);
} }
#endif #endif
@ -1320,48 +1320,52 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
IsLegacy = false; IsLegacy = false;
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
typedef PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXTProc;
typedef PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESAProc;
typedef PFNGLXGETSWAPINTERVALMESAPROC glXGetSwapIntervalMESAProc;
typedef PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGIProc;
const char *glxExts = glXQueryExtensionsString(XDisplay, DefaultScreen(XDisplay)); const char *glxExts = glXQueryExtensionsString(XDisplay, DefaultScreen(XDisplay));
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; #define GLXLOAD(x) x ## Proc x = (x ## Proc) glXGetProcAddressARB( (const GLubyte*) #x);
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); GLXLOAD(glXCreateContextAttribsARB);
GLXContext ctx = 0; GLXContext ctx = 0;
ctxErrorOccurred = false; ctxErrorOccurred = false;
int (*oldHandler)(Display*, XErrorEvent*) = int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
XSetErrorHandler(&ctxErrorHandler);
if (!glXCreateContextAttribsARB) if (!glXCreateContextAttribsARB)
{ {
fprintf(stderr, "glXCreateContextAttribsARB() not found" fprintf(stderr, "glXCreateContextAttribsARB() not found, using old-style GLX context\n" );
" ... using old-style GLX context\n" );
ctx = glXCreateNewContext( XDisplay, bestFbc, GLX_RGBA_TYPE, 0, True ); ctx = glXCreateNewContext( XDisplay, bestFbc, GLX_RGBA_TYPE, 0, True );
} }
else else
{ {
int context_attribs[] = int context_attribs[] =
{ {
GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
#if FRED_INTERNAL #if FRED_INTERNAL
GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_DEBUG_BIT_ARB, GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_DEBUG_BIT_ARB,
#endif #endif
None None
}; };
fprintf(stderr, "Attribs: %d %d %d %d %d\n", fprintf(stderr, "Attribs: %d %d %d %d %d\n",
context_attribs[0], context_attribs[0],
context_attribs[1], context_attribs[1],
context_attribs[2], context_attribs[2],
context_attribs[3], context_attribs[3],
context_attribs[4]); context_attribs[4]);
fprintf(stderr, "Creating context\n" ); fprintf(stderr, "Creating context\n");
ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0, ctx = glXCreateContextAttribsARB(XDisplay, bestFbc, 0, True, context_attribs);
True, context_attribs );
XSync( XDisplay, False ); XSync( XDisplay, False );
if ( !ctxErrorOccurred && ctx ) if (!ctxErrorOccurred && ctx)
{ {
fprintf(stderr, "Created GL 4.3 context\n" ); fprintf(stderr, "Created GL 4.3 context\n" );
} }
@ -1373,12 +1377,11 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
context_attribs[3] = 2; context_attribs[3] = 2;
fprintf(stderr, "Creating context\n" ); fprintf(stderr, "Creating context\n" );
ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0, ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0, True, context_attribs );
True, context_attribs );
XSync( XDisplay, False ); XSync(XDisplay, False);
if ( !ctxErrorOccurred && ctx ) if (!ctxErrorOccurred && ctx)
{ {
fprintf(stderr, "Created GL 3.2 context\n" ); fprintf(stderr, "Created GL 3.2 context\n" );
} }
@ -1389,41 +1392,38 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
ctxErrorOccurred = false; ctxErrorOccurred = false;
fprintf(stderr, "Failed to create GL 3.2 context" fprintf(stderr, "Failed to create GL 3.2 context, using old-style GLX context\n");
" ... using old-style GLX context\n" ); ctx = glXCreateContextAttribsARB(XDisplay, bestFbc, 0, True, context_attribs);
ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0,
True, context_attribs );
IsLegacy = true; IsLegacy = true;
} }
} }
} }
XSync( XDisplay, False ); XSync(XDisplay, False);
XSetErrorHandler( oldHandler ); XSetErrorHandler(oldHandler);
if ( ctxErrorOccurred || !ctx ) if (ctxErrorOccurred || !ctx)
{ {
fprintf(stderr, "Failed to create an OpenGL context\n" ); fprintf(stderr, "Failed to create an OpenGL context\n");
exit(1); exit(1);
} }
if ( ! glXIsDirect ( XDisplay, ctx ) ) if (!glXIsDirect(XDisplay, ctx))
{ {
fprintf(stderr, "Indirect GLX rendering context obtained\n" ); fprintf(stderr, "Indirect GLX rendering context obtained\n");
} }
else else
{ {
fprintf(stderr, "Direct GLX rendering context obtained\n" ); fprintf(stderr, "Direct GLX rendering context obtained\n");
} }
fprintf(stderr, "Making context current\n" ); fprintf(stderr, "Making context current\n");
glXMakeCurrent( XDisplay, XWindow, ctx ); glXMakeCurrent( XDisplay, XWindow, ctx );
GLint n; char *Vendor = (char *)glGetString(GL_VENDOR);
char *Vendor = (char *)glGetString(GL_VENDOR);
char *Renderer = (char *)glGetString(GL_RENDERER); char *Renderer = (char *)glGetString(GL_RENDERER);
char *Version = (char *)glGetString(GL_VERSION); char *Version = (char *)glGetString(GL_VERSION);
//TODO(inso): glGetStringi is required in core profile if the GL version is >= 3.0 //TODO(inso): glGetStringi is required in core profile if the GL version is >= 3.0
char *Extensions = (char *)glGetString(GL_EXTENSIONS); char *Extensions = (char *)glGetString(GL_EXTENSIONS);
@ -1431,32 +1431,33 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
fprintf(stderr, "GL_VENDOR: %s\n", Vendor); fprintf(stderr, "GL_VENDOR: %s\n", Vendor);
fprintf(stderr, "GL_RENDERER: %s\n", Renderer); fprintf(stderr, "GL_RENDERER: %s\n", Renderer);
fprintf(stderr, "GL_VERSION: %s\n", Version); fprintf(stderr, "GL_VERSION: %s\n", Version);
// fprintf(stderr, "GL_EXTENSIONS: %s\n", Extensions); // fprintf(stderr, "GL_EXTENSIONS: %s\n", Extensions);
//NOTE(inso): enable vsync if available. this should probably be optional //NOTE(inso): enable vsync if available. this should probably be optional
if(strstr(glxExts, "GLX_EXT_swap_control ")){ if(strstr(glxExts, "GLX_EXT_swap_control ")){
PFNGLXSWAPINTERVALEXTPROC glx_swap_interval_ext =
(PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
if(glx_swap_interval_ext){ GLXLOAD(glXSwapIntervalEXT);
glx_swap_interval_ext(XDisplay, XWindow, 1);
if(glXSwapIntervalEXT){
glXSwapIntervalEXT(XDisplay, XWindow, 1);
unsigned int swap_val = 0; unsigned int swap_val = 0;
glXQueryDrawable(XDisplay, XWindow, GLX_SWAP_INTERVAL_EXT, &swap_val); glXQueryDrawable(XDisplay, XWindow, GLX_SWAP_INTERVAL_EXT, &swap_val);
linuxvars.vsync = swap_val == 1; linuxvars.vsync = swap_val == 1;
fprintf(stderr, "VSync enabled? %s.\n", linuxvars.vsync ? "Yes" : "No"); fprintf(stderr, "VSync enabled? %s.\n", linuxvars.vsync ? "Yes" : "No");
} }
} else if(strstr(glxExts, "GLX_MESA_swap_control ")){ } else if(strstr(glxExts, "GLX_MESA_swap_control ")){
PFNGLXSWAPINTERVALMESAPROC glx_swap_interval_mesa =
(PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalMESA");
PFNGLXGETSWAPINTERVALMESAPROC glx_get_swap_interval_mesa = GLXLOAD(glXSwapIntervalMESA);
(PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB((const GLubyte*)"glXGetSwapIntervalMESA"); GLXLOAD(glXGetSwapIntervalMESA);
if(glx_swap_interval_mesa){ if(glXSwapIntervalMESA){
glx_swap_interval_mesa(1); glXSwapIntervalMESA(1);
if(glx_get_swap_interval_mesa){
linuxvars.vsync = glx_get_swap_interval_mesa(); if(glXGetSwapIntervalMESA){
linuxvars.vsync = glXGetSwapIntervalMESA();
fprintf(stderr, "VSync enabled? %s (MESA)\n", linuxvars.vsync ? "Yes" : "No"); fprintf(stderr, "VSync enabled? %s (MESA)\n", linuxvars.vsync ? "Yes" : "No");
} else { } else {
// NOTE(inso): assume it worked? // NOTE(inso): assume it worked?
@ -1464,25 +1465,31 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
fputs("VSync enabled? possibly (MESA)", stderr); fputs("VSync enabled? possibly (MESA)", stderr);
} }
} }
} else if(strstr(glxExts, "GLX_SGI_swap_control ")){
PFNGLXSWAPINTERVALSGIPROC glx_swap_interval_sgi =
(PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalSGI");
if(glx_swap_interval_sgi){ } else if(strstr(glxExts, "GLX_SGI_swap_control ")){
glx_swap_interval_sgi(1);
GLXLOAD(glXSwapIntervalSGI);
if(glXSwapIntervalSGI){
glXSwapIntervalSGI(1);
//NOTE(inso): The SGI one doesn't seem to have a way to confirm we got it... //NOTE(inso): The SGI one doesn't seem to have a way to confirm we got it...
linuxvars.vsync = 1; linuxvars.vsync = 1;
fputs("VSync enabled? hopefully (SGI)", stderr); fputs("VSync enabled? hopefully (SGI)", stderr);
} }
} else { } else {
fputs("VSync enabled? nope, no suitable extension", stderr); fputs("VSync enabled? nope, no suitable extension", stderr);
} }
#if FRED_INTERNAL #if FRED_INTERNAL
PFNGLDEBUGMESSAGECALLBACKARBPROC gl_dbg_callback = (PFNGLDEBUGMESSAGECALLBACKARBPROC)glXGetProcAddress((const GLubyte*)"glDebugMessageCallback"); typedef PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackProc;
if(gl_dbg_callback){
GLXLOAD(glDebugMessageCallback);
if(glDebugMessageCallback){
fputs("enabling gl debug\n", stderr); fputs("enabling gl debug\n", stderr);
gl_dbg_callback(&gl_log, 0); glDebugMessageCallback(&gl_log, 0);
glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT);
} }
#endif #endif
@ -1492,6 +1499,8 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#undef GLXLOAD
return(ctx); return(ctx);
} }
@ -1507,8 +1516,7 @@ GLXCanUseFBConfig(Display *XDisplay)
if(glXQueryVersion(XDisplay, &GLXMajor, &GLXMinor)) if(glXQueryVersion(XDisplay, &GLXMajor, &GLXMinor))
{ {
fprintf(stderr, "GLX version %d.%d\n", GLXMajor, GLXMinor); fprintf(stderr, "GLX version %d.%d\n", GLXMajor, GLXMinor);
if(((GLXMajor == 1 ) && (GLXMinor >= 3)) || if(((GLXMajor == 1 ) && (GLXMinor >= 3)) || (GLXMajor > 1))
(GLXMajor > 1))
{ {
Result = true; Result = true;
} }
@ -1572,15 +1580,61 @@ internal Init_Input_Result
InitializeXInput(Display *dpy, Window XWindow) InitializeXInput(Display *dpy, Window XWindow)
{ {
Init_Input_Result result = {}; Init_Input_Result result = {};
XIMStyle style;
XIMStyles *styles = 0; XIMStyles *styles = 0;
i32 i, count; XIMStyle style;
unsigned long xim_event_mask = 0;
i32 i;
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
XSetLocaleModifiers(""); XSetLocaleModifiers("");
fprintf(stderr, "Supported locale?: %s.\n", XSupportsLocale() ? "Yes" : "No"); fprintf(stderr, "Supported locale?: %s.\n", XSupportsLocale() ? "Yes" : "No");
// TODO(inso): handle the case where it isn't supported somehow? // TODO(inso): handle the case where it isn't supported somehow?
result.input_method = XOpenIM(dpy, 0, 0, 0);
if (!result.input_method){
// NOTE(inso): Try falling back to the internal XIM implementation that
// should in theory always exist.
XSetLocaleModifiers("@im=none");
result.input_method = XOpenIM(dpy, 0, 0, 0);
}
if (result.input_method){
if (!XGetIMValues(result.input_method, XNQueryInputStyle, &styles, NULL) && styles){
for (i = 0; i < styles->count_styles; ++i){
style = styles->supported_styles[i];
if (style == (XIMPreeditNothing | XIMStatusNothing)){
result.best_style = style;
break;
}
}
}
if (result.best_style){
XFree(styles);
result.xic = XCreateIC(
result.input_method,
XNInputStyle, result.best_style,
XNClientWindow, XWindow,
XNFocusWindow, XWindow,
NULL
);
if (XGetICValues(result.xic, XNFilterEvents, &xim_event_mask, NULL)){
xim_event_mask = 0;
}
}
else{
result = {};
fputs("Could not get minimum required input style.\n", stderr);
}
}
else{
result = {};
fputs("Could not open X Input Method.\n", stderr);
}
XSelectInput( XSelectInput(
linuxvars.XDisplay, linuxvars.XDisplay,
linuxvars.XWindow, linuxvars.XWindow,
@ -1593,53 +1647,10 @@ InitializeXInput(Display *dpy, Window XWindow)
StructureNotifyMask | StructureNotifyMask |
MappingNotify | MappingNotify |
ExposureMask | ExposureMask |
VisibilityChangeMask VisibilityChangeMask |
xim_event_mask
); );
result.input_method = XOpenIM(dpy, 0, 0, 0);
if (!result.input_method){
// NOTE(inso): Try falling back to the internal XIM implementation that
// should in theory always exist.
XSetLocaleModifiers("@im=none");
result.input_method = XOpenIM(dpy, 0, 0, 0);
}
if (result.input_method){
if (!XGetIMValues(result.input_method, XNQueryInputStyle, &styles, NULL) &&
styles){
result.best_style = 0;
count = styles->count_styles;
for (i = 0; i < count; ++i){
style = styles->supported_styles[i];
if (style == (XIMPreeditNothing | XIMStatusNothing)){
result.best_style = style;
break;
}
}
if (result.best_style){
XFree(styles);
result.xic =
XCreateIC(result.input_method, XNInputStyle, result.best_style,
XNClientWindow, XWindow,
XNFocusWindow, XWindow,
0, 0,
NULL);
}
else{
result = {};
fputs("Could not get minimum required input style", stderr);
}
}
}
else{
result = {};
fputs("Could not open X Input Method", stderr);
}
return(result); return(result);
} }
@ -1699,18 +1710,18 @@ LinuxMaximizeWindow(Display* d, Window w, b32 maximize)
internal void internal void
LinuxSetIcon(Display* d, Window w) LinuxSetIcon(Display* d, Window w)
{ {
Atom WM_ICON = XInternAtom(d, "_NET_WM_ICON", False); Atom WM_ICON = XInternAtom(d, "_NET_WM_ICON", False);
XChangeProperty( XChangeProperty(
d, d,
w, w,
WM_ICON, WM_ICON,
XA_CARDINAL, XA_CARDINAL,
32, 32,
PropModeReplace, PropModeReplace,
(unsigned char*)linux_icon, (unsigned char*)linux_icon,
sizeof(linux_icon) / sizeof(long) sizeof(linux_icon) / sizeof(long)
); );
} }
internal void internal void
@ -1761,42 +1772,64 @@ LinuxHandleX11Events(void)
if(Event.xkey.state & ControlMask) mods[MDFR_CONTROL_INDEX] = 1; if(Event.xkey.state & ControlMask) mods[MDFR_CONTROL_INDEX] = 1;
if(Event.xkey.state & LockMask) mods[MDFR_CAPS_INDEX] = 1; if(Event.xkey.state & LockMask) mods[MDFR_CAPS_INDEX] = 1;
if(Event.xkey.state & Mod1Mask) mods[MDFR_ALT_INDEX] = 1; if(Event.xkey.state & Mod1Mask) mods[MDFR_ALT_INDEX] = 1;
// NOTE(inso): mod5 == AltGr
// if(Event.xkey.state & Mod5Mask) mods[MDFR_ALT_INDEX] = 1;
Event.xkey.state &= ~(ControlMask);
Status status;
KeySym keysym = NoSymbol; KeySym keysym = NoSymbol;
char buff[32], no_caps_buff[32]; char buff[32] = {};
// NOTE(inso): Turn ControlMask off like the win32 code does. Xutf8LookupString(
if(mods[MDFR_CONTROL_INDEX] && !mods[MDFR_ALT_INDEX]){ linuxvars.input_context,
Event.xkey.state &= ~(ControlMask); &Event.xkey,
buff,
sizeof(buff) - 1,
&keysym,
&status
);
if(status == XBufferOverflow){
//TODO(inso): handle properly
Xutf8ResetIC(linuxvars.input_context);
XSetICFocus(linuxvars.input_context);
fputs("FIXME: XBufferOverflow from LookupString.\n", stderr);
} }
// TODO(inso): Use one of the Xutf8LookupString funcs to allow for non-ascii chars u8 key = *buff, key_no_caps = key;
XLookupString(&Event.xkey, buff, sizeof(buff), &keysym, NULL);
Event.xkey.state &= ~LockMask; if(mods[MDFR_CAPS_INDEX] && status == XLookupBoth && Event.xkey.keycode){
XLookupString(&Event.xkey, no_caps_buff, sizeof(no_caps_buff), NULL, NULL); char buff_no_caps[32] = {};
Event.xkey.state &= ~(LockMask);
XLookupString(
&Event.xkey,
buff_no_caps,
sizeof(buff_no_caps) - 1,
NULL,
NULL
);
if(*buff_no_caps){
key_no_caps = *buff_no_caps;
}
}
if(key == '\r') key = '\n';
if(key_no_caps == '\r') key_no_caps = '\n';
if(keysym == XK_ISO_Left_Tab){ if(keysym == XK_ISO_Left_Tab){
*buff = *no_caps_buff = '\t'; key = key_no_caps = '\t';
mods[MDFR_SHIFT_INDEX] = 1; mods[MDFR_SHIFT_INDEX] = 1;
} }
u8 key = keycode_lookup(Event.xkey.keycode); u8 special_key = keycode_lookup(Event.xkey.keycode);
if(key){ if(special_key){
LinuxPushKey(key, 0, 0, &mods, is_hold); LinuxPushKey(special_key, 0, 0, &mods, is_hold);
} else if(key < 128){
LinuxPushKey(key, key, key_no_caps, &mods, is_hold);
} else { } else {
key = buff[0] & 0xFF; LinuxPushKey(0, 0, 0, &mods, is_hold);
if(key < 128){
u8 no_caps_key = no_caps_buff[0] & 0xFF;
if(key == '\r') key = '\n';
if(no_caps_key == '\r') no_caps_key = '\n';
LinuxPushKey(key, key, no_caps_key, &mods, is_hold);
} else {
LinuxPushKey(0, 0, 0, &mods, is_hold);
}
} }
}break; }break;
@ -2594,12 +2627,9 @@ main(int argc, char **argv)
linuxvars.mouse_data.wheel = 0; linuxvars.mouse_data.wheel = 0;
File_Slot *file; File_Slot *file;
int d = 0;
for (file = exchange_vars.file.active.next; for (file = exchange_vars.file.active.next;
file != &exchange_vars.file.active; file != &exchange_vars.file.active;
file = file->next){ file = file->next){
++d;
if (file->flags & FEx_Save){ if (file->flags & FEx_Save){
Assert((file->flags & FEx_Request) == 0); Assert((file->flags & FEx_Request) == 0);