6 Commits
v1.1 ... v1.2

Author SHA1 Message Date
Jarcode
5ec584f35d Updated version 2018-02-06 19:06:30 -08:00
Jarcode
1c2e633bb6 added changelog 2018-02-06 19:00:12 -08:00
Jarcode
1e2aad05b5 Added support for old versions of 'glfw3native.h', fixes #13 2018-02-06 18:22:17 -08:00
Jarcode
8359ad9a98 Added configurable solid background color, closes #16 2018-02-06 18:13:23 -08:00
Jarcode
92f575adfd Removed unessecary 'XOpenDisplay' calls with 'glfwGetX11Display', addresses #15 2018-02-06 16:58:38 -08:00
Jarcode
916ead982e updated readme 2018-02-06 16:42:35 -08:00
8 changed files with 134 additions and 41 deletions

17
CHANGELOG.md Normal file
View File

@@ -0,0 +1,17 @@
## 1.2
* Added support for GLFW 3.1, see issue #13
* Added configurable solid background color, see #16
* Fixed issue with excessive file reads from `~/.Xauthority` see #15
## 1.1
* Added `circle` module
* Added anti-aliasing to the `radial` module, written into the shader itself
* Default configuration values should create more appealing visualizers now
* Massive performance improvements, see issue #10
## 1.0
* All versions of GLava with `1.0` version numbers are older development releases.

View File

