22 Commits

Author SHA1 Message Date
Jarcode
7bb7913bd3 Removed -march=native from Makefile 2018-10-08 12:43:18 -07:00
Jarcode
1a1cbc9cc8 Fixed changes to _XROOTPMAP_ID not updating background with "xroot" transparency 2018-10-08 11:53:58 -07:00
Jarcode
83a94e3eb4 Handle window map_state and VisibilityNotify events, closes #68 2018-10-08 11:18:45 -07:00
Jarcode
acdbb8f3b5 updated README.md 2018-10-07 12:04:00 -07:00
Jarcode
829c1be370 Merge branch 'master' of https://github.com/wacossusca34/glava 2018-10-07 08:20:33 -07:00
Jarcode
261ba8ded5 Added more meaningful error messages to the GLX backend 2018-10-07 08:20:19 -07:00
Levi Webb
fc9c74d256 Merge pull request #66 from coderobe/patch-readme
README: Add required X extensions
2018-10-06 15:21:11 -07:00
Levi Webb
a697af9a0a Merge pull request #67 from coderobe/patch-readme-archlinux
README: Mention Arch Linux binary release (community)
2018-10-06 15:20:40 -07:00
Robin B
437aa146a4 README: Mention Arch Linux binary release (community)
GLava is now part of the official Arch Linux [community] repository, maintained by me
2018-10-06 20:41:11 +02:00
Robin B
1c2f362219 README: Add required X extensions 2018-10-06 19:28:32 +02:00
Levi Webb
7dfb68fb1a Update README.md 2018-10-05 21:38:40 -07:00
Jarcode
353c3bd62f Added support for unmanaged windows, see #65 and #4 2018-10-04 20:14:37 -07:00
Jarcode
e4b16cdbb6 Added option to render bars on left/right sides, see #64 2018-10-03 17:45:48 -07:00
Jarcode
8102f99683 Added option to vertically flip bars output, see #64 2018-10-03 17:21:53 -07:00
Jarcode
14747b1e75 Use default PulseAudio buffer sizes when reading input from server, see #63 2018-09-30 14:50:10 -07:00
Levi Webb
217d5c9eea Fix spelling error 2018-09-26 19:04:44 -07:00
Jarcode
3be916f157 Fixed clickthrough issue on Openbox and XFCE, closes #61 2018-09-17 19:23:06 -07:00
Jarcode
bc955a5b3d Merge branch 'master' of https://github.com/wacossusca34/glava 2018-09-12 21:01:46 -07:00
Jarcode
c7ad0a5024 Added signal handler for SIGINT and SIGTERM 2018-09-12 21:01:12 -07:00
Levi Webb
83ad0d8f8a Merge pull request #60 from Smarthard/master
bars COLOR refactored & alpha channel support added
2018-09-11 21:31:25 -07:00
Smarthard
53f7352347 bars COLOR refactored & alpha channel support added 2018-09-11 19:01:24 +03:00
Jarcode
643b0cf3f5 Added detection for variable changes in Makefile, see #59 2018-09-09 19:26:32 -07:00
13 changed files with 254 additions and 104 deletions

View File

