Initial commit
This commit is contained in:
374
libsst-wm/Xlib/GLXPrivate.c
Normal file
374
libsst-wm/Xlib/GLXPrivate.c
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
GLXPrivate.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/11/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL on X Windows (GLX) utility code
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* GL constants */
|
||||
#define GL_VERSION 0x1F02
|
||||
|
||||
/* GLX constants */
|
||||
#define GLX_DOUBLEBUFFER 5
|
||||
#define GLX_STEREO 6
|
||||
#define GLX_AUX_BUFFERS 7
|
||||
#define GLX_RED_SIZE 8
|
||||
#define GLX_GREEN_SIZE 9
|
||||
#define GLX_BLUE_SIZE 10
|
||||
#define GLX_ALPHA_SIZE 11
|
||||
#define GLX_DEPTH_SIZE 12
|
||||
#define GLX_STENCIL_SIZE 13
|
||||
#define GLX_DRAWABLE_TYPE 0x8010
|
||||
#define GLX_RGBA_TYPE 0x8014
|
||||
#define GLX_WINDOW_BIT 0x00000001
|
||||
#define GLX_PIXMAP_BIT 0x00000002
|
||||
#define GLX_PBUFFER_BIT 0x00000004
|
||||
|
||||
/* GLX_ARB_multisample */
|
||||
#define GLX_SAMPLE_BUFFERS_ARB 100000
|
||||
#define GLX_SAMPLES_ARB 100001
|
||||
|
||||
#define GLX_PBUFFER_HEIGHT 0x8040
|
||||
#define GLX_PBUFFER_WIDTH 0x8041
|
||||
|
||||
/* GLX_ARB_create_context[_profile] */
|
||||
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
|
||||
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
|
||||
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
|
||||
GLXFunctions glX = { 0 };
|
||||
|
||||
static void setupAttribs(int* glxAttr, const SST_OpenGLContextAttributes* attribs, Bool supportsMultisample);
|
||||
static int* addAttr(int* ptr, int attr, int value)
|
||||
{
|
||||
ptr[0] = attr;
|
||||
ptr[1] = value;
|
||||
return ptr + 2;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int loadGLX()
|
||||
{
|
||||
const int flags = RTLD_LAZY | RTLD_GLOBAL;
|
||||
void* libGL;
|
||||
|
||||
/* Set all values to null/0/false */
|
||||
memset(&glX, 0, sizeof(GLXFunctions));
|
||||
|
||||
/* Load OpenGL library with proper DT_SONAME */
|
||||
libGL = dlopen("libGL.so.1", flags);
|
||||
if(libGL == NULL)
|
||||
{
|
||||
/* Failed...try generic name for it */
|
||||
libGL = dlopen("libGL.so", flags);
|
||||
if(libGL == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resolve symbols */
|
||||
glX.QueryExtension = dlsym(libGL, "glXQueryExtension");
|
||||
glX.QueryVersion = dlsym(libGL, "glXQueryVersion");
|
||||
glX.QueryExtensionsString = dlsym(libGL, "glXQueryExtensionsString");
|
||||
glX.ChooseFBConfig = dlsym(libGL, "glXChooseFBConfig");
|
||||
glX.CreateNewContext = dlsym(libGL, "glXCreateNewContext");
|
||||
glX.DestroyContext = dlsym(libGL, "glXDestroyContext");
|
||||
glX.MakeContextCurrent = dlsym(libGL, "glXMakeContextCurrent");
|
||||
glX.GetCurrentContext = dlsym(libGL, "glXGetCurrentContext");
|
||||
glX.SwapBuffers = dlsym(libGL, "glXSwapBuffers");
|
||||
glX.CreatePbuffer = dlsym(libGL, "glXCreatePbuffer");
|
||||
glX.DestroyPbuffer = dlsym(libGL, "glXDestroyPbuffer");
|
||||
|
||||
/* On Linux, glXGetProcAddressARB() is statically exported from libGL.so as part of LSB. However,
|
||||
on non-LSB compliant or other UNIX systems, the -ARB version may not exist. Try the unsuffixed
|
||||
form if the -ARB variant does not exist. */
|
||||
glX.GetProcAddressARB = dlsym(libGL, "glXGetProcAddressARB");
|
||||
if(glX.GetProcAddressARB == NULL)
|
||||
glX.GetProcAddressARB = dlsym(libGL, "glXGetProcAddress");
|
||||
|
||||
/* We dont resolve glXCreateContextAttribsARB yet; first check GLX extension strings. */
|
||||
glX.CreateContextAttribsARB = NULL;
|
||||
|
||||
/* Save library handle */
|
||||
glX.libGL = libGL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void unloadGLX()
|
||||
{
|
||||
dlclose(glX.libGL);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int isGLXLoaded()
|
||||
{
|
||||
return (glX.libGL != NULL);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int isGLXSupported(Display* display)
|
||||
{
|
||||
int major = 0, minor = 0;
|
||||
int combined;
|
||||
const char* ext;
|
||||
|
||||
/* Query if the X server supports GLX. If it doesn't, then nothing to do */
|
||||
if(glX.QueryExtension(display, NULL, NULL) == False)
|
||||
{
|
||||
fprintf(stderr, "%s:GLX extension not supported on this connection.\n", "libsst-wm");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Query the version; we need 1.3 or later */
|
||||
if(glX.QueryVersion(display, &major, &minor) == False)
|
||||
{
|
||||
fprintf(stderr, "%s:Unable to query GLX version.\n", "libsst-wm");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fail on less than 1.3 */
|
||||
combined = (major << 8) | minor;
|
||||
if(combined < 0x13)
|
||||
{
|
||||
fprintf(stderr, "%s:GLX version 1.3 required, found %d.%d\n", "libsst-wm", major, minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ext = glX.QueryExtensionsString(display, DefaultScreen(display));
|
||||
|
||||
/* "GLX_ARB_create_context" and "GLX_ARB_create_context_profile" might both match the first strstr(),
|
||||
but "GLX_ARB_create_context_profile" requires the former, so it's all good.
|
||||
TODO: write less stupid extension checker - one day may not be true */
|
||||
if(combined >= 0x14) /* GLX 1.4 required for GLX_ARB_create_context */
|
||||
{
|
||||
glX.supportsCreateContextARB = (Bool)(strstr(ext, "GLX_ARB_create_context") != NULL);
|
||||
glX.supportsProfiles = (Bool)(strstr(ext, "GLX_ARB_create_context_profile") != NULL);
|
||||
|
||||
/* Supposedly GLX_ARB_create_context is supported. Try to resolve the symbol. If we can't,
|
||||
then backout. */
|
||||
if(glX.supportsCreateContextARB) {
|
||||
glX.CreateContextAttribsARB = glX.GetProcAddressARB("glXCreateContextAttribsARB");
|
||||
if(glX.CreateContextAttribsARB == NULL) {
|
||||
glX.supportsCreateContextARB = False;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Don't have GLX 1.4, so can't possibly have these */
|
||||
{
|
||||
glX.supportsCreateContextARB = False;
|
||||
glX.supportsProfiles = False;
|
||||
}
|
||||
|
||||
glX.supportsMultisample = (Bool)(strstr(ext, "GLX_ARB_multisample") != NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_OpenGLContext GLXCreateOpenGLContext(SST_DisplayTarget_Xlib* displayTarget, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
int attr[MAX_GL_ATTRS];
|
||||
Display* display = displayTarget->display;
|
||||
GLXFBConfig* configs;
|
||||
GLXFBConfig fbconfig;
|
||||
GLXContext ctx;
|
||||
int nrConfigs = 0;
|
||||
SST_OpenGLContext_Xlib* GLctx;
|
||||
uint8_t major, minor;
|
||||
GLXPbuffer pb;
|
||||
const int pbattr[5] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, None };
|
||||
|
||||
/* GLX cannot be used to do anything other than standard OpenGL */
|
||||
if(apiType != SSTGL_OPENGL)
|
||||
return NULL;
|
||||
|
||||
/* GLX doesn't support multisampling, but it was explicitly requested */
|
||||
if(!glX.supportsMultisample && attribs->multisampleFactor > 1)
|
||||
return NULL;
|
||||
|
||||
/* Copy SST attributes to GLX attributes */
|
||||
setupAttribs(attr, attribs, glX.supportsMultisample);
|
||||
|
||||
/* Get a list of configs -- we're going to only use the first one though */
|
||||
configs = glX.ChooseFBConfig(display, DefaultScreen(display), attr, &nrConfigs);
|
||||
if(configs == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Copy first FBConfig entry, free array */
|
||||
fbconfig = *configs;
|
||||
X.Free(configs);
|
||||
|
||||
/* Use the new create context functions? */
|
||||
if(glX.supportsCreateContextARB)
|
||||
{
|
||||
int attr[32];
|
||||
int* ptr = &attr[0];
|
||||
int ctxFlags = 0;
|
||||
|
||||
/* Set the major/minor version */
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_MAJOR_VERSION_ARB, attribs->contextVersionMajor);
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_MINOR_VERSION_ARB, attribs->contextVersionMinor);
|
||||
|
||||
/* If GLX_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(glX.supportsProfiles)
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_PROFILE_MASK_ARB, (attribs->legacyEnabled ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : GLX_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Enable/disable forward compatibility */
|
||||
if(!attribs->legacyEnabled)
|
||||
ctxFlags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(attribs->debugEnabled)
|
||||
ctxFlags |= GLX_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = None;
|
||||
|
||||
|
||||
ctx = glX.CreateContextAttribsARB(display, fbconfig, NULL, True, attr);
|
||||
if(ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
}
|
||||
else /* Use older GLX 1.3 glXCreateNewContext() function */
|
||||
{
|
||||
/* Attempt to create an OpenGL context */
|
||||
ctx = glX.CreateNewContext(display, fbconfig, GLX_RGBA_TYPE, NULL, True);
|
||||
if(ctx == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* In order to check the version number, we're going to need to create
|
||||
a temporary context. I'm using a Pbuffer to do so. */
|
||||
pb = glX.CreatePbuffer(display, fbconfig, pbattr);
|
||||
if(pb == None)
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Activate it */
|
||||
if(glX.MakeContextCurrent(display, pb, pb, ctx))
|
||||
{
|
||||
const char* (*pglGetString)(unsigned int);
|
||||
const char* version;
|
||||
|
||||
/* Check libGL for this */
|
||||
pglGetString = dlsym(glX.libGL, "glGetString");
|
||||
|
||||
version = pglGetString(GL_VERSION);
|
||||
|
||||
major = (uint8_t)(version[0] - '0'); /* "X.Y" -> [0]:major, [2]:minor */
|
||||
minor = (uint8_t)(version[2] - '0');
|
||||
|
||||
/* Save context version information */
|
||||
if(selectedAttribsReturn != NULL)
|
||||
{
|
||||
selectedAttribsReturn->contextVersionMajor = (uint8_t)major;
|
||||
selectedAttribsReturn->contextVersionMinor = (uint8_t)minor;
|
||||
}
|
||||
|
||||
/* OK, we have the information we need. Unbind the context and destroy the Pbuffer */
|
||||
glX.MakeContextCurrent(display, None, None, NULL);
|
||||
glX.DestroyPbuffer(display, pb);
|
||||
|
||||
/* If the major version is too low or the major version is OK, but the minor version is lacking, then fail */
|
||||
if(major < attribs->contextVersionMajor || (major == attribs->contextVersionMajor && minor < attribs->contextVersionMinor))
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else /* Failed to make current */
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
glX.DestroyPbuffer(display, pb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLctx = (SST_OpenGLContext_Xlib*)malloc(sizeof(SST_OpenGLContext_Xlib));
|
||||
if(GLctx == NULL)
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GLctx->glxcontext = ctx;
|
||||
GLctx->displayTarget = displayTarget;
|
||||
GLctx->ctxVersion[0] = major;
|
||||
GLctx->ctxVersion[1] = minor;
|
||||
|
||||
return GLctx;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void setupAttribs(int* glxAttr, const SST_OpenGLContextAttributes* attribs, Bool supportsMultisample)
|
||||
{
|
||||
int* ptr = glxAttr;
|
||||
int r, b, g;
|
||||
|
||||
|
||||
switch(attribs->colorBits)
|
||||
{
|
||||
/* Since these values are "at least", 5-5-5 and 5-6-5 configurations can use the same number */
|
||||
case 15:
|
||||
case 16:
|
||||
r = g = b = 5;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
r = g = b = 8;
|
||||
|
||||
}
|
||||
|
||||
ptr = addAttr(ptr, GLX_DOUBLEBUFFER, True);
|
||||
ptr = addAttr(ptr, GLX_STEREO, (attribs-> stereoEnabled != 0));
|
||||
ptr = addAttr(ptr, GLX_RED_SIZE, r);
|
||||
ptr = addAttr(ptr, GLX_GREEN_SIZE, r);
|
||||
ptr = addAttr(ptr, GLX_BLUE_SIZE, b);
|
||||
ptr = addAttr(ptr, GLX_ALPHA_SIZE, ((int)attribs->alphaBits) & 0xFF);
|
||||
ptr = addAttr(ptr, GLX_DEPTH_SIZE, ((int)attribs->depthBits) & 0xFF);
|
||||
ptr = addAttr(ptr, GLX_STENCIL_SIZE, ((int)attribs->stencilBits) & 0xFF);
|
||||
|
||||
/* Add multisample attributes as appropriate */
|
||||
if(attribs->multisampleFactor > 1 && supportsMultisample)
|
||||
{
|
||||
ptr = addAttr(ptr, GLX_SAMPLE_BUFFERS_ARB, 1);
|
||||
ptr = addAttr(ptr, GLX_SAMPLES_ARB, ((int)attribs->multisampleFactor) & 0xFF);
|
||||
}
|
||||
|
||||
/* End attribute list */
|
||||
*ptr = None;
|
||||
|
||||
}
|
||||
95
libsst-wm/Xlib/GLXPrivate.h
Normal file
95
libsst-wm/Xlib/GLXPrivate.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
GLXPrivate.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/11/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL on X Windows (GLX) utility code
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _GLXPRIVATE_H
|
||||
#define _GLXPRIVATE_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
|
||||
struct SST_DisplayTarget_Xlib;
|
||||
|
||||
#define MAX_GL_ATTRS 32
|
||||
|
||||
/* glx.h types */
|
||||
typedef XID GLXDrawable;
|
||||
typedef XID GLXWindow;
|
||||
typedef XID GLXPbuffer;
|
||||
typedef struct __fakeGLXContext* GLXContext;
|
||||
typedef struct __fakeGLXFBConfig* GLXFBConfig;
|
||||
|
||||
typedef Bool (*pf_glXQueryExtension)(Display* dpy, int* errorBase, int* eventBase);
|
||||
typedef Bool (*pf_glXQueryVersion)(Display* dpy, int* major, int* minor);
|
||||
typedef const char* (*pf_glXQueryExtensionsString)(Display* dpy, int screen);
|
||||
typedef GLXFBConfig* (*pf_glXChooseFBConfig)(Display* dpy, int screen, const int* attrib_list, int* nelements);
|
||||
typedef GLXContext (*pf_glXCreateNewContext)(Display* dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
|
||||
typedef void (*pf_glXDestroyContext)(Display* dpy, GLXContext ctx);
|
||||
typedef Bool (*pf_glXMakeContextCurrent)(Display* display, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
|
||||
typedef GLXContext (*pf_glXGetCurrentContext)(void);
|
||||
typedef void (*pf_glXSwapBuffers)(Display * dpy, GLXDrawable drawable);
|
||||
typedef GLXPbuffer (*pf_glXCreatePbuffer)(Display* dpy, GLXFBConfig config, const int* attrib_list);
|
||||
typedef void (*pf_glXDestroyPbuffer)(Display* dpy, GLXPbuffer pbuf);
|
||||
typedef GLXContext (*pf_glXCreateContextAttribsARB)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int* attrib_list);
|
||||
|
||||
typedef void* (*pf_glXGetProcAddressARB)(const char* procName);
|
||||
|
||||
typedef struct GLXFunctions
|
||||
{
|
||||
pf_glXQueryExtension QueryExtension;
|
||||
pf_glXQueryVersion QueryVersion;
|
||||
pf_glXQueryExtensionsString QueryExtensionsString;
|
||||
pf_glXChooseFBConfig ChooseFBConfig;
|
||||
pf_glXCreateNewContext CreateNewContext;
|
||||
pf_glXDestroyContext DestroyContext;
|
||||
pf_glXMakeContextCurrent MakeContextCurrent;
|
||||
pf_glXGetCurrentContext GetCurrentContext;
|
||||
pf_glXSwapBuffers SwapBuffers;
|
||||
pf_glXCreatePbuffer CreatePbuffer;
|
||||
pf_glXDestroyPbuffer DestroyPbuffer;
|
||||
pf_glXCreateContextAttribsARB CreateContextAttribsARB;
|
||||
pf_glXGetProcAddressARB GetProcAddressARB;
|
||||
|
||||
Bool supportsCreateContextARB;
|
||||
Bool supportsProfiles;
|
||||
Bool supportsMultisample;
|
||||
void* libGL;
|
||||
} GLXFunctions;
|
||||
|
||||
extern GLXFunctions glX;
|
||||
|
||||
/* Load libGL and resolve GLX symbols */
|
||||
int loadGLX();
|
||||
|
||||
/* Unload libGL */
|
||||
void unloadGLX();
|
||||
|
||||
/* Check if libGL was loaded */
|
||||
int isGLXLoaded();
|
||||
|
||||
/* Check if GLX is supported by the X server, and a usable version */
|
||||
int isGLXSupported(Display* display);
|
||||
|
||||
/* Create a GLX context */
|
||||
SST_OpenGLContext GLXCreateOpenGLContext(struct SST_DisplayTarget_Xlib* target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
49
libsst-wm/Xlib/SST_WMDialogBox_Xlib.c
Normal file
49
libsst-wm/Xlib/SST_WMDialogBox_Xlib.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
SST_WMDialogBox_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Simple dialog box window (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
|
||||
#define BUTTON_HSPACE 16 /* Space on either side of a button */
|
||||
#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */
|
||||
#define TEXT_HSPACE 16
|
||||
#define TEXT_VSPACE 16
|
||||
|
||||
typedef struct DialogBoxData
|
||||
{
|
||||
const char* message;
|
||||
int lenMessage;
|
||||
int buttonId;
|
||||
int exitTime;
|
||||
} DialogBoxData;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Xlib_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons)
|
||||
{
|
||||
/* TODO: helluvalota work */
|
||||
(void)target;
|
||||
(void)parent;
|
||||
(void)caption;
|
||||
(void)message;
|
||||
(void)buttons;
|
||||
(void)nrButtons;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
166
libsst-wm/Xlib/SST_WMEnum_Xlib.c
Normal file
166
libsst-wm/Xlib/SST_WMEnum_Xlib.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
SST_WMEnum_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Enumerates graphics adapters and screens.
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WM.h>
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
#include <string.h> /* strlen() etc. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_GraphicsEnumerator Xlib_CreateGraphicsEnumerator(void)
|
||||
{
|
||||
Display* display;
|
||||
SST_GraphicsEnumerator_Xlib* enumerator;
|
||||
|
||||
enumerator = (SST_GraphicsEnumerator_Xlib*)malloc(sizeof(SST_GraphicsEnumerator_Xlib));
|
||||
|
||||
if(enumerator == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Open the display */
|
||||
display = X.OpenDisplay(NULL);
|
||||
if(display == NULL)
|
||||
{
|
||||
free(enumerator);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save and return */
|
||||
enumerator->bpp = (uint32_t)DefaultDepth(display, DefaultScreen(display));
|
||||
enumerator->width = (uint32_t)DisplayWidth(display, DefaultScreen(display));
|
||||
enumerator->height = (uint32_t)DisplayHeight(display, DefaultScreen(display));
|
||||
|
||||
/* Done with display */
|
||||
X.CloseDisplay(display);
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static size_t Xlib_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
(void)enumerator;
|
||||
|
||||
/* Only support 1 adapter */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize)
|
||||
{
|
||||
size_t len;
|
||||
const char* name = "X Display Device";
|
||||
|
||||
(void)enumerator;
|
||||
(void)adapterId;
|
||||
|
||||
len = strlen(name);
|
||||
|
||||
/* Query name length */
|
||||
if(nameReturn == NULL)
|
||||
{
|
||||
*bufferSize = len+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t copyAmount;
|
||||
|
||||
/* Nothing to do? */
|
||||
if(*bufferSize == 0)
|
||||
return;
|
||||
|
||||
/* Use min(len, (*bufferSize)-1) */
|
||||
copyAmount = len;
|
||||
if(copyAmount > (*bufferSize)-1)
|
||||
copyAmount = (*bufferSize)-1;
|
||||
|
||||
memcpy(nameReturn, name, copyAmount);
|
||||
nameReturn[copyAmount] = '\0';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static size_t Xlib_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId)
|
||||
{
|
||||
(void)enumerator;
|
||||
(void)adapterId;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn)
|
||||
{
|
||||
SST_GraphicsEnumerator_Xlib* enumXlib = (SST_GraphicsEnumerator_Xlib*)enumerator;
|
||||
|
||||
/* Only one adapter/screen supported */
|
||||
if(adapterId != 0 || screenId != 0)
|
||||
return;
|
||||
|
||||
if(modesReturn == NULL)
|
||||
*modeCountReturn = 1;
|
||||
else
|
||||
{
|
||||
modesReturn[0].bpp = enumXlib->bpp;
|
||||
modesReturn[0].width = enumXlib->width;
|
||||
modesReturn[0].height = enumXlib->height;
|
||||
modesReturn[0].refreshRate = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode)
|
||||
{
|
||||
SST_GraphicsEnumerator_Xlib* enumXlib = (SST_GraphicsEnumerator_Xlib*)enumerator;
|
||||
if(adapterId != 0 || screenId != 0)
|
||||
return;
|
||||
|
||||
mode->bpp = enumXlib->bpp;
|
||||
mode->width = enumXlib->width;
|
||||
mode->height = enumXlib->height;
|
||||
mode->refreshRate = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
free(enumerator);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct SST_WM_EnumFuncs Xlib_EnumFuncs = {
|
||||
Xlib_CreateGraphicsEnumerator,
|
||||
Xlib_GetEnumAdapterCount,
|
||||
Xlib_GetEnumAdapterName,
|
||||
Xlib_GetEnumScreenCount,
|
||||
Xlib_GetEnumVideoModes,
|
||||
Xlib_GetEnumCurrentVideoMode,
|
||||
Xlib_DestroyGraphicsEnumerator
|
||||
};
|
||||
|
||||
482
libsst-wm/Xlib/SST_WMEvent_Xlib.c
Normal file
482
libsst-wm/Xlib/SST_WMEvent_Xlib.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
SST_WMEvent_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Window event functions (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMEvent.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
|
||||
static SST_WMKey XlibKeyToSSTKey(XEvent* e, uint32_t* utf32Return);
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
static void handleXI2Event(SST_DisplayTarget_Xlib*, XGenericEventCookie* cookie);
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn)
|
||||
{
|
||||
XEvent e;
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Display* display = displayTarget->display;
|
||||
EventQueue* q = &displayTarget->eventQueue;
|
||||
|
||||
/* Read all X events */
|
||||
while(X.Pending(display))
|
||||
{
|
||||
SST_Window_Xlib* win = NULL;
|
||||
SST_Window_Xlib* next;
|
||||
SST_WMEvent* event;
|
||||
#ifdef HAVE_XINPUT2
|
||||
XGenericEventCookie* cookie = &e.xcookie;
|
||||
#endif
|
||||
int up = 1;
|
||||
|
||||
X.NextEvent(display, &e);
|
||||
|
||||
/* Find the window for which this matches and save into 'win' */
|
||||
next = displayTarget->firstWindow;
|
||||
while(next)
|
||||
{
|
||||
/* Window ID matches this event? */
|
||||
if(next->xwin == e.xany.window)
|
||||
{
|
||||
/* Found it, stop here */
|
||||
win = next;
|
||||
break;
|
||||
}
|
||||
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
/* Handle X extension events */
|
||||
if(cookie->type == GenericEvent && cookie->extension == displayTarget->xi2opcode)
|
||||
{
|
||||
X.GetEventData(display, cookie);
|
||||
handleXI2Event(displayTarget, cookie);
|
||||
X.FreeEventData(display, cookie);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Event doesn't apply to any window we own, ignore it */
|
||||
if(win == NULL)
|
||||
continue;
|
||||
|
||||
switch(e.type)
|
||||
{
|
||||
/* Moved mouse */
|
||||
case MotionNotify:
|
||||
{
|
||||
//Ignore MotionNotify when using relative mouse movements
|
||||
if(!displayTarget->relativeMouse)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_MOUSEMOVED;
|
||||
event->details.mouseEvent.x = (uint32_t)e.xmotion.x;
|
||||
event->details.mouseEvent.y = (uint32_t)e.xmotion.y;
|
||||
event->details.mouseEvent.button = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ButtonPress: up = 0; /* Intentional fall through */
|
||||
case ButtonRelease:
|
||||
{
|
||||
const uint32_t button = e.xbutton.button;
|
||||
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
|
||||
/* Button press (1 - 3) */
|
||||
if(button >= Button1 && button <= Button3)
|
||||
{
|
||||
event->type = (up ? SSTWMEVENT_MOUSEUP : SSTWMEVENT_MOUSEDOWN);
|
||||
event->details.mouseEvent.x = (uint32_t)e.xbutton.x;
|
||||
event->details.mouseEvent.y = (uint32_t)e.xbutton.y;
|
||||
event->details.mouseEvent.button = SST_MB1 + (button - Button1);
|
||||
}
|
||||
else if(e.type == ButtonPress) /* Scroll wheel. Button4 = scroll up, Button5 = scroll down. */
|
||||
{ /* X will send two events: press/release for a single scroll. Only send 1 event */
|
||||
event->type = SSTWMEVENT_MOUSEWHEEL;
|
||||
event->details.scrollEvent.vscroll = (button == Button4 ? 1.0f : -1.0f);
|
||||
event->details.scrollEvent.hscroll = 0.0f; /* TODO: how to get horizonal scroll wheel? */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyPress: up = 0; /* Intentional fall through */
|
||||
case KeyRelease:
|
||||
{
|
||||
uint32_t modState = 0;
|
||||
uint8_t whichBit = e.xkey.keycode % 8;
|
||||
uint32_t whichByte = e.xkey.keycode / 8;
|
||||
|
||||
/*
|
||||
X will autorepeat with a bunch of keyd release messages. We only want the key up, so it looks like:
|
||||
PPPPPPPPPPPPPR
|
||||
instead of:
|
||||
PRPRPRPRPRPRPR
|
||||
|
||||
To find this out, when receive a KeyRelease message, we check if there is another KeyPress message with the same
|
||||
exact time. If so, we ignore this KeyRelease message.
|
||||
*/
|
||||
if(e.xany.type == KeyRelease)
|
||||
{
|
||||
if(X.Pending(display))
|
||||
{
|
||||
XEvent nextEvent;
|
||||
X.PeekEvent(display, &nextEvent);
|
||||
|
||||
if( nextEvent.type == KeyPress && /* Opposite of KeyRelease */
|
||||
nextEvent.xkey.keycode == e.xkey.keycode && /* Same key code */
|
||||
nextEvent.xkey.time == e.xkey.time) /* Same time */
|
||||
{
|
||||
/* Ignore it */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, really is a key release then -- unset this bit */
|
||||
displayTarget->keymapBitvector[whichByte] &= ~(1 << whichBit);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if(displayTarget->keymapBitvector[whichByte] >> whichBit)
|
||||
modState |= SSTKEYMOD_REPEAT;
|
||||
|
||||
/* TODO: how to set SSTKEYMOD_REPEAT flag? Maybe use XQueryKeymap()? */
|
||||
displayTarget->keymapBitvector[whichByte] |= (1 << whichBit);
|
||||
|
||||
}
|
||||
|
||||
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
SST_WMKey key;
|
||||
uint32_t utf32;
|
||||
|
||||
key = XlibKeyToSSTKey(&e, &utf32);
|
||||
|
||||
event->window = win;
|
||||
event->type = (up ? SSTWMEVENT_KEYUP : SSTWMEVENT_KEYDOWN);
|
||||
event->details.keyEvent.key = key;
|
||||
event->details.keyEvent.utf32 = utf32;
|
||||
event->details.keyEvent.modifierState = modState;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Window shown */
|
||||
case Expose:
|
||||
{
|
||||
/* TODO: software rendering should blit image */
|
||||
break;
|
||||
}
|
||||
|
||||
case ConfigureNotify:
|
||||
{
|
||||
/* Clients are told to ignore this message if override_redirect is true. */
|
||||
if(e.xconfigure.override_redirect == False)
|
||||
{
|
||||
const XConfigureEvent* xc = (const XConfigureEvent*)&e.xconfigure;
|
||||
|
||||
/* Check if window moved */
|
||||
if(win->lastX != xc->x || win->lastY != xc->y)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_MOVED;
|
||||
event->details.winEvent.x = (uint32_t)(xc->x < 0 ? 0 : xc->x);
|
||||
event->details.winEvent.y = (uint32_t)(xc->y < 0 ? 0 : xc->y);
|
||||
}
|
||||
}
|
||||
|
||||
if(win->lastWidth != xc->width || win->lastHeight != xc->height)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_RESIZED;
|
||||
event->details.winEvent.x = (uint32_t)xc->width;
|
||||
event->details.winEvent.y = (uint32_t)xc->height;
|
||||
}
|
||||
|
||||
win->lastWidth = xc->width;
|
||||
win->lastHeight = xc->height;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClientMessage:
|
||||
{
|
||||
/* Close window attempt? */
|
||||
if(e.xclient.message_type == displayTarget->atomWmProtocols &&
|
||||
(Atom)e.xclient.data.l[0] == displayTarget->atomWmDeleteWindow)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_CLOSE;
|
||||
memset(&event->details, 0, sizeof(event->details));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dequeue for user events first */
|
||||
if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
/* Remove system events next */
|
||||
if(RemoveFromEQ(&displayTarget->eventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static EventQueue* Xlib_getUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
return &displayTarget->userEventQueue;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void Xlib_lockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
pthread_mutex_lock(&displayTarget->eventLock);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_unlockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
pthread_mutex_unlock(&displayTarget->eventLock);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_WMKey XlibKeyToSSTKey(XEvent* e, uint32_t* utf32Return)
|
||||
{
|
||||
uint8_t chars[8];
|
||||
uint32_t utf32;
|
||||
|
||||
KeySym keycode;
|
||||
|
||||
X.LookupString(&e->xkey, (char*)chars, sizeof(chars), &keycode, NULL);
|
||||
|
||||
/* TODO: figure out how to extract multicharacter values */
|
||||
utf32 = (uint32_t)chars[0];
|
||||
|
||||
/* X allows Ctrl+[a-z] to generate some weird characters */
|
||||
if(utf32 < 0x20u)
|
||||
utf32 = 0;
|
||||
|
||||
*utf32Return = utf32;
|
||||
|
||||
/* 0 - 9 */
|
||||
if(keycode >= XK_0 && keycode <= XK_9)
|
||||
return (SST_WMKey)(SSTWMKEY_0 + (keycode - XK_0));
|
||||
|
||||
/* Keypad 0 - 9 */
|
||||
if(keycode >= XK_KP_0 && keycode <= XK_KP_9)
|
||||
return (SST_WMKey)(SSTWMKEY_KEYPAD_0 + (keycode - XK_KP_0));
|
||||
|
||||
/* Capital A-Z */
|
||||
if(keycode >= XK_A && keycode <= XK_Z)
|
||||
return (SST_WMKey)(SSTWMKEY_A + (keycode - XK_A));
|
||||
|
||||
/* Lower case A-Z */
|
||||
if(keycode >= XK_a && keycode <= XK_z)
|
||||
return (SST_WMKey)(SSTWMKEY_A + (keycode - XK_a));
|
||||
|
||||
/* Function keys (F1-F15) */
|
||||
if(keycode >= XK_F1 && keycode <= XK_F15)
|
||||
return (SST_WMKey)(SSTWMKEY_F1 + (keycode - XK_F1));
|
||||
|
||||
switch(keycode)
|
||||
{
|
||||
|
||||
case XK_BackSpace: return SSTWMKEY_BACKSPACE;
|
||||
case XK_Tab: return SSTWMKEY_TAB;
|
||||
case XK_Return: return SSTWMKEY_RETURN;
|
||||
|
||||
case XK_Escape: return SSTWMKEY_ESCAPE;
|
||||
case XK_space: return SSTWMKEY_SPACE;
|
||||
case XK_Caps_Lock: return SSTWMKEY_CAPSLOCK;
|
||||
#if 0
|
||||
case VK_OEM_COMMA : return SSTWMKEY_COMMA;
|
||||
case VK_OEM_PERIOD: return SSTWMKEY_PERIOD;
|
||||
case VK_OEM_2: return SSTWMKEY_FORWARDSLASH; /* '/?' key */
|
||||
case VK_OEM_1: return SSTWMKEY_SEMICOLON; /* ';:' key */
|
||||
case VK_OEM_7: return SSTWMKEY_QUOTES; /* single-quote/double quotes key */
|
||||
case VK_OEM_4: return SSTWMKEY_OPENBRACKET; /* '{{' key */
|
||||
case VK_OEM_6: return SSTWMKEY_CLOSEBRACKET; /* ']}' key */
|
||||
case VK_OEM_5: return SSTWMKEY_BACKSLASH; /* '\|' key */
|
||||
case VK_OEM_MINUS : return SSTWMKEY_UNDERBAR;
|
||||
case VK_OEM_PLUS: return SSTWMKEY_EQUALS;
|
||||
#endif
|
||||
|
||||
//Keypad
|
||||
case XK_KP_Enter: return SSTWMKEY_KEYPAD_ENTER;
|
||||
case XK_Num_Lock: return SSTWMKEY_NUMLOCK;
|
||||
case XK_KP_Decimal: return SSTWMKEY_KEYPAD_PERIOD;
|
||||
case XK_KP_Divide: return SSTWMKEY_KEYPAD_DIVIDE;
|
||||
case XK_KP_Multiply: return SSTWMKEY_KEYPAD_MULTIPLY;
|
||||
case XK_KP_Subtract: return SSTWMKEY_KEYPAD_MINUS;
|
||||
case XK_KP_Add: return SSTWMKEY_KEYPAD_PLUS;
|
||||
|
||||
/* Arrow keys */
|
||||
case XK_Up: return SSTWMKEY_ARROW_UP;
|
||||
case XK_Down: return SSTWMKEY_ARROW_DOWN;
|
||||
case XK_Left: return SSTWMKEY_ARROW_LEFT;
|
||||
case XK_Right: return SSTWMKEY_ARROW_RIGHT;
|
||||
|
||||
/* The page up/down block */
|
||||
case XK_Insert: return SSTWMKEY_INSERT;
|
||||
case XK_Home: return SSTWMKEY_HOME;
|
||||
case XK_End: return SSTWMKEY_END;
|
||||
case XK_Page_Up: return SSTWMKEY_PAGEUP;
|
||||
case XK_Page_Down: return SSTWMKEY_PAGEDOWN;
|
||||
case XK_Delete: return SSTWMKEY_DELETE;
|
||||
|
||||
case XK_Shift_L: return SSTWMKEY_LEFTSHIFT;
|
||||
case XK_Shift_R: return SSTWMKEY_RIGHTSHIFT;
|
||||
case XK_Control_L: return SSTWMKEY_LEFTCONTROL;
|
||||
case XK_Control_R: return SSTWMKEY_RIGHTCONTROL;
|
||||
case XK_Alt_L: return SSTWMKEY_LEFTALT;
|
||||
case XK_Alt_R: return SSTWMKEY_RIGHTALT;
|
||||
case XK_Super_L: return SSTWMKEY_LEFTSUPER;
|
||||
case XK_Super_R: return SSTWMKEY_RIGHTSUPER;
|
||||
#if 0
|
||||
/* Misc */
|
||||
case VK_SNAPSHOT: return SSTWMKEY_PRINTSCREEN;
|
||||
case VK_SCROLL: return SSTWMKEY_SCROLLLOCK;
|
||||
case VK_PAUSE: return SSTWMKEY_PAUSE;
|
||||
#endif
|
||||
case XK_asciitilde: return SSTWMKEY_TILDE; /* `~ key */
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return SSTWMKEY_NONE;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#ifdef HAVE_XINPUT2
|
||||
|
||||
static size_t min2(size_t x, size_t y) { return (x < y ? x : y); }
|
||||
|
||||
static void extractXI2values(const XIRawEvent* rawev, double* valuesReturn, size_t valueArraySize) {
|
||||
size_t i;
|
||||
const double* raw_values = rawev->raw_values;
|
||||
const unsigned char* mask = rawev->valuators.mask;
|
||||
const size_t elemsToCheck = min2(valueArraySize, rawev->valuators.mask_len * 8);
|
||||
|
||||
/* From what I can understand, raw_values[] is a compressed array. XIMaskIsSet(mask,i)
|
||||
is used to check whether element i of the output should be read from raw_values[]. So
|
||||
for example, raw_values[] could be just { 3.0, 5.0}, but the mask could be 1001b, which
|
||||
means that:
|
||||
XIMaskIsSet(1001b,0) == true; -> output[0] = 3.0 (raw_values[0)]
|
||||
XIMaskIsSet(1001b,1) == false; -> output[1] = 0.0 (default value)
|
||||
XIMaskIsSet(1001b,2) == false; -> output[2] = 0.0 (default value)
|
||||
XIMaskIsSet(1001b,3) == true; -> output[3] = 5.0 (raw_values[1])
|
||||
*/
|
||||
for(i=0; i < elemsToCheck; i++) {
|
||||
if(XIMaskIsSet(mask, i)) {
|
||||
valuesReturn[i] = *raw_values;
|
||||
raw_values++;
|
||||
} else {
|
||||
valuesReturn[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Any uninitialized elements at the end set to zero */
|
||||
if(elemsToCheck < valueArraySize) {
|
||||
memset(&valuesReturn[elemsToCheck], 0, (valueArraySize-elemsToCheck)*sizeof(*valuesReturn));
|
||||
}
|
||||
}
|
||||
|
||||
static void handleXI2Event(SST_DisplayTarget_Xlib* displayTarget, XGenericEventCookie* cookie)
|
||||
{
|
||||
XIDeviceEvent* ev = (XIDeviceEvent*)cookie->data;
|
||||
EventQueue* q = &displayTarget->eventQueue;
|
||||
SST_WMEvent* event;
|
||||
|
||||
switch(ev->evtype)
|
||||
{
|
||||
case XI_RawButtonPress:
|
||||
case XI_RawButtonRelease:
|
||||
break;
|
||||
|
||||
case XI_RawMotion:
|
||||
{
|
||||
XIRawEvent* re = (XIRawEvent*)cookie->data;
|
||||
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
double rel[2];
|
||||
|
||||
extractXI2values(re, rel, 2);
|
||||
|
||||
event->window = NULL; /* TODO: ... ?*/
|
||||
event->type = SSTWMEVENT_MOUSERELMOVED;
|
||||
event->details.relMouseEvent.relx = (int32_t)rel[0];
|
||||
event->details.relMouseEvent.rely = (int32_t)rel[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct SST_WM_EventFuncs Xlib_EventFuncs = {
|
||||
Xlib_GetEvent,
|
||||
Xlib_getUserEventQueue,
|
||||
Xlib_lockUserEventQueue,
|
||||
Xlib_unlockUserEventQueue
|
||||
};
|
||||
|
||||
38
libsst-wm/Xlib/SST_WMNonPortable_Xlib.c
Normal file
38
libsst-wm/Xlib/SST_WMNonPortable_Xlib.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
SST_WMNonPortable_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Non-portable API calls in libsst-wm for the Xlib platform
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
Display* SST_WM_GetDisplayX11(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
return win->owner->display;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
Window SST_WM_GetWindowX11(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
return win->xwin;
|
||||
}
|
||||
315
libsst-wm/Xlib/SST_WMOpenGL_Xlib.c
Normal file
315
libsst-wm/Xlib/SST_WMOpenGL_Xlib.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
SST_WMOpenGL_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/13/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL context creation on X Windows
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "GLXPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
|
||||
/*
|
||||
NOTE: We don't include <GL/gl.h> because it may not exist! Many embedded Linux
|
||||
systems now ship with OpenGL|ES only, and because of that, they don't have
|
||||
headers for full OpenGL. This API supports both, so we can't assume any OpenGL
|
||||
headers (either regular or "ES") exist.
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Xlib_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
SST_OpenGLContext glctx;
|
||||
Bool usingGLX = True;
|
||||
Display* display = displayTarget->display;
|
||||
|
||||
/* If using GL|ES, only EGL will do */
|
||||
if(apiType == SSTGL_OPENGL_ES)
|
||||
usingGLX = False;
|
||||
else /* We can use either GLX or EGL to create a full GL context */
|
||||
{
|
||||
/* Not loaded -> fail */
|
||||
if(!isGLXLoaded())
|
||||
usingGLX = False;
|
||||
|
||||
/* The client has GLX libraries, but does the server support it? */
|
||||
if(!isGLXSupported(display))
|
||||
usingGLX = False;
|
||||
|
||||
/* GLX isn't supported */
|
||||
if(usingGLX == False)
|
||||
{
|
||||
/* TODO: try EGL */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(usingGLX)
|
||||
{
|
||||
glctx = GLXCreateOpenGLContext(displayTarget, apiType, attribs, selectedAttribsReturn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Add EGL path */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return glctx;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Xlib_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* master = (SST_OpenGLContext_Xlib*)masterGLContext;
|
||||
SST_OpenGLContext_Xlib* slave;
|
||||
|
||||
#if 0
|
||||
HWND hInvisWnd;
|
||||
FindMonitorInfo fmi;
|
||||
HDC hDC = NULL;
|
||||
HGLRC hGLRC = NULL;
|
||||
BOOL ok;
|
||||
const WGLFunctions* wgl = &master->wgl;
|
||||
|
||||
/* Since the slave context merely needs to be on *a* screen controlled by the display target, just use the first one */
|
||||
findMonitor(&master->displayTarget->devs[0], &fmi);
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */
|
||||
hInvisWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL);
|
||||
if(hInvisWnd == NULL)
|
||||
return NULL;
|
||||
ShowWindow(hInvisWnd, SW_HIDE);
|
||||
|
||||
/* Allocate context structure */
|
||||
slave = HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(slave == NULL)
|
||||
{
|
||||
DestroyWindow(hInvisWnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ok = FALSE;
|
||||
hDC = GetDC(hInvisWnd);
|
||||
|
||||
/* If master context was done using legacy functions... */
|
||||
if(master->isLegacy)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
/* Get the PFD for this pixel foramt */
|
||||
DescribePixelFormat(hDC, master->pixelFormat, sizeof(pfd), &pfd);
|
||||
|
||||
/* Set it */
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, &pfd))
|
||||
{
|
||||
hGLRC = wgl->CreateContext(hDC);
|
||||
if(hGLRC != NULL)
|
||||
{
|
||||
if(wgl->ShareLists(master->context, hGLRC))
|
||||
ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else /* Modern OpenGL functions */
|
||||
{
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, NULL))
|
||||
{
|
||||
HGLRC oldRC;
|
||||
HDC oldDC;
|
||||
|
||||
oldDC = wgl->GetCurrentDC();
|
||||
oldRC = wgl->GetCurrentContext();
|
||||
|
||||
/* Bind master context so we can call wgl extension functions. Note that we're using
|
||||
the invisible window's HDC. This should work because we just set the pixel format to be
|
||||
identical to the master context, meaning they should be compatible */
|
||||
if(wgl->MakeCurrent(hDC, master->context))
|
||||
{
|
||||
int attrs[16];
|
||||
int* ptr = attrs;
|
||||
int ctxFlags;
|
||||
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, master->ctxVersion[0]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, master->ctxVersion[1]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0);
|
||||
|
||||
/* If WGL_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(wgl->supportsProfiles)
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (master->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Legacy-free? */
|
||||
if(!master->legacyEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = 0;
|
||||
|
||||
/* Create the new context, sharing with the master context */
|
||||
hGLRC = wgl->CreateContextAttribsARB(hDC, master->context, attrs);
|
||||
if(hGLRC != NULL)
|
||||
ok = TRUE;
|
||||
}
|
||||
|
||||
/* Restore old context */
|
||||
wgl->MakeCurrent(oldDC, oldRC);
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with the DC */
|
||||
if(hDC)
|
||||
ReleaseDC(hInvisWnd, hDC);
|
||||
|
||||
/* Did we succeed in making the slave context? */
|
||||
if(ok)
|
||||
{
|
||||
/* Set up slave context info */
|
||||
slave->context = hGLRC;
|
||||
slave->displayTarget = master->displayTarget;
|
||||
slave->hDCActive = NULL;
|
||||
slave->hSlaveWnd = hInvisWnd;
|
||||
slave->isLegacy = master->isLegacy;
|
||||
slave->opengl32 = LoadLibraryA("opengl32.dll"); /* Need to increase ref count for opengl32.dll */
|
||||
slave->pixelFormat = master->pixelFormat;
|
||||
slave->wgl = master->wgl; /* TODO: should be safe, right? context dependent, but same device/GL impl... */
|
||||
slave->ctxVersion[0] = master->ctxVersion[0];
|
||||
slave->ctxVersion[1] = master->ctxVersion[1];
|
||||
slave->legacyEnabled = master->legacyEnabled;
|
||||
slave->debugEnabled = master->debugEnabled;
|
||||
}
|
||||
else /* Failure, clean up */
|
||||
{
|
||||
if(hGLRC)
|
||||
master->wgl.DeleteContext(hGLRC);
|
||||
|
||||
DestroyWindow(hInvisWnd);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, slave);
|
||||
slave = NULL;
|
||||
}
|
||||
#endif
|
||||
return slave;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SwapOpenGLBuffers(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx;
|
||||
|
||||
if(glctx->glxcontext)
|
||||
glX.SwapBuffers(glctx->displayTarget->display, glctx->win);
|
||||
else
|
||||
{
|
||||
/* TODO: eglSwapBuffers() */
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx;
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* Unbinding a context from a thread */
|
||||
if(ctx == NULL)
|
||||
{
|
||||
|
||||
/* GLX: Unbind context */
|
||||
if(glctx->glxcontext)
|
||||
{
|
||||
glX.MakeContextCurrent(glctx->displayTarget->display, None, None, NULL);
|
||||
|
||||
glctx->win = None;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: EGL implementation */
|
||||
}
|
||||
|
||||
/* OK */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* GLX*/
|
||||
if(glctx->glxcontext)
|
||||
{
|
||||
|
||||
/* Binding master context to a window */
|
||||
if(win != NULL)
|
||||
{
|
||||
if(glX.MakeContextCurrent(glctx->displayTarget->display, win->xwin, win->xwin, glctx->glxcontext))
|
||||
{
|
||||
glctx->win = win->xwin;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Failed to bind */
|
||||
return 0;
|
||||
}
|
||||
else /* Bind slave context */
|
||||
{
|
||||
/* TODO: bind to a slave's pbuffer, I guess? */
|
||||
}
|
||||
}
|
||||
else /* Otherwise EGL */
|
||||
{
|
||||
/* TODO: EGL */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyOpenGLContext(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx;
|
||||
|
||||
#if 0
|
||||
if(glctx->hSlaveWnd)
|
||||
DestroyWindow(glctx->hSlaveWnd);
|
||||
#endif
|
||||
|
||||
/* Destroy the OpenGL context */
|
||||
glX.DestroyContext(glctx->displayTarget->display, glctx->glxcontext);
|
||||
|
||||
/* Free memory used by our GL context */
|
||||
free(glctx);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
const struct SST_WM_OpenGLFuncs Xlib_OpenGLFuncs = {
|
||||
Xlib_CreateOpenGLContext,
|
||||
Xlib_CreateSlaveOpenGLContext,
|
||||
Xlib_SwapOpenGLBuffers,
|
||||
Xlib_BindOpenGLContext,
|
||||
Xlib_DestroyOpenGLContext
|
||||
};
|
||||
75
libsst-wm/Xlib/SST_WMRender_Xlib.c
Normal file
75
libsst-wm/Xlib/SST_WMRender_Xlib.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
SST_WMRender_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Software rendering support
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include <SST/SST_WMWindow.h>
|
||||
#include "APIPrivate.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Xlib_EnableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* TODO: Use XPutImage or XShm extension */
|
||||
(void)win;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_DisableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* TODO */
|
||||
(void)win;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void* Xlib_LockBackbuffer(SST_Window window, size_t* pitchReturn)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
*pitchReturn = win->softwarePitch;
|
||||
|
||||
return win->softwareBackbuffer;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_UnlockBackbuffer(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* TODO: invalidate window rect and repaint */
|
||||
(void)win;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct SST_WM_RenderFuncs Xlib_RenderFuncs = {
|
||||
Xlib_EnableSoftwareRendering,
|
||||
Xlib_DisableSoftwareRendering,
|
||||
Xlib_LockBackbuffer,
|
||||
Xlib_UnlockBackbuffer
|
||||
};
|
||||
|
||||
86
libsst-wm/Xlib/SST_WMVideoMode_Xlib.c
Normal file
86
libsst-wm/Xlib/SST_WMVideoMode_Xlib.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
SST_WMVideoMode_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Video mode setting functions (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
/*
|
||||
Right now, these are essentially no-ops. Later, some real mechanism needs to be used:
|
||||
|
||||
1) [Preferred] XRandR extension
|
||||
2) XF86VideoMode extension
|
||||
|
||||
That will get good and messy then. In particular, if a set of headers isn't available for the platform,
|
||||
then it basically won't compile. Seems like I need to re-write a few definitions in-line, and of course,
|
||||
link dynamically and do proper version queries (*.so doesn't mean server actually supports it).
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Display* display = displayTarget->display;
|
||||
int xscreen;
|
||||
|
||||
/* Must be screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
xscreen = DefaultScreen(display);
|
||||
|
||||
/* Since we aren't changing the display mode, just verify it matches */
|
||||
if(vmode->bpp != (uint32_t)DefaultDepth(display, xscreen) ||
|
||||
vmode->width != (uint32_t)DisplayWidth(display, xscreen) ||
|
||||
vmode->height != (uint32_t)DisplayHeight(display, xscreen) ||
|
||||
vmode->refreshRate != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Display* display = displayTarget->display;
|
||||
int xscreen;
|
||||
|
||||
/* Must be screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
xscreen = DefaultScreen(display);
|
||||
vmodeReturn->bpp = (uint32_t)DefaultDepth(display, xscreen);
|
||||
vmodeReturn->width = (uint32_t)DisplayWidth(display, xscreen);
|
||||
vmodeReturn->height = (uint32_t)DisplayHeight(display, xscreen);
|
||||
vmodeReturn->refreshRate = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const struct SST_WM_VideoModeFuncs Xlib_VideoModeFuncs = {
|
||||
Xlib_SetVideoModeOnScreen,
|
||||
Xlib_GetVideoModeOnScreen
|
||||
};
|
||||
|
||||
537
libsst-wm/Xlib/SST_WMWindow_Xlib.c
Normal file
537
libsst-wm/Xlib/SST_WMWindow_Xlib.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
SST_WMWindow_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Window creation (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMWindow.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
#include "EventQueue.h"
|
||||
#include "APIPrivate.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static void destroyWin(SST_Window_Xlib* win);
|
||||
|
||||
/* Extended Window Manager Hints (http://standards.freedesktop.org/wm-spec/wm-spec-latest.html) */
|
||||
static int ewmh_supported(SST_DisplayTarget_Xlib* displayTarget, SST_Window_Xlib* win);
|
||||
static void ewmh_setFullscreen(SST_Window_Xlib* win, int fullscreen);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Xlib_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget;
|
||||
#ifdef HAVE_XINPUT2
|
||||
XI2Functions XI;
|
||||
#endif
|
||||
Display* display;
|
||||
|
||||
/* > 1 adapters not supported, multihead not supported */
|
||||
if(screenIndexOrMultihead != 0 || adapterIndex != 0)
|
||||
return NULL;
|
||||
|
||||
/* Open the X display */
|
||||
display = X.OpenDisplay(NULL);
|
||||
if(display == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If we can open a display, then we're connected to the X server,
|
||||
so that is good enough. */
|
||||
|
||||
/* Allocate a display target structure */
|
||||
displayTarget = (SST_DisplayTarget_Xlib*)malloc(sizeof(SST_DisplayTarget_Xlib));
|
||||
if(displayTarget == NULL)
|
||||
{
|
||||
X.CloseDisplay(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize lock for user events */
|
||||
if(pthread_mutex_init(&displayTarget->eventLock, NULL) != 0)
|
||||
{
|
||||
X.CloseDisplay(display);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(InitEQ(&displayTarget->eventQueue) == 0)
|
||||
{
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
X.CloseDisplay(display);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(InitEQ(&displayTarget->userEventQueue) == 0)
|
||||
{
|
||||
DestroyEQ(&displayTarget->eventQueue);
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
X.CloseDisplay(display);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Save fields */
|
||||
displayTarget->display = display;
|
||||
displayTarget->firstWindow = NULL;
|
||||
displayTarget->relativeMouse = 0;
|
||||
displayTarget->ewmhSupport = -1;
|
||||
displayTarget->atomWmProtocols = X.InternAtom(display, "WM_PROTOCOLS", True);
|
||||
displayTarget->atomWmDeleteWindow = X.InternAtom(display, "WM_DELETE_WINDOW", False);
|
||||
memset(displayTarget->keymapBitvector, 0, sizeof(displayTarget->keymapBitvector));
|
||||
|
||||
/* XInput2: Verify that server supports XI2 (sets */
|
||||
#ifdef HAVE_XINPUT2
|
||||
if(XI2_IsLoaded())
|
||||
XI2_IsSupportedOnConnection(displayTarget);
|
||||
#endif
|
||||
|
||||
return (SST_DisplayTarget)displayTarget;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static size_t Xlib_GetDisplayTargetScreenCount(SST_DisplayTarget target)
|
||||
{
|
||||
(void)target;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_Window Xlib_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title)
|
||||
{
|
||||
SST_Window_Xlib* win;
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Window xwin;
|
||||
Display* display = displayTarget->display;
|
||||
int screen = DefaultScreen(display);
|
||||
SST_WMEvent* event;
|
||||
|
||||
/* Must be on screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
xwin = X.CreateSimpleWindow(display,
|
||||
RootWindow(display, screen),
|
||||
(int)x, (int)y,
|
||||
(int)width, (int)height,
|
||||
0, 0, /* border width/color */
|
||||
WhitePixel(display, screen)); /* background color */
|
||||
|
||||
/* Set window's WM_PROTOCOLS property */
|
||||
X.SetWMProtocols(display, xwin, &displayTarget->atomWmDeleteWindow, 1);
|
||||
|
||||
/* Set title bar text */
|
||||
X.StoreName(display, xwin, title);
|
||||
|
||||
/* Map the window to the screen */
|
||||
X.MapRaised(display, xwin);
|
||||
|
||||
/* Force the move, because some window managers just put windows wherever. Argh. */
|
||||
X.MoveWindow(display, xwin, (int)x, (int)y);
|
||||
|
||||
X.SelectInput(display, xwin, KeyPressMask| KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask);
|
||||
|
||||
/* Display it now */
|
||||
X.Flush(display);
|
||||
|
||||
/* Allocate SST window structure */
|
||||
win = (SST_Window_Xlib*)malloc(sizeof(SST_Window_Xlib));
|
||||
if(win == NULL)
|
||||
return NULL;
|
||||
|
||||
win->owner = displayTarget;
|
||||
win->next = displayTarget->firstWindow;
|
||||
win->xwin = xwin;
|
||||
win->lastX = (uint32_t)x;
|
||||
win->lastY = (uint32_t)y;
|
||||
win->lastWidth = (uint32_t)width;
|
||||
win->lastHeight = (uint32_t)height;
|
||||
win->isFullscreen = 0;
|
||||
win->softwareBackbuffer = NULL;
|
||||
win->softwareImage = NULL;
|
||||
win->softwarePitch = 0;
|
||||
|
||||
/* Link window as new root */
|
||||
displayTarget->firstWindow = win;
|
||||
|
||||
/* Add a SSTWMEVENT_CREATED event */
|
||||
event = AllocSlotInEQ(&displayTarget->eventQueue);
|
||||
if(event != NULL)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_CREATED;
|
||||
memset(&event->details, 0, sizeof(event->details));
|
||||
}
|
||||
|
||||
return (SST_Window)win;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Xlib_GetWindowDisplayTarget(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
return win->owner;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SetWindowText(SST_Window window, const char* titleBar)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
X.StoreName(win->owner->display, win->xwin, titleBar);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_GetWindowRect(SST_Window window, SST_Rect* rectReturn)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
Window dummyRoot;
|
||||
int x, y;
|
||||
unsigned int w, h;
|
||||
unsigned int dummy1, dummy2;
|
||||
|
||||
X.GetGeometry(win->owner->display, win->xwin, &dummyRoot, &x, &y, &w, &h, &dummy1, &dummy2);
|
||||
|
||||
rectReturn->x = (uint32_t)x;
|
||||
rectReturn->y = (uint32_t)y;
|
||||
rectReturn->width = (uint32_t)w;
|
||||
rectReturn->height = (uint32_t)h;
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* Only allow operations on screen 0 */
|
||||
if(screenIndex != SST_SAME_SCREEN && screenIndex != 0)
|
||||
return;
|
||||
|
||||
X.MoveWindow(win->owner->display, win->xwin, (int)x, (int)y);
|
||||
X.Sync(win->owner->display, False);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_ResizeWindow(SST_Window window, uint32_t width, uint32_t height)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
X.ResizeWindow(win->owner->display, win->xwin, width, height);
|
||||
X.Sync(win->owner->display, False);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
Display* display = win->owner->display;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTWS_SHOWN:
|
||||
{
|
||||
/* Map or unmap the window respectively */
|
||||
if(param == 0)
|
||||
X.UnmapWindow(display, win->xwin);
|
||||
else
|
||||
X.MapWindow(display, win->xwin);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Turn on/off resizeability */
|
||||
case SSTWS_RESIZEABLE:
|
||||
{
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_FULLSCREEN:
|
||||
{
|
||||
/* If we haven't yet checked for EWMH support, do so now */
|
||||
if(win->owner->ewmhSupport == -1)
|
||||
win->owner->ewmhSupport = ewmh_supported(win->owner, win);
|
||||
|
||||
/* Enabling fullscreen? */
|
||||
if(param && !win->isFullscreen)
|
||||
{
|
||||
|
||||
/* Use EWMH */
|
||||
if(win->owner->ewmhSupport != 0)
|
||||
ewmh_setFullscreen(win, 1);
|
||||
|
||||
win->isFullscreen = True;
|
||||
}
|
||||
else if(win->isFullscreen) /* Disabling fullscreen */
|
||||
{
|
||||
win->isFullscreen = False;
|
||||
|
||||
if(win->owner->ewmhSupport != 0)
|
||||
ewmh_setFullscreen(win, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_MINIMIZED:
|
||||
{
|
||||
if(param == 0) /* Maximize */
|
||||
X.MapRaised(display, win->xwin);
|
||||
else /* Minimize */
|
||||
X.IconifyWindow(display, win->xwin, DefaultScreen(display));
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
switch(state)
|
||||
{
|
||||
case SSTDTS_RELMOUSE:
|
||||
{
|
||||
#ifdef HAVE_XINPUT2
|
||||
XIEventMask eventmask;
|
||||
uint8_t maskBytes[3];
|
||||
|
||||
memset(maskBytes, 0, sizeof(maskBytes));
|
||||
|
||||
eventmask.deviceid = XIAllMasterDevices;
|
||||
eventmask.mask_len = sizeof(maskBytes);
|
||||
eventmask.mask = maskBytes;
|
||||
|
||||
if(!displayTarget->xi2Support)
|
||||
{
|
||||
printf("libsst-wm: XInput2 not supported; cannot use relative mouse mode.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disabling? */
|
||||
if(displayTarget->relativeMouse && param == 0)
|
||||
{
|
||||
displayTarget->relativeMouse = 0;
|
||||
}
|
||||
else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */
|
||||
{
|
||||
printf("libsst-wm: enabling XI2 raw motion\n");
|
||||
XISetMask(maskBytes, XI_RawMotion); /* Macro invocation */
|
||||
displayTarget->relativeMouse = 1;
|
||||
}
|
||||
|
||||
if(XI.SelectEvents(displayTarget->display, DefaultRootWindow(displayTarget->display), &eventmask, 1) == Success)
|
||||
printf("libsst-wm: relative mouse is %s!\n", param?"ON":"OFF");
|
||||
else
|
||||
printf("libsst-wm: failed to change relative mouse mode - XISelectEvents() returned failure\n");
|
||||
|
||||
#else
|
||||
printf("libsst-wm: XI2 not compiled in, cannot use relative mouse mode.");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyWindow(SST_Window window)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget;
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
SST_Window_Xlib* nextWin;
|
||||
|
||||
displayTarget = win->owner;
|
||||
nextWin = displayTarget->firstWindow;
|
||||
|
||||
/* Special case: root window */
|
||||
if(nextWin == win)
|
||||
{
|
||||
/* Set new root to be this->next */
|
||||
displayTarget->firstWindow = win->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
/* Check list */
|
||||
while(nextWin)
|
||||
{
|
||||
/* Did we find the window? */
|
||||
if(nextWin->next == win)
|
||||
{
|
||||
/* Remove this window from the linked list */
|
||||
nextWin->next = win->next;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
nextWin = nextWin->next;
|
||||
}
|
||||
|
||||
/* Don't destroy another display target's window */
|
||||
if(!found)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Actually destroy the window window */
|
||||
destroyWin(win);
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyDisplayTarget(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
SST_Window_Xlib* window = displayTarget->firstWindow;
|
||||
|
||||
/* Destroy all windows */
|
||||
while(window)
|
||||
{
|
||||
/* Save the next window */
|
||||
SST_Window_Xlib* next = window->next;
|
||||
|
||||
destroyWin(window);
|
||||
|
||||
/* Move to next window */
|
||||
window = next;
|
||||
}
|
||||
|
||||
DestroyEQ(&displayTarget->userEventQueue);
|
||||
DestroyEQ(&displayTarget->eventQueue);
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
X.CloseDisplay(displayTarget->display);
|
||||
|
||||
/* Free structures */
|
||||
free(displayTarget);
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void destroyWin(SST_Window_Xlib* win)
|
||||
{
|
||||
/* TODO Destroy more */
|
||||
|
||||
X.DestroyWindow(win->owner->display, win->xwin);
|
||||
free(win);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* Check if extended window manager hints are supported */
|
||||
static int ewmh_supported(SST_DisplayTarget_Xlib* displayTarget, SST_Window_Xlib* win)
|
||||
{
|
||||
Atom actions;
|
||||
Atom actionFullscreen;
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long nrItems;
|
||||
unsigned long bytesAfterReturn;
|
||||
unsigned long i;
|
||||
Atom* propReturn;
|
||||
int foundit = 0;
|
||||
Display* display = displayTarget->display;
|
||||
|
||||
actions = X.InternAtom(display, "_NET_WM_ALLOWED_ACTIONS", False);
|
||||
actionFullscreen = X.InternAtom(display, "_NET_WM_ACTION_FULLSCREEN", False);
|
||||
|
||||
/* Get a list of atoms */
|
||||
if(X.GetWindowProperty(display, win->xwin, actions, 0, 1024, False, XA_ATOM, &actualType,
|
||||
&format,
|
||||
&nrItems,
|
||||
&bytesAfterReturn,
|
||||
(unsigned char**)&propReturn) != Success)
|
||||
{
|
||||
/* Nope */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search through the list for the atom that matches the fullscreen atom */
|
||||
for(i=0; i<nrItems; i++)
|
||||
{
|
||||
if(propReturn[i] == actionFullscreen)
|
||||
{
|
||||
foundit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free atom list and return */
|
||||
X.Free(propReturn);
|
||||
|
||||
return foundit;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* Use extended window manager hints to set the window in/out of fullscreen mode */
|
||||
static void ewmh_setFullscreen(SST_Window_Xlib* win, int fullscreen)
|
||||
{
|
||||
XEvent event;
|
||||
Display* display = win->owner->display;
|
||||
|
||||
event.xclient.type = ClientMessage;
|
||||
event.xclient.serial = 0;
|
||||
event.xclient.send_event = True;
|
||||
event.xclient.display = display;
|
||||
event.xclient.window = win->xwin;
|
||||
event.xclient.message_type = X.InternAtom(display, "_NET_WM_STATE", False);
|
||||
event.xclient.format = 32;
|
||||
event.xclient.data.l[0] = fullscreen;
|
||||
event.xclient.data.l[1] = X.InternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
event.xclient.data.l[2] = 0;
|
||||
event.xclient.data.l[3] = 0;
|
||||
event.xclient.data.l[4] = 0;
|
||||
|
||||
X.SendEvent(display, DefaultRootWindow(display), False, StructureNotifyMask | ResizeRedirectMask, &event);
|
||||
}
|
||||
|
||||
extern int Xlib_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons);
|
||||
|
||||
const struct SST_WM_WindowFuncs Xlib_WindowFuncs = {
|
||||
Xlib_CreateDisplayTarget,
|
||||
Xlib_GetDisplayTargetScreenCount,
|
||||
Xlib_CreateWindowOnScreen,
|
||||
Xlib_GetWindowDisplayTarget,
|
||||
Xlib_SetWindowText,
|
||||
Xlib_GetWindowRect,
|
||||
Xlib_MoveWindowOnScreen,
|
||||
Xlib_ResizeWindow,
|
||||
Xlib_ShowDialogBox,
|
||||
Xlib_SetWindowState,
|
||||
Xlib_SetDisplayTargetState,
|
||||
Xlib_DestroyWindow,
|
||||
Xlib_DestroyDisplayTarget
|
||||
};
|
||||
|
||||
83
libsst-wm/Xlib/XI2Private.c
Normal file
83
libsst-wm/Xlib/XI2Private.c
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
#include <dlfcn.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
|
||||
XI2Functions XI = { 0 };
|
||||
|
||||
void XI2_Load()
|
||||
{
|
||||
const int flags = RTLD_LAZY | RTLD_GLOBAL;
|
||||
void* XI2lib;
|
||||
|
||||
/* Try opening the correct SONAME version of libXi */
|
||||
XI2lib = dlopen("libXi.so.6", flags);
|
||||
|
||||
/* Didn't work? */
|
||||
if(XI2lib == NULL)
|
||||
{
|
||||
/* Try a super-generic version */
|
||||
XI2lib = dlopen("libXi.so", flags);
|
||||
if(XI2lib == NULL)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Resolve symbols */
|
||||
XI.SelectEvents = dlsym(XI2lib, "XISelectEvents");
|
||||
XI.QueryVersion = dlsym(XI2lib, "XIQueryVersion");
|
||||
|
||||
if(XI.SelectEvents == NULL || XI.QueryVersion == NULL)
|
||||
{
|
||||
dlclose(XI2lib);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Save handle */
|
||||
XI.XI2lib = XI2lib;
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void XI2_Unload()
|
||||
{
|
||||
if(XI.XI2lib != NULL)
|
||||
dlclose(XI.XI2lib);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int XI2_IsLoaded()
|
||||
{
|
||||
return (XI.XI2lib != NULL);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void XI2_IsSupportedOnConnection(SST_DisplayTarget_Xlib* displayTarget)
|
||||
{
|
||||
int major = 2, minor = 0;
|
||||
int dummyEvent, dummyError;
|
||||
|
||||
/* Default to NO */
|
||||
displayTarget->xi2Support = 0;
|
||||
displayTarget->xi2opcode = ~0;
|
||||
|
||||
/* Check if server has XI at all. */
|
||||
if(X.QueryExtension(displayTarget->display, "XInputExtension", &displayTarget->xi2opcode, &dummyEvent, &dummyError))
|
||||
{
|
||||
/* OK, does it support XI2? */
|
||||
XI.QueryVersion(displayTarget->display, &major, &minor);
|
||||
|
||||
/* If the version is at least 2.0, we're good */
|
||||
if(major * 100 + minor >= 200) {
|
||||
displayTarget->xi2Support = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
60
libsst-wm/Xlib/XI2Private.h
Normal file
60
libsst-wm/Xlib/XI2Private.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
XI2Private.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 5/13/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Private definitions and functions for XInput2 portion of Xlib driver. XI2 support
|
||||
is optional, but most systems that run a recent version of X will have it.
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#ifndef _XI2PRIVATE_H
|
||||
#define _XI2PRIVATE_H
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef Status (*pf_XISelectEvents)(Display* display, Window win, XIEventMask* masks, int num_masks);
|
||||
typedef Status (*pf_XIQueryVersion)(Display *display, int *major_version_inout, int *minor_version_inout);
|
||||
|
||||
/** Structure describing XInput2 functions used */
|
||||
typedef struct XI2Functions {
|
||||
pf_XISelectEvents SelectEvents;
|
||||
pf_XIQueryVersion QueryVersion;
|
||||
void* XI2lib;
|
||||
} XI2Functions;
|
||||
|
||||
extern XI2Functions XI;
|
||||
|
||||
struct SST_DisplayTarget_Xlib;
|
||||
|
||||
/* Attempt to load XInput2 library */
|
||||
void XI2_Load();
|
||||
|
||||
/* Check if XInput2 library was successfully loaded (X server may not support it though) */
|
||||
int XI2_IsLoaded();
|
||||
|
||||
/* Unload XInput2 library */
|
||||
void XI2_Unload();
|
||||
|
||||
/* Check if the connection to the X server supports XInput2. */
|
||||
void XI2_IsSupportedOnConnection(struct SST_DisplayTarget_Xlib* displayTarget);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
76
libsst-wm/Xlib/XlibDriver.c
Normal file
76
libsst-wm/Xlib/XlibDriver.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
XlibDriver.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 5/14/2014
|
||||
|
||||
Purpose:
|
||||
|
||||
Xlib driver for libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "APIPrivate.h"
|
||||
#include "XlibPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
#include "GLXPrivate.h"
|
||||
|
||||
extern const struct SST_WM_WindowFuncs Xlib_WindowFuncs;
|
||||
extern const struct SST_WM_EnumFuncs Xlib_EnumFuncs;
|
||||
extern const struct SST_WM_EventFuncs Xlib_EventFuncs;
|
||||
extern const struct SST_WM_OpenGLFuncs Xlib_OpenGLFuncs;
|
||||
extern const struct SST_WM_RenderFuncs Xlib_RenderFuncs;
|
||||
extern const struct SST_WM_VideoModeFuncs Xlib_VideoModeFuncs;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Xlib_init()
|
||||
{
|
||||
if(getenv("LIBSST_NO_XLIB"))
|
||||
return 0;
|
||||
|
||||
if(loadXlib() == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
XI2_Load(); /* may fail, but that's OK */
|
||||
#endif
|
||||
|
||||
|
||||
loadGLX();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_shutdown()
|
||||
{
|
||||
#ifdef HAVE_XINPUT2
|
||||
XI2_Unload();
|
||||
#endif
|
||||
|
||||
unloadGLX();
|
||||
|
||||
unloadXlib();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const struct SST_WM_Driver XlibDriver = {
|
||||
"Xlib Driver",
|
||||
Xlib_init,
|
||||
Xlib_shutdown,
|
||||
&Xlib_WindowFuncs,
|
||||
&Xlib_EnumFuncs,
|
||||
&Xlib_EventFuncs,
|
||||
&Xlib_OpenGLFuncs,
|
||||
&Xlib_RenderFuncs,
|
||||
&Xlib_VideoModeFuncs
|
||||
};
|
||||
91
libsst-wm/Xlib/XlibPrivate.c
Normal file
91
libsst-wm/Xlib/XlibPrivate.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
XlibPrivate.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Private defintions and functions for Xlib implementation of libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
XlibFunctions X;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int loadXlib()
|
||||
{
|
||||
const int flags = RTLD_LAZY | RTLD_GLOBAL;
|
||||
void* xlib;
|
||||
|
||||
X.xlib = NULL;
|
||||
|
||||
/* Try opening the correct SONAME version of libX11 */
|
||||
xlib = dlopen("libX11.so.6", flags);
|
||||
|
||||
/* Didn't work? */
|
||||
if(xlib == NULL)
|
||||
{
|
||||
/* Try a super-generic version */
|
||||
xlib = dlopen("libX11.so", flags);
|
||||
if(xlib == NULL)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Resolve symbols */
|
||||
X.OpenDisplay = dlsym(xlib, "XOpenDisplay");
|
||||
X.CloseDisplay = dlsym(xlib, "XCloseDisplay");
|
||||
X.MoveWindow = dlsym(xlib, "XMoveWindow");
|
||||
X.ResizeWindow = dlsym(xlib, "XResizeWindow");
|
||||
X.MapRaised = dlsym(xlib, "XMapRaised");
|
||||
X.MapWindow = dlsym(xlib, "XMapWindow");
|
||||
X.UnmapWindow = dlsym(xlib, "XUnmapWindow");
|
||||
X.StoreName = dlsym(xlib, "XStoreName");
|
||||
X.DestroyWindow = dlsym(xlib, "XDestroyWindow");
|
||||
X.CreateSimpleWindow = dlsym(xlib, "XCreateSimpleWindow");
|
||||
X.GetGeometry = dlsym(xlib, "XGetGeometry");
|
||||
X.GetWindowProperty = dlsym(xlib,"XGetWindowProperty");
|
||||
X.Pending = dlsym(xlib, "XPending");
|
||||
X.NextEvent = dlsym(xlib, "XNextEvent");
|
||||
X.PeekEvent = dlsym(xlib, "XPeekEvent");
|
||||
X.SendEvent = dlsym(xlib, "XSendEvent");
|
||||
X.Flush = dlsym(xlib, "XFlush");
|
||||
X.Sync = dlsym(xlib, "XSync");
|
||||
X.InternAtom = dlsym(xlib, "XInternAtom");
|
||||
X.SetWMProtocols = dlsym(xlib, "XSetWMProtocols");
|
||||
X.IconifyWindow = dlsym(xlib, "XIconifyWindow");
|
||||
X.Free = dlsym(xlib, "XFree");
|
||||
X.SelectInput = dlsym(xlib, "XSelectInput");
|
||||
X.LookupString = dlsym(xlib, "XLookupString");
|
||||
X.QueryKeymap = dlsym(xlib, "XQueryKeymap");
|
||||
X.QueryExtension = dlsym(xlib, "XQueryExtension");
|
||||
X.GetEventData = dlsym(xlib, "XGetEventData");
|
||||
X.FreeEventData = dlsym(xlib, "XFreeEventData");
|
||||
|
||||
|
||||
/* Save handle */
|
||||
X.xlib = xlib;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void unloadXlib()
|
||||
{
|
||||
if(X.xlib != NULL)
|
||||
dlclose(X.xlib);
|
||||
}
|
||||
|
||||
186
libsst-wm/Xlib/XlibPrivate.h
Normal file
186
libsst-wm/Xlib/XlibPrivate.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
XlibPrivate.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _XLIBPRIVATE_H
|
||||
#define _XLIBPRIVATE_H
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <SST/SST_WMTypes.h>
|
||||
#include "EventQueue.h"
|
||||
#include "GLXPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
|
||||
#define MIN_BPP 16 /* Minimum BPP for a mode to be considered. Some embedded systems use 16-bit color to save memory, so accept those too. */
|
||||
|
||||
/* XGenericEventCookie is required for XI2, but not present on Solaris 10, so fake it*/
|
||||
#if defined(__sun) && !defined(HAVE_XINPUT2)
|
||||
typedef void XGenericEventCookie;
|
||||
#endif
|
||||
|
||||
/* Xlib C API */
|
||||
typedef Display* (*pf_XOpenDisplay)(const char* s);
|
||||
typedef void (*pf_XCloseDisplay)(Display* dpy);
|
||||
typedef int (*pf_XMoveWindow)(Display* dpy, Window w, int x, int y);
|
||||
typedef int (*pf_XResizeWindow)(Display* dpy, Window w, unsigned int x, unsigned int y);
|
||||
typedef int (*pf_XMapRaised)(Display* dpy, Window w);
|
||||
typedef int (*pf_XMapWindow)(Display* dpy, Window w);
|
||||
typedef int (*pf_XUnmapWindow)(Display* dpy, Window w);
|
||||
typedef int (*pf_XStoreName)(Display* dpy, Window w, const char* windowName);
|
||||
typedef int (*pf_XDestroyWindow)(Display* dpy, Window w);
|
||||
typedef Window (*pf_XCreateSimpleWindow)(Display*, Window parent, int x, int y, unsigned int w, unsigned int h, unsigned int borderWidth, unsigned long border, unsigned long background);
|
||||
typedef Status (*pf_XGetGeometry)(Display* display, Drawable d, Window* root_return, int* x_return, int* y_return, unsigned int* width_return, unsigned int* height_return, unsigned int* border_width_return, unsigned int* depth_return);
|
||||
typedef int (*pf_XGetWindowProperty)(Display *display, Window w, Atom property, long long_offset, long long_length, Bool _delete, Atom req_type, Atom* actual_type_return, int* actual_format_return, unsigned long* nitems_return, unsigned long* bytes_after_return, unsigned char** prop_return);
|
||||
typedef int (*pf_XPending)(Display* display);
|
||||
typedef int (*pf_XNextEvent)(Display* display, XEvent* event_return);
|
||||
typedef int (*pf_XPeekEvent)(Display* display, XEvent* event_return);
|
||||
typedef Status (*pf_XSendEvent)(Display *display, Window w, Bool propagate, long event_mask, XEvent *event_send);
|
||||
typedef int (*pf_XFlush)(Display* display);
|
||||
typedef int (*pf_XSync)(Display* display, Bool discard);
|
||||
typedef Atom (*pf_XInternAtom)(Display* display, const char* name, Bool create);
|
||||
typedef Status (*pf_XSetWMProtocols)(Display* display, Window w, Atom* protocols, int count);
|
||||
typedef Status (*pf_XIconifyWindow)(Display* display, Window w, int screen_number);
|
||||
typedef void (*pf_XFree)(void*);
|
||||
typedef int (*pf_XSelectInput)(Display* display, Window w, long event_mask);
|
||||
typedef int (*pf_XLookupString)(XKeyEvent* event_struct, char* buffer_return, int bytes_buffer, KeySym* keysym_return, XComposeStatus* status_in_out);
|
||||
typedef int (*pf_XQueryKeymap)(Display *display, char keys_return[32]);
|
||||
typedef Bool (*pf_XQueryExtension)(Display* display, const char* name, int* major_opcode_return, int* first_event_return, int* first_error_return);
|
||||
typedef Bool (*pf_XGetEventData)(Display *display, XGenericEventCookie *cookie);
|
||||
typedef void (*pf_XFreeEventData)(Display *display, XGenericEventCookie *cookie);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct XlibFunctions
|
||||
{
|
||||
pf_XOpenDisplay OpenDisplay;
|
||||
pf_XCloseDisplay CloseDisplay;
|
||||
pf_XMoveWindow MoveWindow;
|
||||
pf_XResizeWindow ResizeWindow;
|
||||
pf_XMapRaised MapRaised;
|
||||
pf_XMapWindow MapWindow;
|
||||
pf_XUnmapWindow UnmapWindow;
|
||||
pf_XStoreName StoreName;
|
||||
pf_XDestroyWindow DestroyWindow;
|
||||
pf_XCreateSimpleWindow CreateSimpleWindow;
|
||||
pf_XGetGeometry GetGeometry;
|
||||
pf_XGetWindowProperty GetWindowProperty;
|
||||
pf_XPending Pending;
|
||||
pf_XNextEvent NextEvent;
|
||||
pf_XPeekEvent PeekEvent;
|
||||
pf_XSendEvent SendEvent;
|
||||
pf_XFlush Flush;
|
||||
pf_XSync Sync;
|
||||
pf_XInternAtom InternAtom;
|
||||
pf_XSetWMProtocols SetWMProtocols;
|
||||
pf_XIconifyWindow IconifyWindow;
|
||||
pf_XFree Free;
|
||||
pf_XSelectInput SelectInput;
|
||||
pf_XLookupString LookupString;
|
||||
pf_XQueryKeymap QueryKeymap;
|
||||
pf_XQueryExtension QueryExtension;
|
||||
pf_XGetEventData GetEventData;
|
||||
pf_XFreeEventData FreeEventData;
|
||||
|
||||
void* xlib;
|
||||
} XlibFunctions;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_GraphicsEnumerator_Xlib
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t bpp;
|
||||
} SST_GraphicsEnumerator_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct SST_Window_Xlib;
|
||||
|
||||
typedef struct SST_DisplayTarget_Xlib
|
||||
{
|
||||
EventQueue eventQueue;
|
||||
uint8_t keymapBitvector[32]; /* Bitmap similar to XQueryKeymap() */
|
||||
pthread_mutex_t eventLock; /* Lock protecting user events, since they may be freely added by other threads */
|
||||
EventQueue userEventQueue;
|
||||
Display* display;
|
||||
struct SST_Window_Xlib* firstWindow;
|
||||
int relativeMouse; /* Is relative mouse move enabled? */
|
||||
int ewmhSupport; /* Extended WM Hints, -1: not checked, 0: not supported, else: supported */
|
||||
int xi2Support; /* XInput2 support, -1: not checked, 0: not supported, else: supported */
|
||||
int xi2opcode; /* XI2 opcode */
|
||||
Atom atomWmProtocols;
|
||||
Atom atomWmDeleteWindow;
|
||||
} SST_DisplayTarget_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_Window_Xlib
|
||||
{
|
||||
struct SST_Window_Xlib* next;
|
||||
SST_DisplayTarget_Xlib* owner;
|
||||
Window xwin;
|
||||
int isFullscreen;
|
||||
|
||||
/* Because configure requests cover a wide variety of events,
|
||||
keep these "last" parameters to check if an event actually occured */
|
||||
int lastX, lastY;
|
||||
int lastWidth, lastHeight;
|
||||
|
||||
/* Software rendering support */
|
||||
XImage* softwareImage;
|
||||
void* softwareBackbuffer;
|
||||
uint32_t softwarePitch;
|
||||
} SST_Window_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_OpenGLContext_Xlib
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget;
|
||||
uint16_t ctxVersion[2]; /* context version major/minor */
|
||||
|
||||
|
||||
/* GLX Fields */
|
||||
int legacyEnabled; /* Did we use legacy GLX (< 1.4) context support? */
|
||||
GLXContext glxcontext;
|
||||
GLXFunctions glX;
|
||||
Window win; /* Window context is bound to */
|
||||
|
||||
/* EGL fields */
|
||||
|
||||
} SST_OpenGLContext_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
extern XlibFunctions X;
|
||||
|
||||
int loadXlib();
|
||||
void unloadXlib();
|
||||
|
||||
#endif
|
||||
32
libsst-wm/Xlib/sources.mk
Normal file
32
libsst-wm/Xlib/sources.mk
Normal file
@@ -0,0 +1,32 @@
|
||||
# libsst-wm/Xlib/sources.mk
|
||||
# Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
# Created: 1/8/2013
|
||||
#
|
||||
# Purpose:
|
||||
#
|
||||
# List of source files for X Windows systems
|
||||
#
|
||||
# License:
|
||||
#
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
ifeq ($(findstring -DHAVE_XLIB,$(CFLAGS)),-DHAVE_XLIB)
|
||||
SRC += \
|
||||
Xlib/SST_WMDialogBox_Xlib.c \
|
||||
Xlib/SST_WMEnum_Xlib.c \
|
||||
Xlib/SST_WMEvent_Xlib.c \
|
||||
Xlib/SST_WMOpenGL_Xlib.c \
|
||||
Xlib/SST_WMNonPortable_Xlib.c \
|
||||
Xlib/SST_WMVideoMode_Xlib.c \
|
||||
Xlib/SST_WMRender_Xlib.c \
|
||||
Xlib/SST_WMWindow_Xlib.c \
|
||||
Xlib/XlibPrivate.c \
|
||||
Xlib/GLXPrivate.c \
|
||||
Xlib/XI2Private.c \
|
||||
Xlib/XlibDriver.c
|
||||
|
||||
endif
|
||||
Reference in New Issue
Block a user