Initial commit

This commit is contained in:
2026-04-03 00:22:39 -05:00
commit eca1e8c458
945 changed files with 218160 additions and 0 deletions

374
libsst-wm/Xlib/GLXPrivate.c Normal file
View 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;
}

View 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

View 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;
}

View 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
};

View 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
};

View 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;
}

View 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
};

View 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
};

View 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
};

View 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
};

View 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

View 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

View 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
};

View 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);
}

View 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
View 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