@@ -6,10 +6,12 @@ obj = $(src:.c=.o)
ifeq ($(BUILD),debug)
CFLAGS_BUILD = -O0 -ggdb -Wall #-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
GLAD_GEN = c-debug
STRIP_CMD = $(info Skipping `strip` for debug builds)
# ASAN = -lasan
else
CFLAGS_BUILD = -O2 -march=native -Wstringop-overflow=0
CFLAGS_BUILD = -O2 -Wstringop-overflow=0
GLAD_GEN = c
STRIP_CMD = strip --strip-all glava
endif
# Detect OS if not specified (OSX, Linux, BSD are supported)
@@ -68,21 +70,31 @@ GLAD_ARGS = --generator=$(GLAD_GEN) --extensions=GL_EXT_framebuffer_multisample,
CFLAGS_COMMON = -I glad/include -DGLAVA_VERSION="$(GLAVA_VERSION)"
CFLAGS_USE = $(CFLAGS_COMMON) $(CFLAGS_GLX) $(CFLAGS_GLFW) $(CFLAGS_BUILD) $(CFLAGS_INSTALL) $(CFLAGS)
# Store relevant variables that may change depending on the environment or user input
STATE = $(BUILD),$(INSTALL),$(ENABLE_GLFW),$(DISABLE_GLX),$(PYTHON),$(CC),$(CFLAGS_USE)
# Only update the file if the contents changed, `make` just looks at the timestamp
$(shell if [[ ! -e build_state ]]; then touch build_state; fi)
$(shell if [ '$(STATE)' != "`cat build_state`" ]; then echo '$(STATE)' > build_state; fi)
all: glava
%.o: %.c glad.o
%.o: %.c glad.o build_state
$(CC) $(CFLAGS_USE) -o $@ -c $(firstword $<)
glava: $(obj)
$(CC) -o glava $(obj) glad.o $(LDFLAGS)
$(STRIP_CMD)
glad.o:
glad.o: build_state
cd $(GLAD_INSTALL_DIR) && $(PYTHON) -m glad $(GLAD_ARGS) --out-path=.
$(CC) $(CFLAGS_USE) -o glad.o $(GLAD_SRCFILE) -c
# Empty build state goal, used to force some of the above rules to re-run if `build_state` was updated
build_state: ;
.PHONY: clean
clean:
rm -f $(obj) glava glad.o
rm -f $(obj) glava glad.o build_state
.PHONY: install
install:

View File

