6 Commits

Author SHA1 Message Date
Jarcode
869ebba6b4 Added dynamic symbol loading for GLX functions, closes #41 2018-04-06 17:02:43 -07:00
Jarcode
dfd16f9e22 Properly compare desktop window types, closes #37 2018-03-19 21:45:19 -07:00
Jarcode
b446ac99c9 Fixed resource leak associated with xlib usage, see #33 2018-03-18 22:01:03 -07:00
Jarcode
8024e308d8 fixed some code style issues 2018-03-18 17:27:36 -07:00
Jarcode
dd5586a76e cleaning up comment formatting & spelling 2018-03-18 17:23:45 -07:00
Jarcode
20e755fbcb Switched to using git tags for versioning 2018-03-18 17:00:14 -07:00
8 changed files with 216 additions and 43 deletions

View File

@@ -45,7 +45,7 @@ endif
ifndef DISABLE_GLX
CFLAGS_GLX = -DGLAVA_GLX
LDFLAGS_GLX = -lGLX -lXrender
LDFLAGS_GLX = -lXrender
endif
ifeq ($(INSTALL),osx)
@@ -57,10 +57,15 @@ LDFLAGS += $(ASAN) -lpulse -lpulse-simple -pthread $(LDFLAGS_GLFW) -ldl -lm -lX1
PYTHON = python
GLAVA_VERSION = \"$(shell git describe --tags 2>/dev/null)\"
ifeq ($(GLAVA_VERSION),\"\")
GLAVA_VERSION = \"unknown\"
endif
GLAD_INSTALL_DIR = glad
GLAD_SRCFILE = ./glad/src/glad.c
GLAD_ARGS = --generator=$(GLAD_GEN) --extensions=GL_EXT_framebuffer_multisample,GL_EXT_texture_filter_anisotropic
CFLAGS_COMMON = -I glad/include
CFLAGS_COMMON = -I glad/include -DGLAVA_VERSION="$(GLAVA_VERSION)"
CFLAGS_USE = $(CFLAGS_COMMON) $(CFLAGS_GLX) $(CFLAGS_GLFW) $(CFLAGS_BUILD) $(CFLAGS_INSTALL) $(CFLAGS)
all: glava

View File

@@ -27,7 +27,6 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
- glad (included as a submodule)
- python (required to generate bindings with glad)
- GCC (this program uses GNU C features)
- GLX headers (optional, disable direct GLX support with `DISABLE_GLX=1`), usually the development packages for `libgl` include this on your distro
**Ubuntu/Debian users:** the following command ensures you have all the needed packages and headers to compile GLava:
```bash

2
glad

Submodule glad updated: 0a146b6723...ec01ac515d

View File

@@ -18,7 +18,6 @@
#include "render.h"
#include "xwin.h"
#define GLAVA_VERSION "1.4.3"
#ifdef GLAD_DEBUG
#define GLAVA_RELEASE_TYPE_PREFIX "debug, "
#else
@@ -272,7 +271,8 @@ int main(int argc, char** argv) {
pthread_mutex_lock(&audio.mutex);
modified = audio.modified;
if (modified) {
/* create our own copies of the audio buffers, so the streaming thread can continue to append to it */
/* create our own copies of the audio buffers, so the streaming
thread can continue to append to it */
memcpy(lb, (void*) audio.audio_out_l, r->bufsize_request * sizeof(float));
memcpy(rb, (void*) audio.audio_out_r, r->bufsize_request * sizeof(float));
audio.modified = false; /* set this flag to false until the next time we read */

167
glx_wcb.c
View File

@@ -13,22 +13,154 @@
#include <math.h>
#include <time.h>
#include <dlfcn.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/shape.h>
#include <X11/Xatom.h>
#include <glad/glad.h>
#include <GL/glx.h>
#include "render.h"
#include "xwin.h"
typedef struct __GLXcontextRec *GLXContext;
typedef XID GLXPixmap;
typedef XID GLXDrawable;
typedef void (*__GLXextFuncPtr)(void);
/* GLX 1.3 and later */
typedef struct __GLXFBConfigRec *GLXFBConfig;
typedef XID GLXFBConfigID;
typedef XID GLXContextID;
typedef XID GLXWindow;
typedef XID GLXPbuffer;
/*
* Tokens for glXChooseVisual and glXGetConfig:
*/
#define GLX_USE_GL 1
#define GLX_BUFFER_SIZE 2
#define GLX_LEVEL 3
#define GLX_RGBA 4
#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_ACCUM_RED_SIZE 14
#define GLX_ACCUM_GREEN_SIZE 15
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_ALPHA_SIZE 17
/*
* Error codes returned by glXGetConfig:
*/
#define GLX_BAD_SCREEN 1
#define GLX_BAD_ATTRIBUTE 2
#define GLX_NO_EXTENSION 3
#define GLX_BAD_VISUAL 4
#define GLX_BAD_CONTEXT 5
#define GLX_BAD_VALUE 6
#define GLX_BAD_ENUM 7
/*
* GLX 1.1 and later:
*/
#define GLX_VENDOR 1
#define GLX_VERSION 2
#define GLX_EXTENSIONS 3
/*
* GLX 1.3 and later:
*/
#define GLX_CONFIG_CAVEAT 0x20
#define GLX_DONT_CARE 0xFFFFFFFF
#define GLX_X_VISUAL_TYPE 0x22
#define GLX_TRANSPARENT_TYPE 0x23
#define GLX_TRANSPARENT_INDEX_VALUE 0x24
#define GLX_TRANSPARENT_RED_VALUE 0x25
#define GLX_TRANSPARENT_GREEN_VALUE 0x26
#define GLX_TRANSPARENT_BLUE_VALUE 0x27
#define GLX_TRANSPARENT_ALPHA_VALUE 0x28
#define GLX_WINDOW_BIT 0x00000001
#define GLX_PIXMAP_BIT 0x00000002
#define GLX_PBUFFER_BIT 0x00000004
#define GLX_AUX_BUFFERS_BIT 0x00000010
#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001
#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002
#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008
#define GLX_DEPTH_BUFFER_BIT 0x00000020
#define GLX_STENCIL_BUFFER_BIT 0x00000040
#define GLX_ACCUM_BUFFER_BIT 0x00000080
#define GLX_NONE 0x8000
#define GLX_SLOW_CONFIG 0x8001
#define GLX_TRUE_COLOR 0x8002
#define GLX_DIRECT_COLOR 0x8003
#define GLX_PSEUDO_COLOR 0x8004
#define GLX_STATIC_COLOR 0x8005
#define GLX_GRAY_SCALE 0x8006
#define GLX_STATIC_GRAY 0x8007
#define GLX_TRANSPARENT_RGB 0x8008
#define GLX_TRANSPARENT_INDEX 0x8009
#define GLX_VISUAL_ID 0x800B
#define GLX_SCREEN 0x800C
#define GLX_NON_CONFORMANT_CONFIG 0x800D
#define GLX_DRAWABLE_TYPE 0x8010
#define GLX_RENDER_TYPE 0x8011
#define GLX_X_RENDERABLE 0x8012
#define GLX_FBCONFIG_ID 0x8013
#define GLX_RGBA_TYPE 0x8014
#define GLX_COLOR_INDEX_TYPE 0x8015
#define GLX_MAX_PBUFFER_WIDTH 0x8016
#define GLX_MAX_PBUFFER_HEIGHT 0x8017
#define GLX_MAX_PBUFFER_PIXELS 0x8018
#define GLX_PRESERVED_CONTENTS 0x801B
#define GLX_LARGEST_PBUFFER 0x801C
#define GLX_WIDTH 0x801D
#define GLX_HEIGHT 0x801E
#define GLX_EVENT_MASK 0x801F
#define GLX_DAMAGED 0x8020
#define GLX_SAVED 0x8021
#define GLX_WINDOW 0x8022
#define GLX_PBUFFER 0x8023
#define GLX_PBUFFER_HEIGHT 0x8040
#define GLX_PBUFFER_WIDTH 0x8041
#define GLX_RGBA_BIT 0x00000001
#define GLX_COLOR_INDEX_BIT 0x00000002
#define GLX_PBUFFER_CLOBBER_MASK 0x08000000
/*
* GLX 1.4 and later:
*/
#define GLX_SAMPLE_BUFFERS 0x186a0 /*100000*/
#define GLX_SAMPLES 0x186a1 /*100001*/
/* glXCreateContextAttribsARB extension definitions */
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
typedef void (*glXSwapIntervalEXTProc) (Display*, GLXDrawable, int);
GLXFBConfig* (*glXChooseFBConfig) (Display* dpy, int screen, const int* attribList, int* nitems);
XVisualInfo* (*glXGetVisualFromFBConfig)(Display* dpy, GLXFBConfig config);
int (*glXGetFBConfigAttrib) (Display* dpy, GLXFBConfig config, int attribute, int *value );
Bool (*glXMakeCurrent) (Display* dpy, GLXDrawable drawable, GLXContext ctx);
GLXDrawable (*glXGetCurrentDrawable) (void);
__GLXextFuncPtr (*glXGetProcAddressARB) (const GLubyte *);
void (*glXSwapBuffers) (Display* dpy, GLXDrawable drawable);
extern struct gl_wcb wcb_glx;
static Display* display;
@@ -55,6 +187,39 @@ static void init(void) {
focused = false;
maximized = false;
transparent = false;
void* hgl = dlopen("libGL.so", RTLD_LAZY);
void* hglx = dlopen("libGLX.so", RTLD_LAZY);
if (!hgl && !hglx) {
fprintf(stderr, "Failed to load GLX functions (libGL and libGLX do not exist!)\n");
exit(EXIT_FAILURE);
}
/* Depending on the graphics driver, the GLX functions that we need may either be in libGL or
libGLX. */
void* resolve_f(const char* symbol) {
void* s = NULL;
if (hgl) s = dlsym(hgl, symbol);
if (!s && hglx) s = dlsym(hglx, symbol);
if (!s) {
fprintf(stderr, "Failed to resolve GLX symbol: `%s`\n", symbol);
exit(EXIT_FAILURE);
}
return s;
}
#define resolve(name) do { name = (typeof(name)) resolve_f(#name); } while (0)
resolve(glXChooseFBConfig);
resolve(glXGetVisualFromFBConfig);
resolve(glXGetFBConfigAttrib);
resolve(glXMakeCurrent);
resolve(glXGetCurrentDrawable);
resolve(glXGetProcAddressARB);
resolve(glXSwapBuffers);
#undef resolve
}
static void apply_decorations(Window w) {

View File

@@ -9,22 +9,22 @@
#include "fifo.h"
static pa_mainloop *m_pulseaudio_mainloop;
static pa_mainloop* m_pulseaudio_mainloop;
static void cb(__attribute__((unused)) pa_context *pulseaudio_context,
const pa_server_info *i,
void *userdata) {
static void cb(__attribute__((unused)) pa_context* pulseaudio_context,
const pa_server_info* i,
void* userdata) {
//getting default sink name
struct audio_data *audio = (struct audio_data *)userdata;
/* Obtain default sink name */
struct audio_data* audio = (struct audio_data*) userdata;
audio->source = malloc(sizeof(char) * 1024);
strcpy(audio->source,i->default_sink_name);
//appending .monitor suffix
/* Append `.monitor` suffix */
audio->source = strcat(audio->source, ".monitor");
//quiting mainloop
/* Quiting mainloop */
pa_context_disconnect(pulseaudio_context);
pa_context_unref(pulseaudio_context);
pa_mainloop_quit(m_pulseaudio_mainloop, 0);
@@ -32,10 +32,9 @@ static void cb(__attribute__((unused)) pa_context *pulseaudio_context,
}
static void pulseaudio_context_state_callback(pa_context *pulseaudio_context,
void *userdata) {
static void pulseaudio_context_state_callback(pa_context* pulseaudio_context, void* userdata) {
// make sure loop is ready
/* Ensure loop is ready */
switch (pa_context_get_state(pulseaudio_context))
{
case PA_CONTEXT_UNCONNECTED:
@@ -54,7 +53,6 @@ static void pulseaudio_context_state_callback(pa_context *pulseaudio_context,
exit(EXIT_FAILURE);
break;
case PA_CONTEXT_TERMINATED:
// printf("PulseAudio context terminated!\n");
pa_mainloop_quit(m_pulseaudio_mainloop, 0);
break;
}
@@ -63,29 +61,29 @@ static void pulseaudio_context_state_callback(pa_context *pulseaudio_context,
void get_pulse_default_sink(struct audio_data* audio) {
pa_mainloop_api *mainloop_api;
pa_context *pulseaudio_context;
pa_mainloop_api* mainloop_api;
pa_context* pulseaudio_context;
int ret;
// Create a mainloop API and connection to the default server
/* Create a mainloop API and connection to the default server */
m_pulseaudio_mainloop = pa_mainloop_new();
mainloop_api = pa_mainloop_get_api(m_pulseaudio_mainloop);
pulseaudio_context = pa_context_new(mainloop_api, "glava device list");
// This function connects to the pulse server
/* Connect to the PA server */
pa_context_connect(pulseaudio_context, NULL, PA_CONTEXT_NOFLAGS,
NULL);
// This function defines a callback so the server will tell us its state.
/* Define a callback so the server will tell us its state */
pa_context_set_state_callback(pulseaudio_context,
pulseaudio_context_state_callback,
(void*)audio);
// starting a mainloop to get default sink
/* Start mainloop to get default sink */
// starting with one non blokng iteration in case pulseaudio is not able to run
/* Start with one non blocking iteration in case pulseaudio is not able to run */
if (!(ret = pa_mainloop_iterate(m_pulseaudio_mainloop, 0, &ret))){
printf("Could not open pulseaudio mainloop to "
"find default device name: %d\n"
@@ -114,12 +112,11 @@ void get_pulse_default_sink(struct audio_data* audio) {
#endif
void* input_pulse(void* data) {
struct audio_data *audio = (struct audio_data *)data;
struct audio_data* audio = (struct audio_data*) data;
int i, n;
size_t ssz = audio->sample_sz;
float buf[ssz / 2];
/* The sample type to use */
const pa_sample_spec ss = {
.format = FSAMPLE_FORMAT,
.rate = audio->rate,
@@ -129,10 +126,10 @@ void* input_pulse(void* data) {
.maxlength = ssz * 2,
.fragsize = ssz
};
pa_simple *s = NULL;
pa_simple* s = NULL;
int error;
if (!(s = pa_simple_new(NULL, "glava", PA_STREAM_RECORD,
audio->source, "audio for glava",
&ss, NULL, &pb, &error))) {
@@ -141,13 +138,13 @@ void* input_pulse(void* data) {
audio->source, pa_strerror(error));
exit(EXIT_FAILURE);
}
n = 0;
float* bl = (float*) audio->audio_out_l;
float* br = (float*) audio->audio_out_r;
size_t fsz = audio->audio_buf_sz;
while (1) {
/* Record some data ... */
@@ -163,17 +160,17 @@ void* input_pulse(void* data) {
memmove(bl, &bl[ssz / 4], (fsz - (ssz / 4)) * sizeof(float));
memmove(br, &br[ssz / 4], (fsz - (ssz / 4)) * sizeof(float));
// sorting out channelss
/* sorting out channels */
for (n = 0, i = 0; i < ssz / 2; i += 2) {
// size_t idx = (i / 2) + (at * (BUFSIZE / 2));
/* size_t idx = (i / 2) + (at * (BUFSIZE / 2)); */
int idx = (fsz - (ssz / 4)) + n;
if (audio->channels == 1) bl[idx] = (buf[i] + buf[i + 1]) / 2;
// stereo storing channels in buffer
/* stereo storing channels in buffer */
if (audio->channels == 2) {
bl[idx] = buf[i];
br[idx] = buf[i + 1];
@@ -183,7 +180,7 @@ void* input_pulse(void* data) {
audio->modified = true;
pthread_mutex_unlock(&audio->mutex);
if (audio->terminate == 1) {
pa_simple_free(s);
break;

View File

@@ -651,7 +651,7 @@ void transform_fft(struct gl_data* d, void** _, void* in) {
}
mmax=istep;
}
/* abs and log scale */
for (n = 0; n < s->sz; ++n) {
if (data[n] < 0.0F) data[n] = -data[n];

13
xwin.c
View File

@@ -67,7 +67,7 @@ bool xwin_should_render(struct renderer* rd) {
Atom actual_type;
int actual_format, t;
unsigned long nitems, bytes_after;
unsigned char* data;
unsigned char* data = NULL;
int handler(Display* d, XErrorEvent* e) { return 0; }
@@ -77,7 +77,7 @@ bool xwin_should_render(struct renderer* rd) {
&actual_type, &actual_format, &nitems, &bytes_after, &data)) {
goto close; /* if an error occurs here, the WM probably isn't EWMH compliant */
}
if (!nitems)
goto close;
@@ -85,6 +85,11 @@ bool xwin_should_render(struct renderer* rd) {
prop = XInternAtom(d, "_NET_WM_STATE", true);
if (data) {
XFree(data);
data = NULL;
}
if (Success != XGetWindowProperty(d, active, prop, 0, LONG_MAX, false, AnyPropertyType,
&actual_type, &actual_format, &nitems, &bytes_after, &data)) {
goto close; /* some WMs are a little slow on creating _NET_WM_STATE, so errors may occur here */
@@ -95,6 +100,8 @@ bool xwin_should_render(struct renderer* rd) {
}
}
close:
if (data)
XFree(data);
if (should_close)
XCloseDisplay(d);
return ret;
@@ -114,7 +121,7 @@ static bool xwin_changeatom(struct gl_wcb* wcb, void* impl, const char* type,
default: formatted[t] = c;
}
}
bool ret = !strcmp(type, "DESKTOP");
bool ret = !strcmp(formatted, "DESKTOP");
char buf[256];
snprintf(buf, sizeof(buf), fmt, formatted);
Atom desk = XInternAtom(d, buf, false);