Merge branch 'master' of https://bitbucket.org/4coder/4coder
commit
8ed3faeea8
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@ CPP_FILES := $(wildcard *.cpp) $(wildcard **/*.cpp)
|
|||
H_FILES := $(wildcard *.h) $(wildcard **/*.h)
|
||||
WARNINGS := -Wno-write-strings
|
||||
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
|
||||
|
||||
|
|
280
linux_4ed.cpp
280
linux_4ed.cpp
|
@ -1292,7 +1292,7 @@ LinuxResizeTarget(i32 width, i32 height){
|
|||
|
||||
// NOTE(allen): Thanks to Casey for providing the linux OpenGL launcher.
|
||||
static bool ctxErrorOccurred = false;
|
||||
static int XInput2OpCode = 0;
|
||||
|
||||
internal int
|
||||
ctxErrorHandler( Display *dpy, XErrorEvent *ev )
|
||||
{
|
||||
|
@ -1309,7 +1309,7 @@ static void gl_log(
|
|||
GLsizei length,
|
||||
const GLchar* message,
|
||||
const void* userParam
|
||||
){
|
||||
){
|
||||
fprintf(stderr, "GL DEBUG: %s\n", message);
|
||||
}
|
||||
#endif
|
||||
|
@ -1320,20 +1320,25 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
IsLegacy = false;
|
||||
|
||||
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));
|
||||
|
||||
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
|
||||
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
|
||||
glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
|
||||
#define GLXLOAD(x) x ## Proc x = (x ## Proc) glXGetProcAddressARB( (const GLubyte*) #x);
|
||||
|
||||
GLXLOAD(glXCreateContextAttribsARB);
|
||||
|
||||
GLXContext ctx = 0;
|
||||
ctxErrorOccurred = false;
|
||||
int (*oldHandler)(Display*, XErrorEvent*) =
|
||||
XSetErrorHandler(&ctxErrorHandler);
|
||||
int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
|
||||
|
||||
if (!glXCreateContextAttribsARB)
|
||||
{
|
||||
fprintf(stderr, "glXCreateContextAttribsARB() not found"
|
||||
" ... using old-style GLX context\n" );
|
||||
fprintf(stderr, "glXCreateContextAttribsARB() not found, using old-style GLX context\n" );
|
||||
ctx = glXCreateNewContext( XDisplay, bestFbc, GLX_RGBA_TYPE, 0, True );
|
||||
}
|
||||
else
|
||||
|
@ -1356,12 +1361,11 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
context_attribs[3],
|
||||
context_attribs[4]);
|
||||
|
||||
fprintf(stderr, "Creating context\n" );
|
||||
ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0,
|
||||
True, context_attribs );
|
||||
fprintf(stderr, "Creating context\n");
|
||||
ctx = glXCreateContextAttribsARB(XDisplay, bestFbc, 0, True, context_attribs);
|
||||
|
||||
XSync( XDisplay, False );
|
||||
if ( !ctxErrorOccurred && ctx )
|
||||
if (!ctxErrorOccurred && ctx)
|
||||
{
|
||||
fprintf(stderr, "Created GL 4.3 context\n" );
|
||||
}
|
||||
|
@ -1373,12 +1377,11 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
context_attribs[3] = 2;
|
||||
|
||||
fprintf(stderr, "Creating context\n" );
|
||||
ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0,
|
||||
True, context_attribs );
|
||||
ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0, True, context_attribs );
|
||||
|
||||
XSync( XDisplay, False );
|
||||
XSync(XDisplay, False);
|
||||
|
||||
if ( !ctxErrorOccurred && ctx )
|
||||
if (!ctxErrorOccurred && ctx)
|
||||
{
|
||||
fprintf(stderr, "Created GL 3.2 context\n" );
|
||||
}
|
||||
|
@ -1389,38 +1392,35 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
|
||||
ctxErrorOccurred = false;
|
||||
|
||||
fprintf(stderr, "Failed to create GL 3.2 context"
|
||||
" ... using old-style GLX context\n" );
|
||||
ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0,
|
||||
True, context_attribs );
|
||||
fprintf(stderr, "Failed to create GL 3.2 context, using old-style GLX context\n");
|
||||
ctx = glXCreateContextAttribsARB(XDisplay, bestFbc, 0, True, context_attribs);
|
||||
|
||||
IsLegacy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XSync( XDisplay, False );
|
||||
XSetErrorHandler( oldHandler );
|
||||
XSync(XDisplay, False);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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 );
|
||||
|
||||
GLint n;
|
||||
char *Vendor = (char *)glGetString(GL_VENDOR);
|
||||
char *Renderer = (char *)glGetString(GL_RENDERER);
|
||||
char *Version = (char *)glGetString(GL_VERSION);
|
||||
|
@ -1435,28 +1435,29 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
|
||||
//NOTE(inso): enable vsync if available. this should probably be optional
|
||||
if(strstr(glxExts, "GLX_EXT_swap_control ")){
|
||||
PFNGLXSWAPINTERVALEXTPROC glx_swap_interval_ext =
|
||||
(PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
|
||||
|
||||
if(glx_swap_interval_ext){
|
||||
glx_swap_interval_ext(XDisplay, XWindow, 1);
|
||||
GLXLOAD(glXSwapIntervalEXT);
|
||||
|
||||
if(glXSwapIntervalEXT){
|
||||
glXSwapIntervalEXT(XDisplay, XWindow, 1);
|
||||
|
||||
unsigned int swap_val = 0;
|
||||
glXQueryDrawable(XDisplay, XWindow, GLX_SWAP_INTERVAL_EXT, &swap_val);
|
||||
|
||||
linuxvars.vsync = swap_val == 1;
|
||||
fprintf(stderr, "VSync enabled? %s.\n", linuxvars.vsync ? "Yes" : "No");
|
||||
}
|
||||
|
||||
} else if(strstr(glxExts, "GLX_MESA_swap_control ")){
|
||||
PFNGLXSWAPINTERVALMESAPROC glx_swap_interval_mesa =
|
||||
(PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalMESA");
|
||||
|
||||
PFNGLXGETSWAPINTERVALMESAPROC glx_get_swap_interval_mesa =
|
||||
(PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB((const GLubyte*)"glXGetSwapIntervalMESA");
|
||||
GLXLOAD(glXSwapIntervalMESA);
|
||||
GLXLOAD(glXGetSwapIntervalMESA);
|
||||
|
||||
if(glx_swap_interval_mesa){
|
||||
glx_swap_interval_mesa(1);
|
||||
if(glx_get_swap_interval_mesa){
|
||||
linuxvars.vsync = glx_get_swap_interval_mesa();
|
||||
if(glXSwapIntervalMESA){
|
||||
glXSwapIntervalMESA(1);
|
||||
|
||||
if(glXGetSwapIntervalMESA){
|
||||
linuxvars.vsync = glXGetSwapIntervalMESA();
|
||||
fprintf(stderr, "VSync enabled? %s (MESA)\n", linuxvars.vsync ? "Yes" : "No");
|
||||
} else {
|
||||
// NOTE(inso): assume it worked?
|
||||
|
@ -1464,25 +1465,31 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
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){
|
||||
glx_swap_interval_sgi(1);
|
||||
} else if(strstr(glxExts, "GLX_SGI_swap_control ")){
|
||||
|
||||
GLXLOAD(glXSwapIntervalSGI);
|
||||
|
||||
if(glXSwapIntervalSGI){
|
||||
glXSwapIntervalSGI(1);
|
||||
|
||||
//NOTE(inso): The SGI one doesn't seem to have a way to confirm we got it...
|
||||
linuxvars.vsync = 1;
|
||||
fputs("VSync enabled? hopefully (SGI)", stderr);
|
||||
}
|
||||
|
||||
} else {
|
||||
fputs("VSync enabled? nope, no suitable extension", stderr);
|
||||
}
|
||||
|
||||
#if FRED_INTERNAL
|
||||
PFNGLDEBUGMESSAGECALLBACKARBPROC gl_dbg_callback = (PFNGLDEBUGMESSAGECALLBACKARBPROC)glXGetProcAddress((const GLubyte*)"glDebugMessageCallback");
|
||||
if(gl_dbg_callback){
|
||||
typedef PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackProc;
|
||||
|
||||
GLXLOAD(glDebugMessageCallback);
|
||||
|
||||
if(glDebugMessageCallback){
|
||||
fputs("enabling gl debug\n", stderr);
|
||||
gl_dbg_callback(&gl_log, 0);
|
||||
glDebugMessageCallback(&gl_log, 0);
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
}
|
||||
#endif
|
||||
|
@ -1492,6 +1499,8 @@ InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc,
|
|||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
#undef GLXLOAD
|
||||
|
||||
return(ctx);
|
||||
}
|
||||
|
||||
|
@ -1507,8 +1516,7 @@ GLXCanUseFBConfig(Display *XDisplay)
|
|||
if(glXQueryVersion(XDisplay, &GLXMajor, &GLXMinor))
|
||||
{
|
||||
fprintf(stderr, "GLX version %d.%d\n", GLXMajor, GLXMinor);
|
||||
if(((GLXMajor == 1 ) && (GLXMinor >= 3)) ||
|
||||
(GLXMajor > 1))
|
||||
if(((GLXMajor == 1 ) && (GLXMinor >= 3)) || (GLXMajor > 1))
|
||||
{
|
||||
Result = true;
|
||||
}
|
||||
|
@ -1572,15 +1580,61 @@ internal Init_Input_Result
|
|||
InitializeXInput(Display *dpy, Window XWindow)
|
||||
{
|
||||
Init_Input_Result result = {};
|
||||
XIMStyle style;
|
||||
XIMStyles *styles = 0;
|
||||
i32 i, count;
|
||||
XIMStyle style;
|
||||
unsigned long xim_event_mask = 0;
|
||||
i32 i;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
XSetLocaleModifiers("");
|
||||
fprintf(stderr, "Supported locale?: %s.\n", XSupportsLocale() ? "Yes" : "No");
|
||||
// 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(
|
||||
linuxvars.XDisplay,
|
||||
linuxvars.XWindow,
|
||||
|
@ -1593,53 +1647,10 @@ InitializeXInput(Display *dpy, Window XWindow)
|
|||
StructureNotifyMask |
|
||||
MappingNotify |
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1761,43 +1772,65 @@ LinuxHandleX11Events(void)
|
|||
if(Event.xkey.state & ControlMask) mods[MDFR_CONTROL_INDEX] = 1;
|
||||
if(Event.xkey.state & LockMask) mods[MDFR_CAPS_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;
|
||||
|
||||
KeySym keysym = NoSymbol;
|
||||
char buff[32], no_caps_buff[32];
|
||||
|
||||
// NOTE(inso): Turn ControlMask off like the win32 code does.
|
||||
if(mods[MDFR_CONTROL_INDEX] && !mods[MDFR_ALT_INDEX]){
|
||||
Event.xkey.state &= ~(ControlMask);
|
||||
|
||||
Status status;
|
||||
KeySym keysym = NoSymbol;
|
||||
char buff[32] = {};
|
||||
|
||||
Xutf8LookupString(
|
||||
linuxvars.input_context,
|
||||
&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
|
||||
XLookupString(&Event.xkey, buff, sizeof(buff), &keysym, NULL);
|
||||
u8 key = *buff, key_no_caps = key;
|
||||
|
||||
Event.xkey.state &= ~LockMask;
|
||||
XLookupString(&Event.xkey, no_caps_buff, sizeof(no_caps_buff), NULL, NULL);
|
||||
if(mods[MDFR_CAPS_INDEX] && status == XLookupBoth && Event.xkey.keycode){
|
||||
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){
|
||||
*buff = *no_caps_buff = '\t';
|
||||
key = key_no_caps = '\t';
|
||||
mods[MDFR_SHIFT_INDEX] = 1;
|
||||
}
|
||||
|
||||
u8 key = keycode_lookup(Event.xkey.keycode);
|
||||
u8 special_key = keycode_lookup(Event.xkey.keycode);
|
||||
|
||||
if(key){
|
||||
LinuxPushKey(key, 0, 0, &mods, is_hold);
|
||||
} else {
|
||||
key = buff[0] & 0xFF;
|
||||
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);
|
||||
if(special_key){
|
||||
LinuxPushKey(special_key, 0, 0, &mods, is_hold);
|
||||
} else if(key < 128){
|
||||
LinuxPushKey(key, key, key_no_caps, &mods, is_hold);
|
||||
} else {
|
||||
LinuxPushKey(0, 0, 0, &mods, is_hold);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
case KeyRelease: {
|
||||
|
@ -2594,12 +2627,9 @@ main(int argc, char **argv)
|
|||
linuxvars.mouse_data.wheel = 0;
|
||||
|
||||
File_Slot *file;
|
||||
int d = 0;
|
||||
|
||||
for (file = exchange_vars.file.active.next;
|
||||
file != &exchange_vars.file.active;
|
||||
file = file->next){
|
||||
++d;
|
||||
|
||||
if (file->flags & FEx_Save){
|
||||
Assert((file->flags & FEx_Request) == 0);
|
||||
|
|
Loading…
Reference in New Issue