@@ -3,12 +3,12 @@
**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/))**:**
**Compiling** (Or use the Arch Linux [`glava` package](https://www.archlinux.org/packages/community/x86_64/glava/), or the [`glava-git` AUR package](https://aur.archlinux.org/packages/glava-git/))**:**
```bash
$ git clone --recursive https://github.com/wacossusca34/glava
$ cd glava
$ make
$ CFLAGS="-march=native" make
$ sudo make install
$ glava
```
@@ -17,7 +17,7 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
**Requirements:**
- X11
- X11 (Xext, Xcomposite, & Xrender)
- PulseAudio
- Linux or BSD
@@ -53,7 +53,7 @@ GLava aims to be compatible with _most_ EWMH compliant window managers. Below is
| WM | ! | Details
| :---: | --- | --- |
| Mutter (GNOME, Budgie) | ![-](https://placehold.it/15/118932/000000?text=+) | `"native"` (default) opacity should be used
| KWin (KDE) | ![-](https://placehold.it/15/118932/000000?text=+) | No issues
| KWin (KDE) | ![-](https://placehold.it/15/118932/000000?text=+) | "Show Desktop" [temporarily hides GLava](https://github.com/wacossusca34/glava/issues/4#issuecomment-419729184)
| Openbox (LXDE or standalone) | ![-](https://placehold.it/15/118932/000000?text=+) | No issues
| Xfwm (XFCE) | ![-](https://placehold.it/15/118932/000000?text=+) | No issues
| Fluxbox | ![-](https://placehold.it/15/118932/000000?text=+) | No issues
@@ -62,7 +62,7 @@ GLava aims to be compatible with _most_ EWMH compliant window managers. Below is
| Herbstluftwm | ![-](https://placehold.it/15/118932/000000?text=+) | `hc rule windowtype~'_NET_WM_WINDOW_TYPE_DESKTOP' manage=off` can be used to unmanage desktop windows
| Unity | ![-](https://placehold.it/15/118932/000000?text=+) | No issues
| AwesomeWM | ![-](https://placehold.it/15/f09c00/000000?text=+) | Can still be focused, may require other changes to config depending on layout
| 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)
| i3 (and i3-gaps) | ![-](https://placehold.it/15/f09c00/000000?text=+) | [i3 does not respect the `"desktop"` window type](https://github.com/wacossusca34/glava/issues/6), try `#request setxwintype "!-"`
| EXWM | ![-](https://placehold.it/15/f03c15/000000?text=+) | EXWM does not have a desktop, and forces window decorations
| Enlightenment | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Xmonad | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
@@ -83,7 +83,7 @@ The below copyright notice applies for the original versions of these files:
`Copyright (c) 2015 Karl Stavestrand <karl@stavestrand.no>`
The modified files are relicensed under the terms of the GPLv3. The MIT license is included for your convience and to satisfy the requirements of the original license, although it (no longer) applies to any code in this repository. You will find the original copyright notice and MIT license in the `LICENSE_ORIGINAL` file.
The modified files are relicensed under the terms of the GPLv3. The MIT license is included for your convience and to satisfy the requirements of the original license, although it no longer applies to any code in this repository. You will find the original copyright notice and MIT license in the `LICENSE_ORIGINAL` file.
The below copyright applies for the modifications to the files listed above, and the remaining sources in the repository:

48
glava.c
View File

@@ -5,6 +5,7 @@
#include <string.h>
#include <pthread.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
@@ -190,6 +191,15 @@ static struct option p_opts[] = {
{0, 0, 0, 0 }
};
static renderer* rd = NULL;
void handle_term(int signum) {
if (rd->alive) {
puts("\nInterrupt recieved, closing...");
rd->alive = false;
}
}
int main(int argc, char** argv) {
/* Evaluate these macros only once, since they allocate */
@@ -228,11 +238,15 @@ int main(int argc, char** argv) {
exit(EXIT_SUCCESS);
}
renderer* r = rd_new(system_shader_paths, entry, force, backend, desktop);
float b0[r->bufsize_request], b1[r->bufsize_request];
rd = rd_new(system_shader_paths, entry, force, backend, desktop);
struct sigaction action = { .sa_handler = handle_term };
sigaction(SIGTERM, &action, NULL);
sigaction(SIGINT, &action, NULL);
float b0[rd->bufsize_request], b1[rd->bufsize_request];
size_t t;
for (t = 0; t < r->bufsize_request; ++t) {
for (t = 0; t < rd->bufsize_request; ++t) {
b0[t] = 0.0F;
b1[t] = 0.0F;
}
@@ -240,20 +254,20 @@ int main(int argc, char** argv) {
struct audio_data audio = {
.source = ({
char* src = NULL;
if (r->audio_source_request && strcmp(r->audio_source_request, "auto") != 0) {
src = strdup(r->audio_source_request);
if (rd->audio_source_request && strcmp(rd->audio_source_request, "auto") != 0) {
src = strdup(rd->audio_source_request);
}
src;
}),
.rate = (unsigned int) r->rate_request,
.rate = (unsigned int) rd->rate_request,
.format = -1,
.terminate = 0,
.channels = r->mirror_input ? 1 : 2,
.channels = rd->mirror_input ? 1 : 2,
.audio_out_r = b0,
.audio_out_l = b1,
.mutex = PTHREAD_MUTEX_INITIALIZER,
.audio_buf_sz = r->bufsize_request,
.sample_sz = r->samplesize_request,
.audio_buf_sz = rd->bufsize_request,
.sample_sz = rd->samplesize_request,
.modified = false
};
if (!audio.source) {
@@ -264,10 +278,10 @@ int main(int argc, char** argv) {
pthread_t thread;
pthread_create(&thread, NULL, input_pulse, (void*) &audio);
float lb[r->bufsize_request], rb[r->bufsize_request];
while (r->alive) {
float lb[rd->bufsize_request], rb[rd->bufsize_request];
while (rd->alive) {
rd_time(r); /* update timer for this frame */
rd_time(rd); /* update timer for this frame */
bool modified; /* if the audio buffer has been updated by the streaming thread */
@@ -277,13 +291,13 @@ int main(int argc, char** argv) {
if (modified) {
/* 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));
memcpy(lb, (void*) audio.audio_out_l, rd->bufsize_request * sizeof(float));
memcpy(rb, (void*) audio.audio_out_r, rd->bufsize_request * sizeof(float));
audio.modified = false; /* set this flag to false until the next time we read */
}
pthread_mutex_unlock(&audio.mutex);
if (!rd_update(r, lb, rb, r->bufsize_request, modified)) {
if (!rd_update(rd, lb, rb, rd->bufsize_request, modified)) {
/* Sleep for 50ms and then attempt to render again */
struct timespec tv = {
.tv_sec = 0, .tv_nsec = 50 * 1000000
@@ -299,5 +313,5 @@ int main(int argc, char** argv) {
}
free(audio.source);
rd_destroy(r);
rd_destroy(rd);
}

View File

@@ -128,6 +128,8 @@ static void swap_buffers(GLFWwindow* w) {
static Display* get_x11_display(void) { return glfwGetX11Display(); }
static Window get_x11_window (GLFWwindow* w) { return glfwGetX11Window(w); }
static bool should_close (GLFWwindow* w) { return glfwWindowShouldClose(w); }
static bool should_render (GLFWwindow* w) { return true; }
static bool bg_changed (GLFWwindow* w) { return false; }
static void get_fbsize (GLFWwindow* w, int* d, int* h) { glfwGetFramebufferSize(w, d, h); }
static void get_pos (GLFWwindow* w, int* x, int* y) { glfwGetWindowPos(w, x, y); }
static double get_time (GLFWwindow* w) { return glfwGetTime(); }

163
glx_wcb.c
View File

@@ -161,6 +161,7 @@ GLXDrawable (*glXGetCurrentDrawable) (void);
__GLXextFuncPtr (*glXGetProcAddressARB) (const GLubyte *);
void (*glXSwapBuffers) (Display* dpy, GLXDrawable drawable);
void (*glXDestroyContext) (Display* dpy, GLXContext ctx);
Bool (*glXQueryVersion) (Display* dpy, int* major, int* minor);
extern struct gl_wcb wcb_glx;
@@ -174,10 +175,11 @@ struct glxwin {
Window w;
GLXContext context;
double time;
bool should_close;
bool should_close, should_render, bg_changed, clickthrough;
char override_state;
};
static Atom ATOM__MOTIF_WM_HINTS, ATOM_WM_DELETE_WINDOW, ATOM_WM_PROTOCOLS, ATOM__NET_ACTIVE_WINDOW;
static Atom ATOM__MOTIF_WM_HINTS, ATOM_WM_DELETE_WINDOW, ATOM_WM_PROTOCOLS, ATOM__NET_ACTIVE_WINDOW, ATOM__XROOTPMAP_ID;
static void init(void) {
display = XOpenDisplay(NULL);
@@ -224,11 +226,13 @@ static void init(void) {
resolve(glXGetProcAddressARB);
resolve(glXSwapBuffers);
resolve(glXDestroyContext);
resolve(glXQueryVersion);
intern(_MOTIF_WM_HINTS, false);
intern(WM_DELETE_WINDOW, true);
intern(WM_PROTOCOLS, true);
intern(_NET_ACTIVE_WINDOW, false);
intern(_XROOTPMAP_ID, false);
#undef intern
#undef resolve
@@ -250,6 +254,19 @@ static void apply_decorations(Window w) {
}
}
static void apply_clickthrough(struct glxwin* w) {
if (w->clickthrough) {
int ignored;
if (XShapeQueryExtension(display, &ignored, &ignored)) {
Region region;
if ((region = XCreateRegion())) {
XShapeCombineRegion(display, w->w, ShapeInput, 0, 0, region, ShapeSet);
XDestroyRegion(region);
}
}
}
}
static void* create_and_bind(const char* name, const char* class,
const char* type, const char** states,
size_t states_sz,
@@ -258,13 +275,29 @@ static void* create_and_bind(const char* name, const char* class,
int version_major, int version_minor,
bool clickthrough) {
struct glxwin* w = malloc(sizeof(struct glxwin));
w->time = 0.0D;
w->should_close = false;
*w = (struct glxwin) {
.override_state = '\0',
.time = 0.0D,
.should_close = false,
.should_render = true,
.bg_changed = false,
.clickthrough = false
};
XVisualInfo* vi;
XSetWindowAttributes attr;
XSetWindowAttributes attr = {};
GLXFBConfig* fbc;
int fb_sz, best = -1, samp = -1;
int glx_minor, glx_major;
glXQueryVersion(display, &glx_minor, &glx_major);
if (glx_major <= 1 && glx_minor < 4) {
fprintf(stderr,
"\nGLX extension version mismatch on the current display (1.4+ required, %d.%d available)\n"
"This is usually due to an outdated X server or graphics drivers.\n\n",
glx_minor, glx_major);
exit(EXIT_FAILURE);
}
static int gl_attrs[] = {
GLX_X_RENDERABLE, True,
@@ -288,8 +321,13 @@ static void* create_and_bind(const char* name, const char* class,
fbc = glXChooseFBConfig(display, DefaultScreen(display), gl_attrs, &fb_sz);
if (!fbc) {
fprintf(stderr, "glXChooseFBConfig(): failed\n" );
abort();
fprintf(stderr,
"\nFailed to obtain a GLX frame buffer that supports OpenGL %d.%d.\n"
"This is usually due to running on very old hardware or not having appropriate drivers.\n\n"
"glXChooseFBConfig(): failed with attrs "
"(GLX_CONTEXT_MAJOR_VERSION_ARB, GLX_CONTEXT_MINOR_VERSION_ARB)\n\n",
version_major, version_minor);
exit(EXIT_FAILURE);
}
for (int t = 0; t < fb_sz; ++t) {
@@ -322,15 +360,22 @@ static void* create_and_bind(const char* name, const char* class,
vi = glXGetVisualFromFBConfig(display, config);
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vi->visual, AllocNone);
attr.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask | PropertyChangeMask;
attr.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask;
attr.event_mask |= PropertyChangeMask | VisibilityChangeMask;
attr.background_pixmap = None;
attr.border_pixel = 0;
unsigned long vmask = CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel;
if (type[0] == '!') {
vmask |= CWOverrideRedirect;
attr.override_redirect = true;
w->override_state = type[1];
}
if (!(w->w = XCreateWindow(display, DefaultRootWindow(display)/**xwin_get_desktop_layer(&wcb_glx)*/,
x, y, d, h, 0,
vi->depth, InputOutput, vi->visual,
CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel,
&attr))) {
vmask, &attr))) {
fprintf(stderr, "XCreateWindow(): failed\n");
abort();
}
@@ -360,34 +405,26 @@ static void* create_and_bind(const char* name, const char* class,
XSetWMProtocols(display, w->w, &ATOM_WM_DELETE_WINDOW, 1);
/* Eliminate the window's effective region */
if (desktop || clickthrough) {
int ignored;
if (XShapeQueryExtension(display, &ignored, &ignored)) {
Region region;
if ((region = XCreateRegion())) {
XShapeCombineRegion(display, w->w, ShapeInput, 0, 0, region, ShapeSet);
XDestroyRegion(region);
}
}
}
w->clickthrough = desktop || clickthrough;
apply_clickthrough(w);
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = NULL;
glXSwapIntervalEXTProc glXSwapIntervalEXT = NULL;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddressARB((const GLubyte*) "glXCreateContextAttribsARB");
glXSwapIntervalEXT = (glXSwapIntervalEXTProc)
glXGetProcAddressARB((const GLubyte*) "glXSwapIntervalEXT");
if (!glXCreateContextAttribsARB) {
fprintf(stderr, "glXGetProcAddressARB(\"glXCreateContextAttribsARB\"): failed\n");
abort();
}
if (!(w->context = glXCreateContextAttribsARB(display, config, 0, True, context_attrs))) {
fprintf(stderr, "glXCreateContextAttribsARB(): failed\n");
abort();
}
XSync(display, False);
glXMakeCurrent(display, w->w, w->context);
@@ -397,29 +434,32 @@ static void* create_and_bind(const char* name, const char* class,
if (glXSwapIntervalEXT) glXSwapIntervalEXT(display, drawable, swap);
// XSelectInput(display, DefaultRootWindow(display), VisibilityChangeMask | PropertyChangeMask);
if (!transparent)
XSelectInput(display, DefaultRootWindow(display), PropertyChangeMask);
return w;
}
static void raise(struct glxwin* w) {
XClientMessageEvent ev = {
.type = ClientMessage,
.serial = 0,
.send_event = true,
.display = display,
.window = w->w,
.message_type = ATOM__NET_ACTIVE_WINDOW,
.format = 32,
.data = { .l = {
[0] = 1, /* source indication -- `1` when coming from an application */
[1] = 0, /* timestamp -- `0` to (attempt to) ignore */
[2] = w->w /* requestor's currently active window -- `0` for none */
if (w->override_state == '\0') {
XClientMessageEvent ev = {
.type = ClientMessage,
.serial = 0,
.send_event = true,
.display = display,
.window = w->w,
.message_type = ATOM__NET_ACTIVE_WINDOW,
.format = 32,
.data = { .l = {
[0] = 1, /* source indication -- `1` when coming from an application */
[1] = 0, /* timestamp -- `0` to (attempt to) ignore */
[2] = w->w /* requestor's currently active window -- `0` for none */
}
}
}
};
/* Send the client message as defined by EWMH standards (usually works) */
XSendEvent(display, DefaultRootWindow(display), false, StructureNotifyMask, (XEvent*) &ev);
};
/* Send the client message as defined by EWMH standards (usually works) */
XSendEvent(display, DefaultRootWindow(display), false, StructureNotifyMask, (XEvent*) &ev);
}
/* Raise the client in the X11 stacking order (sometimes works, can be blocked by the WM) */
XRaiseWindow(display, w->w);
XFlush(display);
@@ -437,12 +477,28 @@ static void set_geometry(struct glxwin* w, int x, int y, int d, int h) {
}
static void set_visible(struct glxwin* w, bool visible) {
if (visible) XMapWindow(display, w->w);
if (visible) {
XMapWindow(display, w->w);
apply_clickthrough(w);
switch (w->override_state) {
case '+': XRaiseWindow(display, w->w); break;
case '-': XLowerWindow(display, w->w); break;
default: break;
}
XFlush(display);
}
else XUnmapWindow(display, w->w);
}
static bool should_close(struct glxwin* w) {
return w->should_close;
static bool should_close (struct glxwin* w) { return w->should_close; }
static bool bg_changed (struct glxwin* w) { return w->bg_changed; }
static bool should_render(struct glxwin* w) {
/* For nearly all window managers, windows are 'minimized' by unmapping parent windows.
VisibilityNotify events are not sent in these instances, so we have to read window
attributes to see if our window isn't viewable. */
XWindowAttributes attrs;
XGetWindowAttributes(display, w->w, &attrs);
return w->should_render && attrs.map_state == IsViewable;
}
static void swap_buffers(struct glxwin* w) {
@@ -458,6 +514,25 @@ static void swap_buffers(struct glxwin* w) {
w->should_close = true;
}
break;
case VisibilityNotify:
switch (ev.xvisibility.state) {
case VisibilityFullyObscured:
w->should_render = false;
break;
case VisibilityUnobscured:
case VisibilityPartiallyObscured:
w->should_render = true;
break;
default:
fprintf(stderr, "Invalid VisibilityNotify event state (%d)\n", ev.xvisibility.state);
break;
}
break;
case PropertyNotify:
if (ev.xproperty.atom == ATOM__XROOTPMAP_ID) {
w->bg_changed = true;
}
break;
default: break;
}
}

View File

@@ -123,7 +123,7 @@ void* input_pulse(void* data) {
.channels = 2
};
const pa_buffer_attr pb = {
.maxlength = ssz * 2,
.maxlength = (uint32_t) -1,
.fragsize = ssz
};

View File

@@ -724,7 +724,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
.sm_prog = 0,
.copy_desktop = true,
.premultiply_alpha = true,
.check_fullscreen = true,
.check_fullscreen = false,
.smooth_pass = true,
.fft_scale = 10.2F,
.fft_cutoff = 0.3F,
@@ -1329,7 +1329,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
overlay(&gl->overlay);
glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a);
gl->wcb->set_visible(gl->w, true);
return r;
@@ -1345,12 +1345,17 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
struct gl_data* gl = r->gl;
size_t t, a, fbsz = bsz * sizeof(float);
r->alive = !gl->wcb->should_close(gl->w);
if (!r->alive)
if (gl->wcb->should_close(gl->w)) {
r->alive = false;
return true;
}
/* Stop rendering if the backend has some reason not to render (minimized, obscured) */
if (!gl->wcb->should_render(gl->w))
return false;
/* Stop rendering when fullscreen windows are focused */
if (gl->check_fullscreen && !xwin_should_render(r))
if (gl->check_fullscreen && !xwin_should_render(gl->wcb, gl->w))
return false;
/* Force disable interpolation if the update rate is close to or higher than the frame rate */
@@ -1417,7 +1422,7 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
}
/* Resize and grab new background data if needed */
if (gl->copy_desktop && (ww != gl->lww || wh != gl->lwh || wx != gl->lwx || wy != gl->lwy)) {
if (gl->copy_desktop && (gl->wcb->bg_changed(gl->w) || ww != gl->lww || wh != gl->lwh || wx != gl->lwx || wy != gl->lwy)) {
gl->bg_tex = xwin_copyglbg(r, gl->bg_tex);
}

View File

@@ -33,6 +33,8 @@ struct gl_wcb {
int version_major, int version_minor,
bool clickthrough);
bool (*should_close) (void* ptr);
bool (*should_render) (void* ptr);
bool (*bg_changed) (void* ptr);
void (*swap_buffers) (void* ptr);
void (*raise) (void* ptr);
void (*destroy) (void* ptr);
@@ -68,6 +70,8 @@ struct gl_wcb {
WCB_FUNC(init), \
WCB_FUNC(create_and_bind), \
WCB_FUNC(should_close), \
WCB_FUNC(should_render), \
WCB_FUNC(bg_changed), \
WCB_FUNC(swap_buffers), \
WCB_FUNC(raise), \
WCB_FUNC(destroy), \

View File

@@ -1,21 +1,32 @@
/* center line thickness (pixels) */
/* Center line thickness (pixels) */
#define C_LINE 1
/* width (in pixels) of each bar */
/* Width (in pixels) of each bar */
#define BAR_WIDTH 4
/* width (in pixels) of each bar gap */
/* Width (in pixels) of each bar gap */
#define BAR_GAP 2
/* outline color */
/* Outline color */
#define BAR_OUTLINE #262626
/* outline width (in pixels, set to 0 to disable outline drawing) */
/* Outline width (in pixels, set to 0 to disable outline drawing) */
#define BAR_OUTLINE_WIDTH 0
/* Amplify magnitude of the results each bar displays */
#define AMPLIFY 300
/* Alpha channel for bars color */
#define ALPHA 0.7
/* How strong the gradient changes */
#define GRADIENT_POWER 60
/* Bar color changes with height */
#define GRADIENT (d / GRADIENT_POWER + 1)
/* Bar color */
#define COLOR (#3366b2 * ((d / 60) + 1))
#define COLOR (#3366b2 * GRADIENT * ALPHA)
/* Direction that the bars are facing, 0 for inward, 1 for outward */
#define DIRECTION 0
/* Whether to switch left/right audio buffers */
#define INVERT 0
/* Whether to flip the output vertically */
#define FLIP 0
/* Whether to mirror output along `Y = X`, causing output to render on the left side of the window */
/* Use with `FLIP 1` to render on the right side */
#define MIRROR_YX 0

View File

@@ -29,17 +29,33 @@ out vec4 fragment;
#define PI 3.14159265359
void main() {
float /* (x, magnitude) of fragment */
dx = (gl_FragCoord.x - (screen.x / 2)),
d = gl_FragCoord.y;
float nbars = floor((screen.x * 0.5F) / float(BAR_WIDTH + BAR_GAP)) * 2;
#if MIRROR_YX == 0
#define AREA_WIDTH screen.x
#define AREA_HEIGHT screen.y
#define AREA_X gl_FragCoord.x
#define AREA_Y gl_FragCoord.y
#else
#define AREA_WIDTH screen.y
#define AREA_HEIGHT screen.x
#define AREA_X gl_FragCoord.y
#define AREA_Y gl_FragCoord.x
#endif
float dx = (AREA_X - (AREA_WIDTH / 2));
#if FLIP == 0
float d = AREA_Y;
#else
float d = AREA_HEIGHT - AREA_Y;
#endif
float nbars = floor((AREA_WIDTH * 0.5F) / float(BAR_WIDTH + BAR_GAP)) * 2;
float section = BAR_WIDTH + BAR_GAP; /* size of section for each bar (including gap) */
float center = section / 2.0F; /* half section, distance to center */
float m = abs(mod(dx, section)); /* position in section */
float md = m - center; /* position in section from center line */
if (md < ceil(float(BAR_WIDTH) / 2) && md >= -floor(float(BAR_WIDTH) / 2)) { /* if not in gap */
float p = int(dx / section) / float(nbars / 2); /* position, (-1.0F, 1.0F)) */
p += sign(p) * ((0.5F + center) / screen.x); /* index center of bar position */
p += sign(p) * ((0.5F + center) / AREA_WIDTH); /* index center of bar position */
/* Apply smooth function and index texture */
#define smooth_f(tex, p) smooth_audio(tex, audio_sz, p)
float v;

View File

@@ -61,7 +61,13 @@
This will set _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_(TYPE),
where (TYPE) is the one of the window types listed (after being
converted to uppercase). */
converted to uppercase).
Alternatively, you can set this value to "!", which will cause
the window to be unmanaged. If this is set, then `addxwinstate`
will do nothing, but you can use "!+" and "!-" to stack on top
or below other windows.
*/
#request setxwintype "normal"
/* (X11 only) EWMH Window state atoms (multiple can be specified).
@@ -119,14 +125,17 @@
#request setinterpolate true
/* Frame limiter, set to the frames per second (FPS) desired or
simple set to zero (or lower) to disable the frame limiter. */
simply set to zero (or lower) to disable the frame limiter. */
#request setframerate 0
/* Enable/disable fullscreen checks. This looks at the currently
focused window and halts GLava's rendering if it is
fullscreen. This prevents rendering from interfering with
other graphically intensive tasks. */
#request setfullscreencheck true
/* Suspends rendering if a fullscreen window is focused while
GLava is still visible (ie. on another monitor). This prevents
rendering from interfering with other graphically intensive
tasks.
If GLava is minimized or completely obscured, it will not
render regardless of this option. */
#request setfullscreencheck false
/* Enable/disable printing framerate every second. 'FPS' stands
for 'Frames Per Second', and 'UPS' stands for 'Updates Per

16
xwin.c
View File

@@ -26,7 +26,7 @@
#include "xwin.h"
/* Note: currently unused */
Window* xwin_get_desktop_layer(struct gl_wcb* wcb) {
Window* __attribute__ ((unused)) xwin_get_desktop_layer(struct gl_wcb* wcb) {
static Window desktop;
static bool searched = false;
if (!searched) {
@@ -140,14 +140,14 @@ const char* xwin_detect_wm(struct gl_wcb* wcb) {
}
bool xwin_should_render(struct renderer* rd) {
bool xwin_should_render(struct gl_wcb* wcb, void* impl) {
bool ret = true, should_close = false;
Display* d = rd_get_wcb(rd)->get_x11_display();
Display* d = wcb->get_x11_display();
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);
@@ -221,8 +221,10 @@ static void xwin_changeatom(struct gl_wcb* wcb, void* impl, const char* type,
-> "desktop", "dock", "toolbar", "menu", "utility", "splash", "dialog", "normal" */
bool xwin_settype(struct gl_wcb* wcb, void* impl, const char* rtype) {
S_UPPER(rtype, type);
xwin_changeatom(wcb, impl, type, "_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_%s", PropModeReplace);
if (type[0] != '!') {
xwin_changeatom(wcb, impl, type, "_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_%s", PropModeReplace);
}
return !strcmp(type, "DESKTOP");
}
@@ -278,7 +280,7 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
Display* d = rd_get_wcb(rd)->get_x11_display();
Drawable src = get_drawable(d, DefaultRootWindow(d));
bool use_shm = XShmQueryExtension(d);
/* Obtain section of root pixmap */
XShmSegmentInfo shminfo;

2
xwin.h
View File

@@ -6,7 +6,7 @@
typedef unsigned long int Window;
bool xwin_should_render(struct renderer* rd);
bool xwin_should_render(struct gl_wcb* wcb, void* impl);
void xwin_wait_for_wm(void);
bool xwin_settype(struct gl_wcb* wcb, void* impl, const char* type);
void xwin_setdesktop(struct gl_wcb* wcb, void* impl, unsigned long desktop);