@@ -1,7 +1,7 @@
## GLava
<img align="left" width="200" height="200" src="https://thumbs.gfycat.com/DefiantInformalIndianspinyloach-size_restricted.gif" />
GLava is an OpenGL audio spectrum visualizer. Its primary use case is for desktop widgets or backgrounds. Displayed to the left is the `radial` shader module running in GLava.
GLava is an OpenGL audio spectrum visualizer. Its primary use case is for desktop windows or backgrounds. Displayed to the left is the `radial` shader module, and [here is a demonstration video](https://streamable.com/dgpj8). Development is active, and reporting issues is encouranged.
**Compiling** (Or use the [`glava-git` AUR package](https://aur.archlinux.org/packages/glava-git/))**:**
@@ -19,7 +19,7 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
- X11
- PulseAudio
- GLFW 3.2+
- GLFW 3.1+
- Linux or BSD
**Additional compile time requirements:**
@@ -47,14 +47,15 @@ GLava aims to be compatible with _most_ EWMH compliant window managers. Below is
| WM | ! | Details
| :---: | --- | --- |
| GNOME (on X11) | ![-](https://placehold.it/15/118932/000000?text=+) | No notable issues
| Openbox (LXDE or standalone) | ![-](https://placehold.it/15/118932/000000?text=+) | Untested, but should work without issues
| Openbox (LXDE or standalone) | ![-](https://placehold.it/15/118932/000000?text=+) | [Some tweaks may be required](https://www.reddit.com/r/unixporn/comments/7vcgi4/oc_after_receiving_positive_feedback_here_i/dtrkvja/)
| Xfwm (XFCE) | ![-](https://placehold.it/15/118932/000000?text=+) | Untested, but should work without issues
| Fluxbox | ![-](https://placehold.it/15/118932/000000?text=+) | Untested, but should work without issues
| iceWM | ![-](https://placehold.it/15/118932/000000?text=+) | No notable issues
| kwin (KDE) | ![-](https://placehold.it/15/f03c15/000000?text=+) | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing
| AwesomeWM | ![-](https://placehold.it/15/f09c00/000000?text=+) | Requires the WM to be restarted (`Super + Ctl + R`) in order for new desktop windows to behave correctly, can still be focused, may require other changes to config depending on layout
| Budgie Desktop | ![-](https://placehold.it/15/f09c00/000000?text=+) | `"xroot"` transparency breaks with Budgie's wallpaper window
| kwin (KDE) | ![-](https://placehold.it/15/f09c00/000000?text=+) | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing
| i3 (and i3-gaps) | ![-](https://placehold.it/15/f03c15/000000?text=+) | [i3 does not respect the `"desktop"` window type](https://github.com/wacossusca34/glava/issues/6)
| EXWM | ![-](https://placehold.it/15/f03c15/000000?text=+) | EXWM does not have a desktop, and forces window decorations
| AwesomeWM | ![-](https://placehold.it/15/f03c15/000000?text=+) | Requires the WM to be restarted (`Super + Ctl + R`) in order for new desktop windows to behave correctly, can still be focused, may require other changes to config depending on layout
| Unity | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Enlightenment | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Bspwm | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
@@ -62,13 +63,6 @@ GLava aims to be compatible with _most_ EWMH compliant window managers. Below is
| xmonad | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Any non EWMH-compliant WM | ![-](https://placehold.it/15/f03c15/000000?text=+) | Window types and hints will not work if the window manager does not support the EWMH standards.
### [Demo](https://streamable.com/dgpj8)
Above is the `graph` module, below is the `bars` module, `circle` to the left, and `radial` is to the right:
<img src="https://thumbs.gfycat.com/LittleUniformGermanpinscher-size_restricted.gif">
## Licensing
GLava is licensed under the terms of the GPLv3. GLava includes some (heavily modified) source code that originated from [cava](https://github.com/karlstav/cava), which was initially provided under the MIT license. The source files that originated from cava are the following:

View File

@@ -18,7 +18,7 @@
#include "render.h"
#include "xwin.h"
#define GLAVA_VERSION "1.1"
#define GLAVA_VERSION "1.2"
#ifdef GLAD_DEBUG
#define GLAVA_RELEASE_TYPE_PREFIX "debug, "
#else

100
render.c
View File

@@ -97,9 +97,14 @@ struct gl_data {
int rate; /* framerate */
double tcounter;
int fcounter, ucounter, kcounter;
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop, smooth_pass;
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop,
smooth_pass, use_alpha;
void** t_data;
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio, smooth_factor, fft_scale, fft_cutoff;
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio,
smooth_factor, fft_scale, fft_cutoff;
struct {
float r, g, b, a;
} clear_color;
float* interpolate_buf[6];
int geometry[4];
};
@@ -147,7 +152,7 @@ static GLuint shaderload(const char* rpath,
"#define UNIFORM_LIMIT %d\n"
"#define PRE_SMOOTHED_AUDIO %d\n"
"#define SMOOTH_FACTOR %.6f\n"
"#define XROOT %d\n";
"#define USE_ALPHA %d\n";
struct glsl_ext ext = {
.source = raw ? NULL : map,
@@ -166,7 +171,7 @@ static GLuint shaderload(const char* rpath,
GLchar* buf = malloc((blen * sizeof(GLchar*)) + ext.p_len);
int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms,
gl->smooth_pass ? 1 : 0, (double) gl->smooth_factor,
gl->copy_desktop ? 1 : 0);
gl->use_alpha ? 1 : 0);
if (written < 0) {
fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path);
return 0;
@@ -699,10 +704,12 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
.bg_tex = 0,
.sm_prog = 0,
.copy_desktop = true,
.use_alpha = true,
.smooth_pass = true,
.fft_scale = 10.2F,
.fft_cutoff = 0.3F,
.geometry = { 0, 0, 500, 400 }
.geometry = { 0, 0, 500, 400 },
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F }
};
#ifdef GLAD_DEBUG
@@ -742,10 +749,14 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
bool native_opacity = !strcmp("native", (char*) args[0]);
gl->use_alpha = true;
#ifdef GLFW_TRANSPARENT_FRAMEBUFFER
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, native_opacity ? GLFW_TRUE : GLFW_FALSE);
gl->use_alpha = false;
#elif GLFW_TRANSPARENT
glfwWindowHint(GLFW_TRANSPARENT, native_opacity ? GLFW_TRUE : GLFW_FALSE);
gl->use_alpha = false;
#else
if (native_opacity)
printf("WARNING: the linked version of GLFW3 does not have transparency support"
@@ -763,6 +774,63 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
}
})
},
{
.name = "setbg", .fmt = "s",
.handler = RHANDLER(name, args, {
float* results[] = {
&gl->clear_color.r,
&gl->clear_color.g,
&gl->clear_color.b,
&gl->clear_color.a
};
const size_t elem_sz = 2;
char* str = (char*) args[0];
size_t t, len = strlen(str), i = 0, s = 0;
uint8_t elem_bytes[elem_sz];
/* Ignore '0x' prefix, if present */
if (len >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
len -= 2;
str += 2;
}
for (t = 0; t < len && t < 8; ++t) {
char c = str[t];
uint8_t b;
/* obtain value from character */
switch (c) {
case 'a' ... 'f': b = (c - 'a') + 10; break;
case 'A' ... 'F': b = (c - 'A') + 10; break;
case '0' ... '9': b = c - '0'; break;
default:
fprintf(stderr, "Invalid value for `setbg` request: '%s'\n", (char*) args[0]);
exit(EXIT_FAILURE);
}
elem_bytes[s] = b;
if (s >= elem_sz - 1) { /* advance to next element */
uint32_t e = 0; /* component storage */
/* mask storage with input data */
for (size_t v = 0; v < elem_sz; ++v) {
e |= (uint32_t) elem_bytes[v] << (((elem_sz - 1) - v) * 4);
}
/* convert to [0, 1] as floating point value */
*results[i] = (float) e / (float) ((1 << (elem_sz * 4)) - 1);
printf("[DEBUG] component %d value: %d (float: %f)\n", i, e, *results[i]);
s = 0;
++i;
} else { /* advance character */
++s;
}
}
})
},
{
.name = "setbgf", .fmt = "ffff",
.handler = RHANDLER(name, args, {
gl->clear_color.r = *(float*) args[0];
gl->clear_color.g = *(float*) args[1];
gl->clear_color.b = *(float*) args[2];
gl->clear_color.a = *(float*) args[3];
})
},
{
.name = "mod", .fmt = "s",
.handler = RHANDLER(name, args, {
@@ -1002,8 +1070,6 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
size_t m_len = strlen(module);
size_t bsz = d_len + m_len + 2;
@@ -1156,6 +1222,8 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
glfwShowWindow(gl->w);
glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a);
if (xwintype) {
xwin_settype(r, xwintype);
free(xwintype);
@@ -1281,15 +1349,15 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
static bool setup = false;
/* Shader to flip texture and override alpha channel */
static const char* frag_shader =
"uniform sampler2D tex;" "\n"
"uniform ivec2 screen;" "\n"
"out vec4 fragment;" "\n"
"in vec4 gl_FragCoord;" "\n"
"void main() {" "\n"
" fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, " "\n"
" (screen.y - gl_FragCoord.y) / screen.y));" "\n"
" fragment.a = 1.0F;" "\n"
"}" "\n";
"uniform sampler2D tex;" "\n"
"uniform ivec2 screen;" "\n"
"out vec4 fragment;" "\n"
"in vec4 gl_FragCoord;" "\n"
"void main() {" "\n"
" fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, " "\n"
" (screen.y - gl_FragCoord.y) / screen.y));" "\n"
" fragment.a = 1.0F;" "\n"
"}" "\n";
if (!setup) {
bg_prog = shaderlink(shaderload(NULL, GL_VERTEX_SHADER, VERTEX_SHADER_SRC,
NULL, NULL, 330, true, gl),

View File

@@ -11,6 +11,7 @@ out vec4 fragment; /* output */
void main() {
fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);
#if C_SMOOTH > 0
#if USE_ALPHA
vec4
a0 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 0)), 0),
a1 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 1)), 0),
@@ -27,4 +28,5 @@ void main() {
fragment = avg;
}
#endif
#endif
}

View File

@@ -30,7 +30,7 @@ out vec4 fragment;
void main() {
#if XROOT > 0
#if USE_ALPHA > 0
#define APPLY_FRAG(f, c) f = vec4(f.rgb * f.a + c.rgb * (1 - f.a), max(c.a, f.a))
fragment.a = 0;
#else
@@ -47,7 +47,7 @@ void main() {
float d = sqrt((dx * dx) + (dy * dy)); /* distance */
if (d > C_RADIUS - (float(C_LINE) / 2.0F) && d < C_RADIUS + (float(C_LINE) / 2.0F)) {
fragment = OUTLINE;
#if XROOT > 0
#if USE_ALPHA > 0
fragment.a *= ((float(C_LINE) / 2.0F) - abs(d - C_RADIUS)) * C_ALIAS_FACTOR;
#else
return; /* return immediately if there is no alpha blending available */
@@ -73,7 +73,7 @@ void main() {
v *= AMPLIFY; /* amplify */
#undef smooth_f
/* offset to fragment distance from inner circle */
#if XROOT > 0
#if USE_ALPHA > 0
#define ALIAS_FACTOR (((BAR_WIDTH / 2) - abs(ym)) * BAR_ALIAS_FACTOR)
d -= C_RADIUS; /* start bar overlapping the inner circle for blending */
#else
@@ -90,7 +90,7 @@ void main() {
#else
r = COLOR;
#endif
#if XROOT > 0
#if USE_ALPHA > 0
r.a *= ALIAS_FACTOR;
#endif
APPLY_FRAG(fragment, r);
@@ -98,7 +98,7 @@ void main() {
}
#if BAR_OUTLINE_WIDTH > 0
if (d <= v) {
#if XROOT > 0
#if USE_ALPHA > 0
vec4 r = BAR_OUTLINE;
r.a *= ALIAS_FACTOR;
APPLY_FRAG(fragment, r);

View File

@@ -53,6 +53,10 @@
/* GLFW window geometry (x, y, width, height) */
#request setgeometry 0 0 400 600
/* Window background color (RGB format).
Only works with `setopacity "none"` */
#request setbg 3C3C3C
/* (X11 only) EWMH Window type. Possible values are:
"desktop", "dock", "toolbar", "menu",

22
xwin.c
View File

@@ -16,6 +16,11 @@
#include <X11/extensions/XShm.h>
#define GLFW_EXPOSE_NATIVE_X11
/* Hack to make GLFW 3.1 headers work with GLava. We don't use the context APIs from GLFW, but
the old headers require one of them to be selected for exposure in glfw3native.h. */
#if (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR <= 1)
#define GLFW_EXPOSE_NATIVE_GLX
#endif
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
@@ -24,8 +29,12 @@
#include "xwin.h"
bool xwin_should_render(void) {
bool ret = true;
Display* d = XOpenDisplay(0);
bool ret = true, should_close = false;
Display* d = glfwGetX11Display();
if (!d) {
d = XOpenDisplay(0);
should_close = true;
}
Atom prop = XInternAtom(d, "_NET_ACTIVE_WINDOW", true);
Atom fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", true);
@@ -58,7 +67,8 @@ bool xwin_should_render(void) {
}
}
close:
XCloseDisplay(d);
if (should_close)
XCloseDisplay(d);
return ret;
}
@@ -66,7 +76,7 @@ bool xwin_should_render(void) {
-> "desktop", "dock", "toolbar", "menu", "utility", "splash", "dialog", "normal" */
static void xwin_changeatom(struct renderer* rd, const char* type, const char* atom, const char* fmt, int mode) {
Window w = glfwGetX11Window((GLFWwindow*) rd_get_impl_window(rd));
Display* d = XOpenDisplay(0);
Display* d = glfwGetX11Display();
Atom wtype = XInternAtom(d, atom, false);
size_t len = strlen(type), t;
char formatted[len + 1];
@@ -81,7 +91,6 @@ static void xwin_changeatom(struct renderer* rd, const char* type, const char* a
snprintf(buf, sizeof(buf), fmt, formatted);
Atom desk = XInternAtom(d, buf, false);
XChangeProperty(d, w, wtype, XA_ATOM, 32, mode, (unsigned char*) &desk, 1);
XCloseDisplay(d);
}
void xwin_settype(struct renderer* rd, const char* type) {
@@ -127,7 +136,7 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
glfwGetFramebufferSize(gwin, &w, &h);
glfwGetWindowPos(gwin, &x, &y);
XColor c;
Display* d = XOpenDisplay(0);
Display* d = glfwGetX11Display();
Pixmap p = get_pixmap(d, RootWindow(d, DefaultScreen(d)));
/* Obtain section of root pixmap using XShm */
@@ -228,7 +237,6 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
shmctl(shminfo.shmid, IPC_RMID, NULL);
XDestroyImage(image);
XCloseDisplay(d);
return texture;
}