Merge branch 'unstable'
This commit is contained in:
16
Makefile
16
Makefile
@@ -4,7 +4,7 @@ obj = $(src:.c=.o)
|
|||||||
# Build type parameter
|
# Build type parameter
|
||||||
|
|
||||||
ifeq ($(BUILD),debug)
|
ifeq ($(BUILD),debug)
|
||||||
CFLAGS_BUILD = -O1 -ggdb -Wall -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
CFLAGS_BUILD = -O0 -ggdb -Wall -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||||
GLAD_GEN = c-debug
|
GLAD_GEN = c-debug
|
||||||
ASAN = -lasan
|
ASAN = -lasan
|
||||||
else
|
else
|
||||||
@@ -38,12 +38,22 @@ ifeq ($(INSTALL),unix)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifndef DISABLE_GLFW
|
||||||
|
CFLAGS_GLFW = -DGLAVA_GLFW
|
||||||
|
LDFLAGS_GLFW = -lglfw
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef DISABLE_GLX
|
||||||
|
CFLAGS_GLX = -DGLAVA_GLX
|
||||||
|
LDFLAGS_GLX = -lGLX -lXrender
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(INSTALL),osx)
|
ifeq ($(INSTALL),osx)
|
||||||
CFLAGS_INSTALL = -DGLAVA_OSX
|
CFLAGS_INSTALL = -DGLAVA_OSX
|
||||||
SHADER_DIR = Library/glava
|
SHADER_DIR = Library/glava
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LDFLAGS = $(ASAN) -lpulse -lpulse-simple -pthread -lglfw -ldl -lm -lX11 -lXext
|
LDFLAGS = $(ASAN) -lpulse -lpulse-simple -pthread $(LDFLAGS_GLFW) -ldl -lm -lX11 -lXext $(LDFLAGS_GLX)
|
||||||
|
|
||||||
PYTHON = python
|
PYTHON = python
|
||||||
|
|
||||||
@@ -51,7 +61,7 @@ GLAD_INSTALL_DIR = glad
|
|||||||
GLAD_SRCFILE = ./glad/src/glad.c
|
GLAD_SRCFILE = ./glad/src/glad.c
|
||||||
GLAD_ARGS = --generator=$(GLAD_GEN) --extensions=GL_EXT_framebuffer_multisample,GL_EXT_texture_filter_anisotropic
|
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
|
||||||
CFLAGS_USE = $(CFLAGS_COMMON) $(CFLAGS_BUILD) $(CFLAGS_INSTALL) $(CFLAGS)
|
CFLAGS_USE = $(CFLAGS_COMMON) $(CFLAGS_GLX) $(CFLAGS_GLFW) $(CFLAGS_BUILD) $(CFLAGS_INSTALL) $(CFLAGS)
|
||||||
|
|
||||||
all: glava
|
all: glava
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
|
|||||||
|
|
||||||
- X11
|
- X11
|
||||||
- PulseAudio
|
- PulseAudio
|
||||||
- GLFW 3.1+
|
- GLFW 3.1+ (optional, disable with `DISABLE_GLFW=1`)
|
||||||
- Linux or BSD
|
- Linux or BSD
|
||||||
|
|
||||||
**Additional compile time requirements:**
|
**Additional compile time requirements:**
|
||||||
@@ -27,6 +27,7 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
|
|||||||
- glad (included as a submodule)
|
- glad (included as a submodule)
|
||||||
- python (required to generate bindings with glad)
|
- python (required to generate bindings with glad)
|
||||||
- GCC (this program uses GNU C features)
|
- 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:
|
**Ubuntu/Debian users:** the following command ensures you have all the needed packages and headers to compile GLava:
|
||||||
```bash
|
```bash
|
||||||
@@ -43,22 +44,19 @@ To embed GLava in your desktop (for EWMH compliant window managers), use `#reque
|
|||||||
|
|
||||||
\* On an XDG compliant Linux or BSD system. OSX will use `/Library/glava` and `~/Library/Preferences/glava` instead.
|
\* On an XDG compliant Linux or BSD system. OSX will use `/Library/glava` and `~/Library/Preferences/glava` instead.
|
||||||
|
|
||||||
**Note for `#request setopacity`:** While most users will prefer the faster `xroot` transparency, GLFW 3.3 (unreleased) is needed in order to support the `native` transparency option (older versions still work). Arch users can install `glfw-x11-git` from the AUR and recompile GLava for this feature.
|
|
||||||
|
|
||||||
## Desktop window compatibility
|
## Desktop window compatibility
|
||||||
|
|
||||||
GLava aims to be compatible with _most_ EWMH compliant window managers. Below is a list of common window managers and issues specific to them for trying to get GLava to behave as a desktop window or widget:
|
GLava aims to be compatible with _most_ EWMH compliant window managers. Below is a list of common window managers and issues specific to them for trying to get GLava to behave as a desktop window or widget:
|
||||||
|
|
||||||
| WM | ! | Details
|
| WM | ! | Details
|
||||||
| :---: | --- | --- |
|
| :---: | --- | --- |
|
||||||
|
| Mutter (GNOME, Budgie) |  | `"native"` (default) opacity should be used
|
||||||
| Openbox (LXDE or standalone) |  | [Some tweaks may be required](https://www.reddit.com/r/unixporn/comments/7vcgi4/oc_after_receiving_positive_feedback_here_i/dtrkvja/)
|
| Openbox (LXDE or standalone) |  | [Some tweaks may be required](https://www.reddit.com/r/unixporn/comments/7vcgi4/oc_after_receiving_positive_feedback_here_i/dtrkvja/)
|
||||||
| Xfwm (XFCE) |  | Untested, but should work without issues
|
| Xfwm (XFCE) |  | Untested, but should work without issues
|
||||||
| Fluxbox |  | Untested, but should work without issues
|
| Fluxbox |  | Untested, but should work without issues
|
||||||
| iceWM |  | No notable issues
|
| iceWM |  | No notable issues
|
||||||
| Herbstluftwm |  | `hc rule windowtype~'_NET_WM_WINDOW_TYPE_DESKTOP' manage=off` can be used to unmanage desktop windows
|
| Herbstluftwm |  | `hc rule windowtype~'_NET_WM_WINDOW_TYPE_DESKTOP' manage=off` can be used to unmanage desktop windows
|
||||||
| GNOME (on X11) |  | [Some issues with `"xroot"` reported](https://github.com/wacossusca34/glava/issues/18)
|
|
||||||
| AwesomeWM |  | Can still be focused, may require other changes to config depending on layout
|
| AwesomeWM |  | Can still be focused, may require other changes to config depending on layout
|
||||||
| Budgie Desktop |  | `"xroot"` transparency breaks with Budgie's wallpaper window
|
|
||||||
| kwin (KDE) |  | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing
|
| kwin (KDE) |  | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing
|
||||||
| i3 (and i3-gaps) |  | [i3 does not respect the `"desktop"` window type](https://github.com/wacossusca34/glava/issues/6)
|
| i3 (and i3-gaps) |  | [i3 does not respect the `"desktop"` window type](https://github.com/wacossusca34/glava/issues/6)
|
||||||
| EXWM |  | EXWM does not have a desktop, and forces window decorations
|
| EXWM |  | EXWM does not have a desktop, and forces window decorations
|
||||||
|
|||||||
14
glava.c
14
glava.c
@@ -18,7 +18,7 @@
|
|||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "xwin.h"
|
#include "xwin.h"
|
||||||
|
|
||||||
#define GLAVA_VERSION "1.3"
|
#define GLAVA_VERSION "1.4"
|
||||||
#ifdef GLAD_DEBUG
|
#ifdef GLAD_DEBUG
|
||||||
#define GLAVA_RELEASE_TYPE_PREFIX "debug, "
|
#define GLAVA_RELEASE_TYPE_PREFIX "debug, "
|
||||||
#else
|
#else
|
||||||
@@ -167,18 +167,22 @@ static const char* help_str =
|
|||||||
"-C, --copy-config creates copies and symbolic links in the user configuration\n"
|
"-C, --copy-config creates copies and symbolic links in the user configuration\n"
|
||||||
" directory for glava, copying any files in the root directory\n"
|
" directory for glava, copying any files in the root directory\n"
|
||||||
" of the installed shader directory, and linking any modules.\n"
|
" of the installed shader directory, and linking any modules.\n"
|
||||||
|
"-b, --backend specifies a window creation backend to use. By default, the most\n"
|
||||||
|
" appropriate backend will be used for the underlying windowing\n"
|
||||||
|
" system.\n"
|
||||||
"-V, --version print application version and exit\n"
|
"-V, --version print application version and exit\n"
|
||||||
"\n"
|
"\n"
|
||||||
GLAVA_VERSION_STRING "\n"
|
GLAVA_VERSION_STRING "\n"
|
||||||
" -- Copyright (C) 2017 Levi Webb\n";
|
" -- Copyright (C) 2017 Levi Webb\n";
|
||||||
|
|
||||||
static const char* opt_str = "hvVe:Cm:";
|
static const char* opt_str = "hvVe:Cm:b:";
|
||||||
static struct option p_opts[] = {
|
static struct option p_opts[] = {
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"verbose", no_argument, 0, 'v'},
|
{"verbose", no_argument, 0, 'v'},
|
||||||
{"entry", required_argument, 0, 'e'},
|
{"entry", required_argument, 0, 'e'},
|
||||||
{"force-mod", required_argument, 0, 'm'},
|
{"force-mod", required_argument, 0, 'm'},
|
||||||
{"copy-config", no_argument, 0, 'C'},
|
{"copy-config", no_argument, 0, 'C'},
|
||||||
|
{"backend", required_argument, 0, 'b'},
|
||||||
{"version", no_argument, 0, 'V'},
|
{"version", no_argument, 0, 'V'},
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
@@ -190,6 +194,7 @@ int main(int argc, char** argv) {
|
|||||||
const char* user_path = SHADER_USER_PATH;
|
const char* user_path = SHADER_USER_PATH;
|
||||||
const char* entry = "rc.glsl";
|
const char* entry = "rc.glsl";
|
||||||
const char* force = NULL;
|
const char* force = NULL;
|
||||||
|
const char* backend = NULL;
|
||||||
const char* system_shader_paths[] = { user_path, install_path, NULL };
|
const char* system_shader_paths[] = { user_path, install_path, NULL };
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool copy_mode = false;
|
bool copy_mode = false;
|
||||||
@@ -201,6 +206,7 @@ int main(int argc, char** argv) {
|
|||||||
case 'C': copy_mode = true; break;
|
case 'C': copy_mode = true; break;
|
||||||
case 'e': entry = optarg; break;
|
case 'e': entry = optarg; break;
|
||||||
case 'm': force = optarg; break;
|
case 'm': force = optarg; break;
|
||||||
|
case 'b': backend = optarg; break;
|
||||||
case '?': exit(EXIT_FAILURE); break;
|
case '?': exit(EXIT_FAILURE); break;
|
||||||
case 'V':
|
case 'V':
|
||||||
puts(GLAVA_VERSION_STRING);
|
puts(GLAVA_VERSION_STRING);
|
||||||
@@ -219,7 +225,7 @@ int main(int argc, char** argv) {
|
|||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer* r = rd_new(system_shader_paths, entry, force);
|
renderer* r = rd_new(system_shader_paths, entry, force, backend);
|
||||||
|
|
||||||
float b0[r->bufsize_request], b1[r->bufsize_request];
|
float b0[r->bufsize_request], b1[r->bufsize_request];
|
||||||
size_t t;
|
size_t t;
|
||||||
@@ -274,7 +280,7 @@ int main(int argc, char** argv) {
|
|||||||
pthread_mutex_unlock(&audio.mutex);
|
pthread_mutex_unlock(&audio.mutex);
|
||||||
|
|
||||||
/* Only render if needed (ie. stop rendering when fullscreen windows are focused) */
|
/* Only render if needed (ie. stop rendering when fullscreen windows are focused) */
|
||||||
if (xwin_should_render()) {
|
if (xwin_should_render(r)) {
|
||||||
rd_update(r, lb, rb, r->bufsize_request, modified);
|
rd_update(r, lb, rb, r->bufsize_request, modified);
|
||||||
} else {
|
} else {
|
||||||
/* Sleep for 50ms and then attempt to render again */
|
/* Sleep for 50ms and then attempt to render again */
|
||||||
|
|||||||
138
glfw_wcb.c
Normal file
138
glfw_wcb.c
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
/* GLFW window and OpenGL context creation. */
|
||||||
|
|
||||||
|
#ifdef GLAVA_GLFW
|
||||||
|
|
||||||
|
#define GLAVA_RDX11
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include "render.h"
|
||||||
|
#include "xwin.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 <GLFW/glfw3native.h>
|
||||||
|
|
||||||
|
/* Fixes for old GLFW versions */
|
||||||
|
#ifndef GLFW_TRUE
|
||||||
|
#define GLFW_TRUE GL_TRUE
|
||||||
|
#endif
|
||||||
|
#ifndef GLFW_FALSE
|
||||||
|
#define GLFW_FALSE GL_FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DECL_WINDOW_HINT(F, H) \
|
||||||
|
static void F(bool var) { glfwWindowHint(H, var); }
|
||||||
|
#define DECL_WINDOW_HINT_STUB(F) \
|
||||||
|
static void F(bool _) { fprintf(stderr, "Warning: " #F " not implemented for GLFW backend\n"); }
|
||||||
|
|
||||||
|
static void init(void) {
|
||||||
|
if (!glfwInit()) {
|
||||||
|
fprintf(stderr, "glfwInit(): failed\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
|
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
|
||||||
|
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DECL_WINDOW_HINT(set_floating, GLFW_FLOATING);
|
||||||
|
DECL_WINDOW_HINT(set_decorated, GLFW_DECORATED);
|
||||||
|
DECL_WINDOW_HINT(set_focused, GLFW_FOCUSED);
|
||||||
|
#ifdef GLFW_MAXIMIZED
|
||||||
|
DECL_WINDOW_HINT(set_maximized, GLFW_MAXIMIZED);
|
||||||
|
#else
|
||||||
|
DECL_WINDOW_HINT_STUB(set_maximized);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern struct gl_wcb wcb_glfw;
|
||||||
|
|
||||||
|
static void* create_and_bind(const char* name, const char* class,
|
||||||
|
const char* type, const char** states,
|
||||||
|
size_t states_sz,
|
||||||
|
int d, int h,
|
||||||
|
int x, int y,
|
||||||
|
int version_major, int version_minor) {
|
||||||
|
|
||||||
|
GLFWwindow* w;
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, version_major);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, version_minor);
|
||||||
|
|
||||||
|
if (!(w = glfwCreateWindow(d, h, class, NULL, NULL))) {
|
||||||
|
fprintf(stderr, "glfwCreateWindow(): failed\n");
|
||||||
|
glfwTerminate();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
xwin_settype(&wcb_glfw, w, type);
|
||||||
|
|
||||||
|
for (size_t t = 0; t < states_sz; ++t)
|
||||||
|
xwin_addstate(&wcb_glfw, w, states[t]);
|
||||||
|
|
||||||
|
glfwSetWindowPos(w, x, y);
|
||||||
|
glfwMakeContextCurrent(w);
|
||||||
|
|
||||||
|
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_transparent(bool transparent) {
|
||||||
|
#ifdef GLFW_TRANSPARENT_FRAMEBUFFER
|
||||||
|
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, transparent ? GLFW_TRUE : GLFW_FALSE);
|
||||||
|
#elif GLFW_TRANSPARENT
|
||||||
|
glfwWindowHint(GLFW_TRANSPARENT, transparent ? GLFW_TRUE : GLFW_FALSE);
|
||||||
|
#else
|
||||||
|
if (transparent)
|
||||||
|
fprintf(stderr, "Warning: the linked version of GLFW3 does not have transparency support"
|
||||||
|
" (GLFW_TRANSPARENT[_FRAMEBUFFER])!\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_geometry(GLFWwindow* w, int x, int y, int d, int h) {
|
||||||
|
glfwSetWindowPos(w, x, y);
|
||||||
|
glfwSetWindowSize(w, d, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_visible(GLFWwindow* w, bool visible) {
|
||||||
|
if (visible) glfwShowWindow(w);
|
||||||
|
else glfwHideWindow(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool swap_buffers(GLFWwindow* w) {
|
||||||
|
glfwSwapBuffers(w);
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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(); }
|
||||||
|
static void set_time (GLFWwindow* w, double time) { glfwSetTime(time); }
|
||||||
|
static void set_swap (int i) { glfwSwapInterval(i); }
|
||||||
|
|
||||||
|
WCB_ATTACH("glfw", wcb_glfw);
|
||||||
|
|
||||||
|
#endif /* GLAVA_GLFW */
|
||||||
278
glx_wcb.c
Normal file
278
glx_wcb.c
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
|
||||||
|
/* Xlib window creation and GLX context creation backend */
|
||||||
|
|
||||||
|
#ifdef GLAVA_GLX
|
||||||
|
|
||||||
|
#define GLAVA_RDX11
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/extensions/Xrender.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
|
||||||
|
#include "render.h"
|
||||||
|
#include "xwin.h"
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
extern struct gl_wcb wcb_glx;
|
||||||
|
|
||||||
|
static Display* display;
|
||||||
|
|
||||||
|
static int swap;
|
||||||
|
|
||||||
|
static bool floating, decorated, focused, maximized, transparent;
|
||||||
|
|
||||||
|
struct glxwin {
|
||||||
|
Window w;
|
||||||
|
GLXContext context;
|
||||||
|
double time;
|
||||||
|
bool should_close;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(void) {
|
||||||
|
display = XOpenDisplay(NULL);
|
||||||
|
if (!display) {
|
||||||
|
fprintf(stderr, "XOpenDisplay(): could not establish connection to X11 server\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
floating = false;
|
||||||
|
decorated = true;
|
||||||
|
focused = false;
|
||||||
|
maximized = false;
|
||||||
|
transparent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apply_decorations(Window w) {
|
||||||
|
if (!decorated) {
|
||||||
|
struct {
|
||||||
|
unsigned long flags, functions, decorations;
|
||||||
|
long input_mode;
|
||||||
|
unsigned long status;
|
||||||
|
} hints;
|
||||||
|
|
||||||
|
hints.flags = 2;
|
||||||
|
hints.decorations = 0;
|
||||||
|
|
||||||
|
Atom motif = XInternAtom(display, "_MOTIF_WM_HINTS", false);
|
||||||
|
|
||||||
|
XChangeProperty(display, w, motif, motif, 32, PropModeReplace,
|
||||||
|
(unsigned char*) &hints, sizeof(hints) / sizeof(long));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* create_and_bind(const char* name, const char* class,
|
||||||
|
const char* type, const char** states,
|
||||||
|
size_t states_sz,
|
||||||
|
int d, int h,
|
||||||
|
int x, int y,
|
||||||
|
int version_major, int version_minor) {
|
||||||
|
struct glxwin* w = malloc(sizeof(struct glxwin));
|
||||||
|
w->time = 0.0D;
|
||||||
|
w->should_close = false;
|
||||||
|
|
||||||
|
XVisualInfo* vi;
|
||||||
|
XSetWindowAttributes attr;
|
||||||
|
GLXFBConfig* fbc;
|
||||||
|
int fb_sz, best = -1, samp = -1;
|
||||||
|
|
||||||
|
static int gl_attrs[] = {
|
||||||
|
GLX_X_RENDERABLE, True,
|
||||||
|
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||||
|
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||||
|
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
|
||||||
|
GLX_DOUBLEBUFFER, True,
|
||||||
|
GLX_RED_SIZE, 8,
|
||||||
|
GLX_GREEN_SIZE, 8,
|
||||||
|
GLX_BLUE_SIZE, 8,
|
||||||
|
GLX_ALPHA_SIZE, 8,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
int context_attrs[] = {
|
||||||
|
GLX_CONTEXT_MAJOR_VERSION_ARB, version_major,
|
||||||
|
GLX_CONTEXT_MINOR_VERSION_ARB, version_minor,
|
||||||
|
// GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
fbc = glXChooseFBConfig(display, DefaultScreen(display), gl_attrs, &fb_sz);
|
||||||
|
if (!fbc) {
|
||||||
|
fprintf(stderr, "glXChooseFBConfig(): failed\n" );
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int t = 0; t < fb_sz; ++t) {
|
||||||
|
XVisualInfo* xvi = glXGetVisualFromFBConfig(display, fbc[t]);
|
||||||
|
if (xvi) {
|
||||||
|
int samp_buf, samples;
|
||||||
|
glXGetFBConfigAttrib(display, fbc[t], GLX_SAMPLE_BUFFERS, &samp_buf);
|
||||||
|
glXGetFBConfigAttrib(display, fbc[t], GLX_SAMPLES, &samples );
|
||||||
|
XRenderPictFormat* fmt = XRenderFindVisualFormat(display, xvi->visual);
|
||||||
|
|
||||||
|
if (!fmt || (transparent ? fmt->direct.alphaMask == 0 : fmt->direct.alphaMask != 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (best < 0 || samp_buf && samples > samp) {
|
||||||
|
best = t;
|
||||||
|
samp = samples;
|
||||||
|
}
|
||||||
|
XFree(xvi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best == -1) {
|
||||||
|
fprintf(stderr, "Could not find suitable format for FBConfig\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLXFBConfig config = fbc[best];
|
||||||
|
XFree(fbc);
|
||||||
|
|
||||||
|
vi = glXGetVisualFromFBConfig(display, config);
|
||||||
|
|
||||||
|
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vi->visual, AllocNone);
|
||||||
|
attr.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask;
|
||||||
|
attr.background_pixmap = None;
|
||||||
|
attr.border_pixel = 0;
|
||||||
|
|
||||||
|
if (!(w->w = XCreateWindow(display, DefaultRootWindow(display),
|
||||||
|
x, y, d, h, 0,
|
||||||
|
vi->depth, InputOutput, vi->visual,
|
||||||
|
CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel,
|
||||||
|
&attr))) {
|
||||||
|
fprintf(stderr, "XCreateWindow(): failed\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
xwin_settype(&wcb_glx, w, type);
|
||||||
|
|
||||||
|
for (size_t t = 0; t < states_sz; ++t)
|
||||||
|
xwin_addstate(&wcb_glx, w, states[t]);
|
||||||
|
|
||||||
|
if (floating) xwin_addstate(&wcb_glx, w, "above");
|
||||||
|
if (maximized) {
|
||||||
|
xwin_addstate(&wcb_glx, w, "maximized_horz");
|
||||||
|
xwin_addstate(&wcb_glx, w, "maximized_vert");
|
||||||
|
}
|
||||||
|
|
||||||
|
XSetClassHint(display, w->w, &((XClassHint) { .res_name = (char*) class, .res_class = (char*) class }));
|
||||||
|
|
||||||
|
apply_decorations(w->w);
|
||||||
|
|
||||||
|
XFree(vi);
|
||||||
|
|
||||||
|
XStoreName(display, w->w, name);
|
||||||
|
|
||||||
|
Atom dwin = XInternAtom(display, "WM_DELETE_WINDOW", false);
|
||||||
|
XSetWMProtocols(display, w->w, &dwin, 1);
|
||||||
|
|
||||||
|
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);
|
||||||
|
gladLoadGL();
|
||||||
|
|
||||||
|
GLXDrawable drawable = glXGetCurrentDrawable();
|
||||||
|
|
||||||
|
if (glXSwapIntervalEXT) glXSwapIntervalEXT(display, drawable, swap);
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_swap (int _swap) { swap = _swap; }
|
||||||
|
static void set_floating (bool _floating) { floating = _floating; }
|
||||||
|
static void set_decorated (bool _decorated) { decorated = _decorated; }
|
||||||
|
static void set_focused (bool _focused) { focused = _focused; }
|
||||||
|
static void set_maximized (bool _maximized) { maximized = _maximized; }
|
||||||
|
static void set_transparent(bool _transparent) { transparent = _transparent; }
|
||||||
|
|
||||||
|
static void set_geometry(struct glxwin* w, int x, int y, int d, int h) {
|
||||||
|
XMoveResizeWindow(display, w->w, x, y, (unsigned int) d, (unsigned int) h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_visible(struct glxwin* w, bool visible) {
|
||||||
|
if (visible) XMapWindow(display, w->w);
|
||||||
|
else XUnmapWindow(display, w->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool should_close(struct glxwin* w) {
|
||||||
|
return w->should_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swap_buffers(struct glxwin* w) {
|
||||||
|
glXSwapBuffers(display, w->w);
|
||||||
|
|
||||||
|
while (XPending(display) > 0) {
|
||||||
|
XEvent ev;
|
||||||
|
XNextEvent(display, &ev);
|
||||||
|
switch (ev.type) {
|
||||||
|
case ClientMessage:
|
||||||
|
if (ev.xclient.message_type == XInternAtom(display, "WM_PROTOCOLS", 1)
|
||||||
|
&& ev.xclient.data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", 1)) {
|
||||||
|
w->should_close = true;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_fbsize(struct glxwin* w, int* d, int* h) {
|
||||||
|
XWindowAttributes a;
|
||||||
|
XGetWindowAttributes(display, w->w, &a);
|
||||||
|
*d = a.width;
|
||||||
|
*h = a.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_pos(struct glxwin* w, int* x, int* y) {
|
||||||
|
XWindowAttributes a;
|
||||||
|
Window _ignored;
|
||||||
|
XTranslateCoordinates(display, w->w, DefaultRootWindow(display), 0, 0, x, y, &_ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double get_timert(void) {
|
||||||
|
struct timespec tv;
|
||||||
|
if (clock_gettime(CLOCK_REALTIME, &tv)) {
|
||||||
|
fprintf(stderr, "clock_gettime(CLOCK_REALTIME, ...): %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
return (double) tv.tv_sec + ((double) tv.tv_nsec / 1000000000.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double get_time (struct glxwin* w) { return get_timert() - w->time; }
|
||||||
|
static void set_time (struct glxwin* w, double time) { w->time = get_timert() - time; }
|
||||||
|
static Display* get_x11_display(struct glxwin* w) { return display; }
|
||||||
|
static Window get_x11_window (struct glxwin* w) { return w->w; }
|
||||||
|
|
||||||
|
WCB_ATTACH("glx", wcb_glx);
|
||||||
|
|
||||||
|
#endif /* GLAVA_GLX */
|
||||||
244
render.c
244
render.c
@@ -14,15 +14,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
/* Fixes for old GLFW versions */
|
|
||||||
#ifndef GLFW_TRUE
|
|
||||||
#define GLFW_TRUE GL_TRUE
|
|
||||||
#endif
|
|
||||||
#ifndef GLFW_FALSE
|
|
||||||
#define GLFW_FALSE GL_FALSE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "xwin.h"
|
#include "xwin.h"
|
||||||
@@ -44,6 +35,17 @@
|
|||||||
#define VERTEX_SHADER_SRC \
|
#define VERTEX_SHADER_SRC \
|
||||||
"layout(location = 0) in vec3 pos; void main() { gl_Position = vec4(pos.x, pos.y, 0.0F, 1.0F); }"
|
"layout(location = 0) in vec3 pos; void main() { gl_Position = vec4(pos.x, pos.y, 0.0F, 1.0F); }"
|
||||||
|
|
||||||
|
struct gl_wcb* wcbs[2] = {};
|
||||||
|
static size_t wcbs_idx = 0;
|
||||||
|
|
||||||
|
static inline void register_wcb(struct gl_wcb* wcb) { wcbs[wcbs_idx++] = wcb; }
|
||||||
|
|
||||||
|
#define DECL_WCB(N) \
|
||||||
|
do { \
|
||||||
|
extern struct gl_wcb N; \
|
||||||
|
register_wcb(&N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* GLSL bind source */
|
/* GLSL bind source */
|
||||||
|
|
||||||
struct gl_bind_src {
|
struct gl_bind_src {
|
||||||
@@ -83,7 +85,7 @@ struct gl_bind {
|
|||||||
|
|
||||||
struct gl_sfbo {
|
struct gl_sfbo {
|
||||||
GLuint fbo, tex, shader;
|
GLuint fbo, tex, shader;
|
||||||
bool valid;
|
bool valid, nativeonly;
|
||||||
const char* name;
|
const char* name;
|
||||||
struct gl_bind* binds;
|
struct gl_bind* binds;
|
||||||
size_t binds_sz;
|
size_t binds_sz;
|
||||||
@@ -100,13 +102,14 @@ struct gl_data {
|
|||||||
struct overlay_data overlay;
|
struct overlay_data overlay;
|
||||||
GLuint audio_tex_r, audio_tex_l, bg_tex, sm_prog;
|
GLuint audio_tex_r, audio_tex_l, bg_tex, sm_prog;
|
||||||
size_t stages_sz, bufscale, avg_frames;
|
size_t stages_sz, bufscale, avg_frames;
|
||||||
GLFWwindow* w;
|
void* w;
|
||||||
|
struct gl_wcb* wcb;
|
||||||
int lww, lwh, lwx, lwy; /* last window dimensions */
|
int lww, lwh, lwx, lwy; /* last window dimensions */
|
||||||
int rate; /* framerate */
|
int rate; /* framerate */
|
||||||
double tcounter;
|
double tcounter;
|
||||||
int fcounter, ucounter, kcounter;
|
int fcounter, ucounter, kcounter;
|
||||||
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop,
|
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop,
|
||||||
smooth_pass, use_alpha;
|
smooth_pass, premultiply_alpha;
|
||||||
void** t_data;
|
void** t_data;
|
||||||
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio,
|
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio,
|
||||||
smooth_factor, fft_scale, fft_cutoff;
|
smooth_factor, fft_scale, fft_cutoff;
|
||||||
@@ -117,6 +120,8 @@ struct gl_data {
|
|||||||
int geometry[4];
|
int geometry[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* load shader file */
|
/* load shader file */
|
||||||
static GLuint shaderload(const char* rpath,
|
static GLuint shaderload(const char* rpath,
|
||||||
GLenum type,
|
GLenum type,
|
||||||
@@ -160,7 +165,8 @@ static GLuint shaderload(const char* rpath,
|
|||||||
"#define UNIFORM_LIMIT %d\n"
|
"#define UNIFORM_LIMIT %d\n"
|
||||||
"#define PRE_SMOOTHED_AUDIO %d\n"
|
"#define PRE_SMOOTHED_AUDIO %d\n"
|
||||||
"#define SMOOTH_FACTOR %.6f\n"
|
"#define SMOOTH_FACTOR %.6f\n"
|
||||||
"#define USE_ALPHA %d\n";
|
"#define USE_ALPHA %d\n"
|
||||||
|
"#define PREMULTIPLY_ALPHA %d\n";
|
||||||
|
|
||||||
struct glsl_ext ext = {
|
struct glsl_ext ext = {
|
||||||
.source = raw ? NULL : map,
|
.source = raw ? NULL : map,
|
||||||
@@ -175,11 +181,11 @@ static GLuint shaderload(const char* rpath,
|
|||||||
/* If this is raw input, skip processing */
|
/* If this is raw input, skip processing */
|
||||||
if (!raw) ext_process(&ext, rpath);
|
if (!raw) ext_process(&ext, rpath);
|
||||||
|
|
||||||
size_t blen = strlen(header_fmt) + 42;
|
size_t blen = strlen(header_fmt) + 64;
|
||||||
GLchar* buf = malloc((blen * sizeof(GLchar*)) + ext.p_len);
|
GLchar* buf = malloc((blen * sizeof(GLchar*)) + ext.p_len);
|
||||||
int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms,
|
int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms,
|
||||||
gl->smooth_pass ? 1 : 0, (double) gl->smooth_factor,
|
gl->smooth_pass ? 1 : 0, (double) gl->smooth_factor,
|
||||||
gl->use_alpha ? 1 : 0);
|
1, gl->premultiply_alpha ? 1 : 0);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path);
|
fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -676,7 +682,8 @@ static struct gl_bind_src* lookup_bind_src(const char* str) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct renderer* rd_new(const char** paths, const char* entry, const char* force_mod) {
|
struct renderer* rd_new(const char** paths, const char* entry,
|
||||||
|
const char* force_mod, const char* force_backend) {
|
||||||
|
|
||||||
renderer* r = malloc(sizeof(struct renderer));
|
renderer* r = malloc(sizeof(struct renderer));
|
||||||
*r = (struct renderer) {
|
*r = (struct renderer) {
|
||||||
@@ -691,6 +698,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
struct gl_data* gl = r->gl;
|
struct gl_data* gl = r->gl;
|
||||||
*gl = (struct gl_data) {
|
*gl = (struct gl_data) {
|
||||||
.w = NULL,
|
.w = NULL,
|
||||||
|
.wcb = NULL,
|
||||||
.stages = NULL,
|
.stages = NULL,
|
||||||
.rate = 0,
|
.rate = 0,
|
||||||
.tcounter = 0.0D,
|
.tcounter = 0.0D,
|
||||||
@@ -712,7 +720,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
.bg_tex = 0,
|
.bg_tex = 0,
|
||||||
.sm_prog = 0,
|
.sm_prog = 0,
|
||||||
.copy_desktop = true,
|
.copy_desktop = true,
|
||||||
.use_alpha = true,
|
.premultiply_alpha = true,
|
||||||
.smooth_pass = true,
|
.smooth_pass = true,
|
||||||
.fft_scale = 10.2F,
|
.fft_scale = 10.2F,
|
||||||
.fft_cutoff = 0.3F,
|
.fft_cutoff = 0.3F,
|
||||||
@@ -720,6 +728,49 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F }
|
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool forced = force_backend != NULL;
|
||||||
|
const char* backend = force_backend;
|
||||||
|
|
||||||
|
/* Window creation backend interfaces */
|
||||||
|
#ifdef GLAVA_GLFW
|
||||||
|
DECL_WCB(wcb_glfw);
|
||||||
|
if (!forced) backend = "glfw";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GLAVA_GLX
|
||||||
|
DECL_WCB(wcb_glx);
|
||||||
|
if (!forced && !getenv("WAYLAND_DISPLAY") && getenv("DISPLAY")) {
|
||||||
|
backend = "glx";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!backend) {
|
||||||
|
fprintf(stderr, "No backend available for the active windowing system\n");
|
||||||
|
if (wcbs_idx == 0) {
|
||||||
|
fprintf(stderr, "None have been compiled into this build.\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Available backends:\n");
|
||||||
|
for (size_t t = 0; t < wcbs_idx; ++t) {
|
||||||
|
fprintf(stderr, "\t\"%s\"\n", wcbs[t]->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Using backend: '%s'\n", backend);
|
||||||
|
|
||||||
|
for (size_t t = 0; t < wcbs_idx; ++t) {
|
||||||
|
if (wcbs[t]->name && !strcmp(wcbs[t]->name, backend)) {
|
||||||
|
gl->wcb = wcbs[t];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!gl->wcb) {
|
||||||
|
fprintf(stderr, "Invalid window creation backend selected: '%s'\n", gl->wcb);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef GLAD_DEBUG
|
#ifdef GLAD_DEBUG
|
||||||
printf("Assigning debug callback\n");
|
printf("Assigning debug callback\n");
|
||||||
static bool assigned_debug_cb = false;
|
static bool assigned_debug_cb = false;
|
||||||
@@ -729,15 +780,11 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!glfwInit())
|
gl->wcb->init();
|
||||||
abort();
|
|
||||||
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
int shader_version = 330,
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
context_version_major = 3,
|
||||||
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
|
context_version_minor = 3;
|
||||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
|
||||||
|
|
||||||
int shader_version = 330;
|
|
||||||
const char* module = force_mod;
|
const char* module = force_mod;
|
||||||
char* xwintype = NULL, * wintitle = "GLava";
|
char* xwintype = NULL, * wintitle = "GLava";
|
||||||
char** xwinstates = malloc(1);
|
char** xwinstates = malloc(1);
|
||||||
@@ -746,15 +793,9 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
struct gl_sfbo* current = NULL;
|
struct gl_sfbo* current = NULL;
|
||||||
size_t t_count = 0;
|
size_t t_count = 0;
|
||||||
|
|
||||||
#define WINDOW_HINT(request, attr) \
|
#define WINDOW_HINT(request) \
|
||||||
{ .name = request, .fmt = "b", \
|
{ .name = "set" #request, .fmt = "b", \
|
||||||
.handler = RHANDLER(name, args, { glfwWindowHint(attr, *(bool*) args[0]); }) }
|
.handler = RHANDLER(name, args, { gl->wcb->set_##request(*(bool*) args[0]); }) }
|
||||||
|
|
||||||
#define STUB(request, f) \
|
|
||||||
{ .name = request, .fmt = f, \
|
|
||||||
.handler = RHANDLER(name, args, { \
|
|
||||||
fprintf(stderr, "warning: '%s' request is not implemented for this build\n", \
|
|
||||||
request); }) }
|
|
||||||
|
|
||||||
struct request_handler handlers[] = {
|
struct request_handler handlers[] = {
|
||||||
{
|
{
|
||||||
@@ -763,19 +804,9 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
|
|
||||||
bool native_opacity = !strcmp("native", (char*) args[0]);
|
bool native_opacity = !strcmp("native", (char*) args[0]);
|
||||||
|
|
||||||
gl->use_alpha = true;
|
gl->premultiply_alpha = native_opacity;
|
||||||
|
|
||||||
#ifdef GLFW_TRANSPARENT_FRAMEBUFFER
|
gl->wcb->set_transparent(native_opacity);
|
||||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, native_opacity ? GLFW_TRUE : GLFW_FALSE);
|
|
||||||
if (native_opacity) gl->use_alpha = false;
|
|
||||||
#elif GLFW_TRANSPARENT
|
|
||||||
glfwWindowHint(GLFW_TRANSPARENT, native_opacity ? GLFW_TRUE : GLFW_FALSE);
|
|
||||||
if (native_opacity) gl->use_alpha = false;
|
|
||||||
#else
|
|
||||||
if (native_opacity)
|
|
||||||
printf("WARNING: the linked version of GLFW3 does not have transparency support"
|
|
||||||
" (GLFW_TRANSPARENT[_FRAMEBUFFER])!\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!strcmp("xroot", (char*) args[0]))
|
if (!strcmp("xroot", (char*) args[0]))
|
||||||
gl->copy_desktop = true;
|
gl->copy_desktop = true;
|
||||||
@@ -823,19 +854,26 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
WINDOW_HINT("setfloating", GLFW_FLOATING),
|
{
|
||||||
WINDOW_HINT("setdecorated", GLFW_DECORATED),
|
.name = "nativeonly", .fmt = "b",
|
||||||
WINDOW_HINT("setfocused", GLFW_FOCUSED),
|
.handler = RHANDLER(name, args, {
|
||||||
#ifdef GLFW_MAXIMIZED
|
if (current)
|
||||||
WINDOW_HINT("setmaximized", GLFW_MAXIMIZED),
|
current->nativeonly = *(bool*) args[0];
|
||||||
#else
|
else {
|
||||||
STUB("setmaximized", "b"),
|
fprintf(stderr, "`nativeonly` request needs module context\n");
|
||||||
#endif
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
WINDOW_HINT(floating),
|
||||||
|
WINDOW_HINT(decorated),
|
||||||
|
WINDOW_HINT(focused),
|
||||||
|
WINDOW_HINT(maximized),
|
||||||
{
|
{
|
||||||
.name = "setversion", .fmt = "ii",
|
.name = "setversion", .fmt = "ii",
|
||||||
.handler = RHANDLER(name, args, {
|
.handler = RHANDLER(name, args, {
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, *(int*) args[0]);
|
context_version_major = *(int*) args[0];
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, *(int*) args[1]);
|
context_version_minor = *(int*) args[1];
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -865,7 +903,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
{ .name = "setshaderversion", .fmt = "i",
|
{ .name = "setshaderversion", .fmt = "i",
|
||||||
.handler = RHANDLER(name, args, { shader_version = *(int*) args[0]; }) },
|
.handler = RHANDLER(name, args, { shader_version = *(int*) args[0]; }) },
|
||||||
{ .name = "setswap", .fmt = "i",
|
{ .name = "setswap", .fmt = "i",
|
||||||
.handler = RHANDLER(name, args, { glfwSwapInterval(*(int*) args[0]); }) },
|
.handler = RHANDLER(name, args, { gl->wcb->set_swap(*(int*) args[0]); }) },
|
||||||
{ .name = "setframerate", .fmt = "i",
|
{ .name = "setframerate", .fmt = "i",
|
||||||
.handler = RHANDLER(name, args, { gl->rate = *(int*) args[0]; }) },
|
.handler = RHANDLER(name, args, { gl->rate = *(int*) args[0]; }) },
|
||||||
{ .name = "setprintframes", .fmt = "b",
|
{ .name = "setprintframes", .fmt = "b",
|
||||||
@@ -1035,26 +1073,16 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(gl->w = glfwCreateWindow(500, 400, wintitle, NULL, NULL))) {
|
if (!(gl->w = gl->wcb->create_and_bind(wintitle, "GLava", xwintype,
|
||||||
glfwTerminate();
|
(const char**) xwinstates, xwinstates_sz,
|
||||||
|
gl->geometry[2], gl->geometry[3],
|
||||||
|
gl->geometry[0], gl->geometry[1],
|
||||||
|
context_version_major, context_version_minor))) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xwintype) {
|
if (xwintype) free(xwintype);
|
||||||
xwin_settype(r, xwintype);
|
if (xwinstates) free(xwinstates);
|
||||||
free(xwintype);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t t = 0; t < xwinstates_sz; ++t) {
|
|
||||||
xwin_addstate(r, xwinstates[t]);
|
|
||||||
}
|
|
||||||
free(xwinstates);
|
|
||||||
|
|
||||||
glfwSetWindowPos(gl->w, gl->geometry[0], gl->geometry[1]);
|
|
||||||
glfwSetWindowSize(gl->w, gl->geometry[2], gl->geometry[3]);
|
|
||||||
|
|
||||||
glfwMakeContextCurrent(gl->w);
|
|
||||||
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_DEPTH_CLAMP);
|
glDisable(GL_DEPTH_CLAMP);
|
||||||
@@ -1063,8 +1091,10 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
glDisable(GL_MULTISAMPLE);
|
glDisable(GL_MULTISAMPLE);
|
||||||
glDisable(GL_LINE_SMOOTH);
|
glDisable(GL_LINE_SMOOTH);
|
||||||
|
|
||||||
|
if (!gl->premultiply_alpha) {
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
size_t m_len = strlen(module);
|
size_t m_len = strlen(module);
|
||||||
size_t bsz = d_len + m_len + 2;
|
size_t bsz = d_len + m_len + 2;
|
||||||
@@ -1128,6 +1158,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
.name = strdup(d->d_name),
|
.name = strdup(d->d_name),
|
||||||
.shader = 0,
|
.shader = 0,
|
||||||
.valid = false,
|
.valid = false,
|
||||||
|
.nativeonly = false,
|
||||||
.binds = malloc(1),
|
.binds = malloc(1),
|
||||||
.binds_sz = 0
|
.binds_sz = 0
|
||||||
};
|
};
|
||||||
@@ -1144,7 +1175,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
as it can rendered directly */
|
as it can rendered directly */
|
||||||
if (idx != count) {
|
if (idx != count) {
|
||||||
int w, h;
|
int w, h;
|
||||||
glfwGetFramebufferSize(gl->w, &w, &h);
|
gl->wcb->get_fbsize(gl->w, &w, &h);
|
||||||
setup_sfbo(&stages[idx - 1], w, h);
|
setup_sfbo(&stages[idx - 1], w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,6 +1199,23 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gl->stages = stages;
|
||||||
|
gl->stages_sz = count;
|
||||||
|
|
||||||
|
{
|
||||||
|
struct gl_sfbo* final = NULL;
|
||||||
|
if (!gl->premultiply_alpha) {
|
||||||
|
for (size_t t = 0; t < gl->stages_sz; ++t) {
|
||||||
|
if (!gl->stages[t].nativeonly) {
|
||||||
|
final = &gl->stages[t];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Invalidate framebuffer and use direct rendering if it was instantiated
|
||||||
|
due to a following `nativeonly` shader pass. */
|
||||||
|
if (final) final->valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compile smooth pass shader */
|
/* Compile smooth pass shader */
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1177,15 +1225,11 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
char util[usz]; /* module pack path to use */
|
char util[usz]; /* module pack path to use */
|
||||||
snprintf(util, usz, "%s/%s", data, util_folder);
|
snprintf(util, usz, "%s/%s", data, util_folder);
|
||||||
loading_smooth_pass = true;
|
loading_smooth_pass = true;
|
||||||
if (!(gl->sm_prog = shaderbuild(gl, util, data, handlers, shader_version, "smooth_pass.frag"))) {
|
if (!(gl->sm_prog = shaderbuild(gl, util, data, handlers, shader_version, "smooth_pass.frag")))
|
||||||
abort();
|
abort();
|
||||||
}
|
|
||||||
loading_smooth_pass = false;
|
loading_smooth_pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
gl->stages = stages;
|
|
||||||
gl->stages_sz = count;
|
|
||||||
|
|
||||||
/* target seconds per update */
|
/* target seconds per update */
|
||||||
gl->target_spu = (float) (r->samplesize_request / 4) / (float) r->rate_request;
|
gl->target_spu = (float) (r->samplesize_request / 4) / (float) r->rate_request;
|
||||||
|
|
||||||
@@ -1217,7 +1261,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
|
|
||||||
glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a);
|
glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a);
|
||||||
|
|
||||||
glfwShowWindow(gl->w);
|
gl->wcb->set_visible(gl->w, true);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -1225,14 +1269,14 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
|||||||
void rd_time(struct renderer* r) {
|
void rd_time(struct renderer* r) {
|
||||||
struct gl_data* gl = r->gl;
|
struct gl_data* gl = r->gl;
|
||||||
|
|
||||||
glfwSetTime(0.0D); /* reset time for measuring this frame */
|
gl->wcb->set_time(gl->w, 0.0D); /* reset time for measuring this frame */
|
||||||
}
|
}
|
||||||
|
|
||||||
void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modified) {
|
void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modified) {
|
||||||
struct gl_data* gl = r->gl;
|
struct gl_data* gl = r->gl;
|
||||||
size_t t, a, fbsz = bsz * sizeof(float);
|
size_t t, a, fbsz = bsz * sizeof(float);
|
||||||
|
|
||||||
r->alive = !glfwWindowShouldClose(gl->w);
|
r->alive = !gl->wcb->should_close(gl->w);
|
||||||
if (!r->alive)
|
if (!r->alive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1287,8 +1331,8 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
int ww, wh, wx, wy;
|
int ww, wh, wx, wy;
|
||||||
glfwGetFramebufferSize(gl->w, &ww, &wh);
|
gl->wcb->get_fbsize(gl->w, &ww, &wh);
|
||||||
glfwGetWindowPos(gl->w, &wx, &wy);
|
gl->wcb->get_pos(gl->w, &wx, &wy);
|
||||||
|
|
||||||
/* Resize screen textures if needed */
|
/* Resize screen textures if needed */
|
||||||
if (ww != gl->lww || wh != gl->lwh) {
|
if (ww != gl->lww || wh != gl->lwh) {
|
||||||
@@ -1322,6 +1366,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
/* Current shader program */
|
/* Current shader program */
|
||||||
struct gl_sfbo* current = &gl->stages[t];
|
struct gl_sfbo* current = &gl->stages[t];
|
||||||
|
|
||||||
|
if (current->nativeonly && !gl->premultiply_alpha)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Bind framebuffer if this is not the final pass */
|
/* Bind framebuffer if this is not the final pass */
|
||||||
if (current->valid)
|
if (current->valid)
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
|
||||||
@@ -1339,8 +1386,8 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
"out vec4 fragment;" "\n"
|
"out vec4 fragment;" "\n"
|
||||||
"in vec4 gl_FragCoord;" "\n"
|
"in vec4 gl_FragCoord;" "\n"
|
||||||
"void main() {" "\n"
|
"void main() {" "\n"
|
||||||
" fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, " "\n"
|
" fragment = texelFetch(tex, ivec2(gl_FragCoord.x, " "\n"
|
||||||
" (screen.y - gl_FragCoord.y) / screen.y));" "\n"
|
" screen.y - gl_FragCoord.y), 0);" "\n"
|
||||||
" fragment.a = 1.0F;" "\n"
|
" fragment.a = 1.0F;" "\n"
|
||||||
"}" "\n";
|
"}" "\n";
|
||||||
if (!setup) {
|
if (!setup) {
|
||||||
@@ -1361,9 +1408,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
/* We need to disable blending, we might read in bogus alpha values due
|
/* We need to disable blending, we might read in bogus alpha values due
|
||||||
to how we obtain the background texture (format is four byte `rgb_`,
|
to how we obtain the background texture (format is four byte `rgb_`,
|
||||||
where the last value is skipped) */
|
where the last value is skipped) */
|
||||||
glDisable(GL_BLEND);
|
if (!gl->premultiply_alpha) glDisable(GL_BLEND);
|
||||||
drawoverlay(&gl->overlay);
|
drawoverlay(&gl->overlay);
|
||||||
glEnable(GL_BLEND);
|
if (!gl->premultiply_alpha) glEnable(GL_BLEND);
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1441,7 +1488,8 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
|
|
||||||
/* setup and bind framebuffer to texture */
|
/* setup and bind framebuffer to texture */
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, sm->fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, sm->fbo);
|
||||||
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_1D, sm->tex, 0);
|
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,\
|
||||||
|
GL_TEXTURE_1D, sm->tex, 0);
|
||||||
|
|
||||||
switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
|
switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
|
||||||
case GL_FRAMEBUFFER_COMPLETE: break;
|
case GL_FRAMEBUFFER_COMPLETE: break;
|
||||||
@@ -1462,11 +1510,11 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
glUniform1i(sm_uw, sz); /* target texture width */
|
glUniform1i(sm_uw, sz); /* target texture width */
|
||||||
glUniform1i(sm_usz, sz); /* source texture width */
|
glUniform1i(sm_usz, sz); /* source texture width */
|
||||||
glUniform1i(sm_utex, offset);
|
glUniform1i(sm_utex, offset);
|
||||||
glDisable(GL_BLEND);
|
if (!gl->premultiply_alpha) glDisable(GL_BLEND);
|
||||||
glViewport(0, 0, sz, 1);
|
glViewport(0, 0, sz, 1);
|
||||||
drawoverlay(&gl->overlay);
|
drawoverlay(&gl->overlay);
|
||||||
glViewport(0, 0, ww, wh);
|
glViewport(0, 0, ww, wh);
|
||||||
glEnable(GL_BLEND);
|
if (!gl->premultiply_alpha) glEnable(GL_BLEND);
|
||||||
|
|
||||||
/* Return state */
|
/* Return state */
|
||||||
glUseProgram(current->shader);
|
glUseProgram(current->shader);
|
||||||
@@ -1527,10 +1575,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Swap buffers, handle events, etc. (vsync is potentially included here, too) */
|
/* Swap buffers, handle events, etc. (vsync is potentially included here, too) */
|
||||||
glfwSwapBuffers(gl->w);
|
gl->wcb->swap_buffers(gl->w);
|
||||||
glfwPollEvents();
|
|
||||||
|
|
||||||
double duration = glfwGetTime(); /* frame execution time */
|
double duration = gl->wcb->get_time(gl->w); /* frame execution time */
|
||||||
|
|
||||||
/* Handling sleeping (to meet target framerate) */
|
/* Handling sleeping (to meet target framerate) */
|
||||||
if (gl->rate > 0) {
|
if (gl->rate > 0) {
|
||||||
@@ -1566,8 +1613,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
|
|
||||||
/* Refresh window position and size if we are forcing it */
|
/* Refresh window position and size if we are forcing it */
|
||||||
if (gl->force_geometry) {
|
if (gl->force_geometry) {
|
||||||
glfwSetWindowPos(gl->w, gl->geometry[0], gl->geometry[1]);
|
gl->wcb->set_geometry(gl->w,
|
||||||
glfwSetWindowSize(gl->w, gl->geometry[2], gl->geometry[3]);
|
gl->geometry[0], gl->geometry[1],
|
||||||
|
gl->geometry[2], gl->geometry[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1576,10 +1624,10 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* rd_get_impl_window (struct renderer* r) { return r->gl->w; }
|
void* rd_get_impl_window (struct renderer* r) { return r->gl->w; }
|
||||||
|
struct gl_wcb* rd_get_wcb (struct renderer* r) { return r->gl->wcb; }
|
||||||
|
|
||||||
void rd_destroy(struct renderer* r) {
|
void rd_destroy(struct renderer* r) {
|
||||||
/* TODO: delete everything else, not really needed though (as the application exits after here) */
|
/* TODO: delete everything else, not really needed though (as the application exits after here) */
|
||||||
glfwTerminate();
|
|
||||||
free(r->gl);
|
free(r->gl);
|
||||||
free(r);
|
free(r);
|
||||||
}
|
}
|
||||||
|
|||||||
71
render.h
71
render.h
@@ -1,4 +1,7 @@
|
|||||||
|
|
||||||
|
#ifndef RENDER_H
|
||||||
|
#define RENDER_H
|
||||||
|
|
||||||
struct gl_data;
|
struct gl_data;
|
||||||
|
|
||||||
typedef struct renderer {
|
typedef struct renderer {
|
||||||
@@ -8,8 +11,72 @@ typedef struct renderer {
|
|||||||
struct gl_data* gl;
|
struct gl_data* gl;
|
||||||
} renderer;
|
} renderer;
|
||||||
|
|
||||||
struct renderer* rd_new(const char** paths, const char* entry, const char* force_mod);
|
struct renderer* rd_new (const char** paths, const char* entry,
|
||||||
void rd_update(struct renderer*, float* lb, float* rb, size_t bsz, bool modified);
|
const char* force_mod, const char* force_backend);
|
||||||
|
void rd_update (struct renderer*, float* lb, float* rb,
|
||||||
|
size_t bsz, bool modified);
|
||||||
void rd_destroy (struct renderer*);
|
void rd_destroy (struct renderer*);
|
||||||
void rd_time (struct renderer*);
|
void rd_time (struct renderer*);
|
||||||
void* rd_get_impl_window(struct renderer*);
|
void* rd_get_impl_window(struct renderer*);
|
||||||
|
struct gl_wcb* rd_get_wcb (struct renderer*);
|
||||||
|
|
||||||
|
/* gl_wcb - OpenGL Window Creation Backend interface */
|
||||||
|
struct gl_wcb {
|
||||||
|
const char* name;
|
||||||
|
void (*init) (void);
|
||||||
|
void* (*create_and_bind)(const char* name, const char* class,
|
||||||
|
const char* type, const char** states,
|
||||||
|
size_t states_sz,
|
||||||
|
int w, int h,
|
||||||
|
int x, int y,
|
||||||
|
int version_major, int version_minor);
|
||||||
|
bool (*should_close) (void* ptr);
|
||||||
|
bool (*swap_buffers) (void* ptr);
|
||||||
|
void (*get_pos) (void* ptr, int* x, int* y);
|
||||||
|
void (*get_fbsize) (void* ptr, int* w, int* h);
|
||||||
|
void (*set_geometry) (void* ptr, int x, int y, int w, int h);
|
||||||
|
void (*set_swap) (int interval);
|
||||||
|
void (*set_floating) (bool floating);
|
||||||
|
void (*set_decorated) (bool decorated);
|
||||||
|
void (*set_focused) (bool focused);
|
||||||
|
void (*set_maximized) (bool maximized);
|
||||||
|
void (*set_transparent)(bool transparent);
|
||||||
|
double (*get_time) (void* ptr);
|
||||||
|
void (*set_time) (void* ptr, double time);
|
||||||
|
void (*set_visible) (void* ptr, bool visible);
|
||||||
|
#ifdef GLAVA_RDX11
|
||||||
|
Display* (*get_x11_display)(void);
|
||||||
|
Window (*get_x11_window) (void* ptr);
|
||||||
|
#else /* define placeholders to ensure equal struct size */
|
||||||
|
void* _X11_DISPLAY_PLACEHOLDER;
|
||||||
|
void* _X11_WINDOW_PLACEHOLDER;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WCB_FUNC(F) \
|
||||||
|
.F = (typeof(((struct gl_wcb*) NULL)->F)) &F
|
||||||
|
|
||||||
|
#define WCB_ATTACH(B, N) \
|
||||||
|
struct gl_wcb N = { \
|
||||||
|
.name = B, \
|
||||||
|
WCB_FUNC(init), \
|
||||||
|
WCB_FUNC(create_and_bind), \
|
||||||
|
WCB_FUNC(should_close), \
|
||||||
|
WCB_FUNC(swap_buffers), \
|
||||||
|
WCB_FUNC(set_swap), \
|
||||||
|
WCB_FUNC(get_pos), \
|
||||||
|
WCB_FUNC(get_fbsize), \
|
||||||
|
WCB_FUNC(set_geometry), \
|
||||||
|
WCB_FUNC(set_floating), \
|
||||||
|
WCB_FUNC(set_decorated), \
|
||||||
|
WCB_FUNC(set_focused), \
|
||||||
|
WCB_FUNC(set_maximized), \
|
||||||
|
WCB_FUNC(set_transparent), \
|
||||||
|
WCB_FUNC(set_time), \
|
||||||
|
WCB_FUNC(get_time), \
|
||||||
|
WCB_FUNC(set_visible), \
|
||||||
|
WCB_FUNC(get_x11_display), \
|
||||||
|
WCB_FUNC(get_x11_window) \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* RENDER_H */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* center radius (pixels) */
|
/* center radius (pixels) */
|
||||||
#define C_RADIUS 128
|
#define C_RADIUS 128
|
||||||
/* center line thickness (pixels) */
|
/* center line thickness (pixels) */
|
||||||
#define C_LINE 2
|
#define C_LINE 1.5
|
||||||
/* outline color */
|
/* outline color */
|
||||||
#define OUTLINE #333333
|
#define OUTLINE #333333
|
||||||
/* Amplify magnitude of the results each bar displays */
|
/* Amplify magnitude of the results each bar displays */
|
||||||
|
|||||||
1
shaders/circle/3.frag
Normal file
1
shaders/circle/3.frag
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include ":util/premultiply.frag"
|
||||||
@@ -31,8 +31,8 @@ out vec4 fragment;
|
|||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
#if USE_ALPHA > 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))
|
#define APPLY_FRAG(f, c) f = vec4(f.rgb * f.a + c.rgb * (1 - clamp(f.a, 0, 1)), max(c.a, f.a))
|
||||||
fragment.a = 0;
|
fragment = #00000000;
|
||||||
#else
|
#else
|
||||||
#define APPLY_FRAG(f, c) f = c
|
#define APPLY_FRAG(f, c) f = c
|
||||||
#endif
|
#endif
|
||||||
@@ -46,9 +46,9 @@ void main() {
|
|||||||
float theta = atan(dy, dx); /* fragment angle with the center of the screen as the origin */
|
float theta = atan(dy, dx); /* fragment angle with the center of the screen as the origin */
|
||||||
float d = sqrt((dx * dx) + (dy * dy)); /* distance */
|
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)) {
|
if (d > C_RADIUS - (float(C_LINE) / 2.0F) && d < C_RADIUS + (float(C_LINE) / 2.0F)) {
|
||||||
fragment = OUTLINE;
|
APPLY_FRAG(fragment, OUTLINE);
|
||||||
#if USE_ALPHA > 0
|
#if USE_ALPHA > 0
|
||||||
fragment.a *= ((float(C_LINE) / 2.0F) - abs(d - C_RADIUS)) * C_ALIAS_FACTOR;
|
fragment.a *= clamp(((C_LINE / 2) - abs(C_RADIUS - d)) * C_ALIAS_FACTOR, 0, 1);
|
||||||
#else
|
#else
|
||||||
return; /* return immediately if there is no alpha blending available */
|
return; /* return immediately if there is no alpha blending available */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1
shaders/radial/2.frag
Normal file
1
shaders/radial/2.frag
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include ":util/premultiply.frag"
|
||||||
@@ -15,23 +15,22 @@
|
|||||||
See documentation for more details. */
|
See documentation for more details. */
|
||||||
#request mod bars
|
#request mod bars
|
||||||
|
|
||||||
/* GLFW window hints */
|
/* Window hints */
|
||||||
#request setfloating false
|
#request setfloating false
|
||||||
#request setdecorated false
|
#request setdecorated true
|
||||||
#request setfocused false
|
#request setfocused false
|
||||||
#request setmaximized false
|
#request setmaximized false
|
||||||
|
|
||||||
/* Force GLFW window geometry (locking the window in place),
|
/* Force window geometry (locking the window in place), useful
|
||||||
useful for some pesky WMs that try to reposition the window
|
for some pesky WMs that try to reposition the window when
|
||||||
when embedding in the desktop. */
|
embedding in the desktop. */
|
||||||
#request setforcegeometry false
|
#request setforcegeometry false
|
||||||
|
|
||||||
/* Set window background opacity mode. Possible values are:
|
/* Set window background opacity mode. Possible values are:
|
||||||
|
|
||||||
"native" - True transparency provided by the compositor.
|
"native" - True transparency provided by the compositor. Can
|
||||||
Requires GLFW 3.3+ and an active compositor. Can
|
reduce performance on some systems, depending on
|
||||||
reduce performance on some systems, and will not
|
the compositor used.
|
||||||
blend with the visualizer's alpha layer.
|
|
||||||
|
|
||||||
"xroot" - Maintain a copy of the root window's pixmap
|
"xroot" - Maintain a copy of the root window's pixmap
|
||||||
(usually the desktop background) to provide a
|
(usually the desktop background) to provide a
|
||||||
@@ -40,22 +39,22 @@
|
|||||||
Has very little performance impact.
|
Has very little performance impact.
|
||||||
|
|
||||||
"none" - Disable window opacity completely. */
|
"none" - Disable window opacity completely. */
|
||||||
#request setopacity "xroot"
|
#request setopacity "native"
|
||||||
|
|
||||||
/* OpenGL context and GLSL shader versions, do not change unless
|
/* OpenGL context and GLSL shader versions, do not change unless
|
||||||
you *absolutely* know what you are doing. */
|
you *absolutely* know what you are doing. */
|
||||||
#request setversion 3 3
|
#request setversion 3 3
|
||||||
#request setshaderversion 330
|
#request setshaderversion 330
|
||||||
|
|
||||||
/* GLFW window title */
|
/* Window title */
|
||||||
#request settitle "GLava"
|
#request settitle "GLava"
|
||||||
|
|
||||||
/* GLFW window geometry (x, y, width, height) */
|
/* Window geometry (x, y, width, height) */
|
||||||
#request setgeometry 0 0 400 600
|
#request setgeometry 0 0 800 600
|
||||||
|
|
||||||
/* Window background color (RGB format).
|
/* Window background color (RGB format).
|
||||||
Only works with `setopacity "none"` */
|
Does not work with `setopacity "xroot"` */
|
||||||
#request setbg 3C3C3C
|
#request setbg 00000000
|
||||||
|
|
||||||
/* (X11 only) EWMH Window type. Possible values are:
|
/* (X11 only) EWMH Window type. Possible values are:
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@
|
|||||||
default output device. */
|
default output device. */
|
||||||
#request setsource "auto"
|
#request setsource "auto"
|
||||||
|
|
||||||
/* GLFW buffer swap interval (vsync), set to '0' to prevent
|
/* Buffer swap interval (vsync), set to '0' to prevent
|
||||||
waiting for refresh, '1' (or more) to wait for the specified
|
waiting for refresh, '1' (or more) to wait for the specified
|
||||||
amount of frames. */
|
amount of frames. */
|
||||||
#request setswap 1
|
#request setswap 1
|
||||||
|
|||||||
15
shaders/util/premultiply.frag
Normal file
15
shaders/util/premultiply.frag
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#request nativeonly true
|
||||||
|
|
||||||
|
#request uniform "prev" tex
|
||||||
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
out vec4 fragment;
|
||||||
|
in vec4 gl_FragCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);
|
||||||
|
#if PREMULTIPLY_ALPHA > 0
|
||||||
|
fragment.rgb *= fragment.a;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
114
xwin.c
114
xwin.c
@@ -12,27 +12,50 @@
|
|||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/extensions/Xcomposite.h>
|
||||||
#include <X11/extensions/XShm.h>
|
#include <X11/extensions/XShm.h>
|
||||||
|
|
||||||
#define GLFW_EXPOSE_NATIVE_X11
|
|
||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
/* 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 <GLFW/glfw3native.h>
|
|
||||||
|
|
||||||
|
#define GLAVA_RDX11
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "xwin.h"
|
#include "xwin.h"
|
||||||
|
|
||||||
bool xwin_should_render(void) {
|
static Window find_desktop(struct renderer* r) {
|
||||||
|
static Window desktop;
|
||||||
|
static bool searched = false;
|
||||||
|
if (!searched) {
|
||||||
|
Display* d = rd_get_wcb(r)->get_x11_display();
|
||||||
|
desktop = DefaultRootWindow(d);
|
||||||
|
Window _ignored, * children;
|
||||||
|
unsigned int nret;
|
||||||
|
XQueryTree(d, desktop, &_ignored, &_ignored, &children, &nret);
|
||||||
|
if (children) {
|
||||||
|
for (unsigned int t = 0; t < nret; ++t) {
|
||||||
|
char* name;
|
||||||
|
XFetchName(d, children[t], &name);
|
||||||
|
if (name) {
|
||||||
|
/* Mutter-based window managers */
|
||||||
|
if (!strcmp(name, "mutter guard window")) {
|
||||||
|
printf("Using mutter guard window instead of root window\n");
|
||||||
|
// desktop = children[t];
|
||||||
|
t = nret; /* break after */
|
||||||
|
}
|
||||||
|
XFree(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XFree(children);
|
||||||
|
}
|
||||||
|
searched = true;
|
||||||
|
}
|
||||||
|
return desktop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xwin_should_render(struct renderer* rd) {
|
||||||
bool ret = true, should_close = false;
|
bool ret = true, should_close = false;
|
||||||
Display* d = glfwGetX11Display();
|
Display* d = rd_get_wcb(rd)->get_x11_display();
|
||||||
if (!d) {
|
if (!d) {
|
||||||
d = XOpenDisplay(0);
|
d = XOpenDisplay(0);
|
||||||
should_close = true;
|
should_close = true;
|
||||||
@@ -50,11 +73,14 @@ bool xwin_should_render(void) {
|
|||||||
|
|
||||||
XSetErrorHandler(handler); /* dummy error handler */
|
XSetErrorHandler(handler); /* dummy error handler */
|
||||||
|
|
||||||
if (Success != XGetWindowProperty(d, RootWindow(d, 0), prop, 0, 1, false, AnyPropertyType,
|
if (Success != XGetWindowProperty(d, DefaultRootWindow(d), prop, 0, 1, false, AnyPropertyType,
|
||||||
&actual_type, &actual_format, &nitems, &bytes_after, &data)) {
|
&actual_type, &actual_format, &nitems, &bytes_after, &data)) {
|
||||||
goto close; /* if an error occurs here, the WM probably isn't EWMH compliant */
|
goto close; /* if an error occurs here, the WM probably isn't EWMH compliant */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!nitems)
|
||||||
|
goto close;
|
||||||
|
|
||||||
Window active = ((Window*) data)[0];
|
Window active = ((Window*) data)[0];
|
||||||
|
|
||||||
prop = XInternAtom(d, "_NET_WM_STATE", true);
|
prop = XInternAtom(d, "_NET_WM_STATE", true);
|
||||||
@@ -76,9 +102,10 @@ bool xwin_should_render(void) {
|
|||||||
|
|
||||||
/* Set window types defined by the EWMH standard, possible values:
|
/* Set window types defined by the EWMH standard, possible values:
|
||||||
-> "desktop", "dock", "toolbar", "menu", "utility", "splash", "dialog", "normal" */
|
-> "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) {
|
static void xwin_changeatom(struct gl_wcb* wcb, void* impl, const char* type,
|
||||||
Window w = glfwGetX11Window((GLFWwindow*) rd_get_impl_window(rd));
|
const char* atom, const char* fmt, int mode) {
|
||||||
Display* d = glfwGetX11Display();
|
Window w = wcb->get_x11_window(impl);
|
||||||
|
Display* d = wcb->get_x11_display();
|
||||||
Atom wtype = XInternAtom(d, atom, false);
|
Atom wtype = XInternAtom(d, atom, false);
|
||||||
size_t len = strlen(type), t;
|
size_t len = strlen(type), t;
|
||||||
char formatted[len + 1];
|
char formatted[len + 1];
|
||||||
@@ -95,16 +122,16 @@ static void xwin_changeatom(struct renderer* rd, const char* type, const char* a
|
|||||||
XChangeProperty(d, w, wtype, XA_ATOM, 32, mode, (unsigned char*) &desk, 1);
|
XChangeProperty(d, w, wtype, XA_ATOM, 32, mode, (unsigned char*) &desk, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xwin_settype(struct renderer* rd, const char* type) {
|
void xwin_settype(struct gl_wcb* wcb, void* impl, const char* type) {
|
||||||
xwin_changeatom(rd, type, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_%s", PropModeReplace);
|
xwin_changeatom(wcb, impl, type, "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_%s", PropModeReplace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xwin_addstate(struct renderer* rd, const char* state) {
|
void xwin_addstate(struct gl_wcb* wcb, void* impl, const char* state) {
|
||||||
xwin_changeatom(rd, state, "_NET_WM_STATE", "_NET_WM_STATE_%s", PropModeAppend);
|
xwin_changeatom(wcb, impl, state, "_NET_WM_STATE", "_NET_WM_STATE_%s", PropModeAppend);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Pixmap get_pixmap(Display* d, Window w) {
|
static Drawable get_drawable(Display* d, Window w) {
|
||||||
Pixmap p;
|
Drawable p;
|
||||||
Atom act_type;
|
Atom act_type;
|
||||||
int act_format;
|
int act_format;
|
||||||
unsigned long nitems, bytes_after;
|
unsigned long nitems, bytes_after;
|
||||||
@@ -115,11 +142,11 @@ static Pixmap get_pixmap(Display* d, Window w) {
|
|||||||
|
|
||||||
if (XGetWindowProperty(d, w, id, 0, 1, False, XA_PIXMAP,
|
if (XGetWindowProperty(d, w, id, 0, 1, False, XA_PIXMAP,
|
||||||
&act_type, &act_format, &nitems, &bytes_after,
|
&act_type, &act_format, &nitems, &bytes_after,
|
||||||
&data) == Success) {
|
&data) == Success && data) {
|
||||||
if (data) {
|
|
||||||
p = *((Pixmap *) data);
|
p = *((Pixmap *) data);
|
||||||
XFree(data);
|
XFree(data);
|
||||||
}
|
} else {
|
||||||
|
p = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
@@ -133,31 +160,39 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
GLFWwindow* gwin = (GLFWwindow*) rd_get_impl_window(rd);
|
bool use_shm = true;
|
||||||
int x, y, w, h;
|
|
||||||
glfwGetFramebufferSize(gwin, &w, &h);
|
|
||||||
glfwGetWindowPos(gwin, &x, &y);
|
|
||||||
XColor c;
|
|
||||||
Display* d = glfwGetX11Display();
|
|
||||||
Pixmap p = get_pixmap(d, RootWindow(d, DefaultScreen(d)));
|
|
||||||
|
|
||||||
/* Obtain section of root pixmap using XShm */
|
int x, y, w, h;
|
||||||
|
rd_get_wcb(rd)->get_fbsize(rd_get_impl_window(rd), &w, &h);
|
||||||
|
rd_get_wcb(rd)->get_pos(rd_get_impl_window(rd), &x, &y);
|
||||||
|
XColor c;
|
||||||
|
Display* d = rd_get_wcb(rd)->get_x11_display();
|
||||||
|
Drawable src = get_drawable(d, find_desktop(rd));
|
||||||
|
|
||||||
|
/* Obtain section of root pixmap */
|
||||||
|
|
||||||
XShmSegmentInfo shminfo;
|
XShmSegmentInfo shminfo;
|
||||||
Visual* visual = DefaultVisual(d, DefaultScreen(d));
|
Visual* visual = DefaultVisual(d, DefaultScreen(d));
|
||||||
XVisualInfo match = { .visualid = XVisualIDFromVisual(visual) };
|
XVisualInfo match = { .visualid = XVisualIDFromVisual(visual) };
|
||||||
int nret;
|
int nret;
|
||||||
XVisualInfo* info = XGetVisualInfo(d, VisualIDMask, &match, &nret);
|
XVisualInfo* info = XGetVisualInfo(d, VisualIDMask, &match, &nret);
|
||||||
XImage* image = XShmCreateImage(d, visual, info->depth, ZPixmap, NULL,
|
XImage* image;
|
||||||
|
if (use_shm) {
|
||||||
|
image = XShmCreateImage(d, visual, info->depth, ZPixmap, NULL,
|
||||||
&shminfo, (unsigned int) w, (unsigned int) h);
|
&shminfo, (unsigned int) w, (unsigned int) h);
|
||||||
if ((shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, IPC_CREAT | 0777)) == -1) {
|
if ((shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
|
||||||
|
IPC_CREAT | 0777)) == -1) {
|
||||||
fprintf(stderr, "shmget() failed: %s\n", strerror(errno));
|
fprintf(stderr, "shmget() failed: %s\n", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
|
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
|
||||||
shminfo.readOnly = false;
|
shminfo.readOnly = false;
|
||||||
XShmAttach(d, &shminfo);
|
XShmAttach(d, &shminfo);
|
||||||
XShmGetImage(d, p, image, x, y, AllPlanes);
|
XShmGetImage(d, src, image, x, y, AllPlanes);
|
||||||
|
} else {
|
||||||
|
image = XGetImage(d, src, x, y, (unsigned int) w, (unsigned int) h,
|
||||||
|
ZPixmap, AllPlanes);
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to convert pixel bit depth to OpenGL storage format. The following formats\
|
/* Try to convert pixel bit depth to OpenGL storage format. The following formats\
|
||||||
will need intermediate conversion before OpenGL can accept the data:
|
will need intermediate conversion before OpenGL can accept the data:
|
||||||
@@ -165,6 +200,7 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
|
|||||||
- 8-bit pixel formats (retro displays, low-bandwidth virtual displays)
|
- 8-bit pixel formats (retro displays, low-bandwidth virtual displays)
|
||||||
- 36-bit pixel formats (rare deep color displays) */
|
- 36-bit pixel formats (rare deep color displays) */
|
||||||
|
|
||||||
|
if (image) {
|
||||||
bool invalid = false, aligned = false;
|
bool invalid = false, aligned = false;
|
||||||
GLenum type;
|
GLenum type;
|
||||||
switch (image->bits_per_pixel) {
|
switch (image->bits_per_pixel) {
|
||||||
@@ -233,12 +269,14 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
|
|||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, format, type, buf);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, format, type, buf);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); /* restore default */
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); /* restore default */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (use_shm) {
|
||||||
XShmDetach(d, &shminfo);
|
XShmDetach(d, &shminfo);
|
||||||
shmdt(shminfo.shmaddr);
|
shmdt(shminfo.shmaddr);
|
||||||
shmctl(shminfo.shmid, IPC_RMID, NULL);
|
shmctl(shminfo.shmid, IPC_RMID, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
XDestroyImage(image);
|
if (image) XDestroyImage(image);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|||||||
6
xwin.h
6
xwin.h
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
bool xwin_should_render(void);
|
bool xwin_should_render(struct renderer* rd);
|
||||||
void xwin_settype(struct renderer* rd, const char* type);
|
void xwin_settype(struct gl_wcb* wcb, void* impl, const char* type);
|
||||||
void xwin_addstate(struct renderer* rd, const char* state);
|
void xwin_addstate(struct gl_wcb* wcb, void* impl, const char* state);
|
||||||
unsigned int xwin_copyglbg(struct renderer* rd, unsigned int texture);
|
unsigned int xwin_copyglbg(struct renderer* rd, unsigned int texture);
|
||||||
|
|||||||
Reference in New Issue
Block a user