Added GLX window creation backend, addresses #18
This commit is contained in:
16
Makefile
16
Makefile
@@ -38,20 +38,30 @@ ifeq ($(INSTALL),unix)
|
||||
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)
|
||||
CFLAGS_INSTALL = -DGLAVA_OSX
|
||||
SHADER_DIR = Library/glava
|
||||
endif
|
||||
|
||||
LDFLAGS = $(ASAN) -lpulse -lpulse-simple -pthread -lglfw -ldl -lm -lX11 -lXext -lXcomposite
|
||||
LDFLAGS = $(ASAN) -lpulse -lpulse-simple -pthread $(LDFLAGS_GLFW) -ldl -lm -lX11 -lXext $(LDFLAGS_GLX)
|
||||
|
||||
PYTHON = python
|
||||
|
||||
GLAD_INSTALL_DIR = glad
|
||||
GLAD_SRCFILE = ./glad/src/glad.c
|
||||
GLAD_ARGS = --generator=$(GLAD_GEN) --extensions=GL_EXT_framebuffer_multisample,GL_EXT_texture_filter_anisotropic
|
||||
CFLAGS_COMMON = -DGLAVA_GLFW -DGLAVA_GLX -I glad/include
|
||||
CFLAGS_USE = $(CFLAGS_COMMON) $(CFLAGS_BUILD) $(CFLAGS_INSTALL) $(CFLAGS)
|
||||
CFLAGS_COMMON = -I glad/include
|
||||
CFLAGS_USE = $(CFLAGS_COMMON) $(CFLAGS_GLX) $(CFLAGS_GLFW) $(CFLAGS_BUILD) $(CFLAGS_INSTALL) $(CFLAGS)
|
||||
|
||||
all: glava
|
||||
|
||||
|
||||
14
README.md
14
README.md
@@ -19,7 +19,7 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
|
||||
|
||||
- X11
|
||||
- PulseAudio
|
||||
- GLFW 3.1+
|
||||
- GLFW 3.1+ (optional, disable with `DISABLE_GLFW=1`)
|
||||
- Linux or BSD
|
||||
|
||||
**Additional compile time requirements:**
|
||||
@@ -27,8 +27,9 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
|
||||
- glad (included as a submodule)
|
||||
- python (required to generate bindings with glad)
|
||||
- GCC (this program uses GNU C features)
|
||||
- GLX headers (optional, disable direct GLX support with `DISABLE_GLX=1`), usually the development packages for `libgl` include this on your distro
|
||||
|
||||
**Ubuntu/Debian users:** the following command ensures you have all the needed packages and headers to compile and run GLava:
|
||||
**Ubuntu/Debian users:** the following command ensures you have all the needed packages and headers to compile GLava:
|
||||
```bash
|
||||
sudo apt-get install libpulse libpulse-dev libglfw3 libglfw3-dev libxext6 libxext6-dev python make gcc
|
||||
```
|
||||
@@ -43,28 +44,25 @@ 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.
|
||||
|
||||
**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
|
||||
|
||||
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
|
||||
| :---: | --- | --- |
|
||||
| GNOME (on X11) |  | No notable issues
|
||||
| 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/)
|
||||
| Xfwm (XFCE) |  | Untested, but should work without issues
|
||||
| Fluxbox |  | Untested, but should work without issues
|
||||
| iceWM |  | No notable issues
|
||||
| AwesomeWM |  | Requires the WM to be restarted (`Super + Ctl + R`) in order for new desktop windows to behave correctly, can still be focused, may require other changes to config depending on layout
|
||||
| Budgie Desktop |  | `"xroot"` transparency breaks with Budgie's wallpaper window
|
||||
| Herbstluftwm |  | `hc rule windowtype~'_NET_WM_WINDOW_TYPE_DESKTOP' manage=off` can be used to unmanage desktop windows
|
||||
| AwesomeWM |  | Can still be focused, may require other changes to config depending on layout
|
||||
| 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)
|
||||
| EXWM |  | EXWM does not have a desktop, and forces window decorations
|
||||
| Unity |  | Needs testing
|
||||
| Enlightenment |  | Needs testing
|
||||
| Bspwm |  | Needs testing
|
||||
| Herbstluftwm |  | Needs testing
|
||||
| xmonad |  | Needs testing
|
||||
| Any non EWMH-compliant WM |  | Window types and hints will not work if the window manager does not support the EWMH standards.
|
||||
|
||||
|
||||
12
glava.c
12
glava.c
@@ -18,7 +18,7 @@
|
||||
#include "render.h"
|
||||
#include "xwin.h"
|
||||
|
||||
#define GLAVA_VERSION "1.3"
|
||||
#define GLAVA_VERSION "1.4"
|
||||
#ifdef GLAD_DEBUG
|
||||
#define GLAVA_RELEASE_TYPE_PREFIX "debug, "
|
||||
#else
|
||||
@@ -167,18 +167,22 @@ static const char* help_str =
|
||||
"-C, --copy-config creates copies and symbolic links in the user configuration\n"
|
||||
" directory for glava, copying any files in the root directory\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"
|
||||
"\n"
|
||||
GLAVA_VERSION_STRING "\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[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"entry", required_argument, 0, 'e'},
|
||||
{"force-mod", required_argument, 0, 'm'},
|
||||
{"copy-config", no_argument, 0, 'C'},
|
||||
{"backend", required_argument, 0, 'b'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
@@ -190,6 +194,7 @@ int main(int argc, char** argv) {
|
||||
const char* user_path = SHADER_USER_PATH;
|
||||
const char* entry = "rc.glsl";
|
||||
const char* force = NULL;
|
||||
const char* backend = NULL;
|
||||
const char* system_shader_paths[] = { user_path, install_path, NULL };
|
||||
bool verbose = false;
|
||||
bool copy_mode = false;
|
||||
@@ -201,6 +206,7 @@ int main(int argc, char** argv) {
|
||||
case 'C': copy_mode = true; break;
|
||||
case 'e': entry = optarg; break;
|
||||
case 'm': force = optarg; break;
|
||||
case 'b': backend = optarg; break;
|
||||
case '?': exit(EXIT_FAILURE); break;
|
||||
case 'V':
|
||||
puts(GLAVA_VERSION_STRING);
|
||||
@@ -219,7 +225,7 @@ int main(int argc, char** argv) {
|
||||
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];
|
||||
size_t t;
|
||||
|
||||
10
glfw_wcb.c
10
glfw_wcb.c
@@ -37,9 +37,9 @@
|
||||
#endif
|
||||
|
||||
#define DECL_WINDOW_HINT(F, H) \
|
||||
static void F(void* _, bool var) { glfwWindowHint(H, var); }
|
||||
static void F(bool var) { glfwWindowHint(H, var); }
|
||||
#define DECL_WINDOW_HINT_STUB(F) \
|
||||
static void F(void* _, bool _) { fprintf(stderr, "Warning: " #F " not implemented for GLFW backend\n"); }
|
||||
static void F(bool _) { fprintf(stderr, "Warning: " #F " not implemented for GLFW backend\n"); }
|
||||
|
||||
static void init(void) {
|
||||
if (!glfwInit()) {
|
||||
@@ -97,7 +97,7 @@ static void* create_and_bind(const char* name, const char* class,
|
||||
return w;
|
||||
}
|
||||
|
||||
static void set_transparent(GLFWwindow* w, bool transparent) {
|
||||
static void set_transparent(bool transparent) {
|
||||
#ifdef GLFW_TRANSPARENT_FRAMEBUFFER
|
||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, transparent ? GLFW_TRUE : GLFW_FALSE);
|
||||
#elif GLFW_TRANSPARENT
|
||||
@@ -124,14 +124,14 @@ static bool swap_buffers(GLFWwindow* w) {
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
static Display* get_x11_display(GLFWwindow* w) { return glfwGetX11Display(); }
|
||||
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 (GLFWwindow* w, int i) { glfwSwapInterval(i); }
|
||||
static void set_swap (int i) { glfwSwapInterval(i); }
|
||||
|
||||
WCB_ATTACH("glfw", wcb_glfw);
|
||||
|
||||
|
||||
279
glx_wcb.c
Normal file
279
glx_wcb.c
Normal file
@@ -0,0 +1,279 @@
|
||||
|
||||
/* 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;
|
||||
GC gc;
|
||||
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");
|
||||
}
|
||||
|
||||
apply_decorations(w->w);
|
||||
|
||||
XFree(vi);
|
||||
|
||||
gc = XCreateGC(display, w->w, 0, 0);
|
||||
|
||||
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 */
|
||||
65
render.c
65
render.c
@@ -35,18 +35,17 @@
|
||||
#define VERTEX_SHADER_SRC \
|
||||
"layout(location = 0) in vec3 pos; void main() { gl_Position = vec4(pos.x, pos.y, 0.0F, 1.0F); }"
|
||||
|
||||
/* Window creation backend interfaces */
|
||||
#ifdef GLAVA_GLFW
|
||||
extern struct gl_wcb wcb_glfw;
|
||||
#endif
|
||||
struct gl_wcb* wcbs[2] = {};
|
||||
static size_t wcbs_idx = 0;
|
||||
|
||||
#define INIT_WCBS() \
|
||||
static inline void register_wcb(struct gl_wcb* wcb) { wcbs[wcbs_idx++] = wcb; }
|
||||
|
||||
#define DECL_WCB(N) \
|
||||
do { \
|
||||
wcbs[0] = wcb_glfw; \
|
||||
extern struct gl_wcb N; \
|
||||
register_wcb(&N); \
|
||||
} while (0)
|
||||
|
||||
struct gl_wcb wcbs[2] = {};
|
||||
|
||||
/* GLSL bind source */
|
||||
|
||||
struct gl_bind_src {
|
||||
@@ -682,7 +681,8 @@ static struct gl_bind_src* lookup_bind_src(const char* str) {
|
||||
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));
|
||||
*r = (struct renderer) {
|
||||
@@ -727,19 +727,40 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F }
|
||||
};
|
||||
|
||||
const char* backend = "glfw";
|
||||
bool forced = force_backend != NULL;
|
||||
const char* backend = force_backend;
|
||||
|
||||
INIT_WCBS();
|
||||
/* Window creation backend interfaces */
|
||||
#ifdef GLAVA_GLFW
|
||||
DECL_WCB(wcb_glfw);
|
||||
if (!forced) backend = "glfw";
|
||||
#endif
|
||||
|
||||
#ifdef GLAVA_UNIX
|
||||
if (!getenv("WAYLAND_DISPLAY") && getenv("DISPLAY")) {
|
||||
// backend = "glx";
|
||||
#ifdef GLAVA_GLX
|
||||
DECL_WCB(wcb_glx);
|
||||
if (!forced && !getenv("WAYLAND_DISPLAY") && getenv("DISPLAY")) {
|
||||
backend = "glx";
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t t = 0; t < sizeof(wcbs) / sizeof(*wcbs); ++t) {
|
||||
if (wcbs[t].name && !strcmp(wcbs[t].name, backend)) {
|
||||
gl->wcb = &wcbs[t];
|
||||
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;
|
||||
}
|
||||
};
|
||||
@@ -773,7 +794,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
|
||||
#define WINDOW_HINT(request) \
|
||||
{ .name = "set" #request, .fmt = "b", \
|
||||
.handler = RHANDLER(name, args, { gl->wcb->set_##request(gl->w, *(bool*) args[0]); }) }
|
||||
.handler = RHANDLER(name, args, { gl->wcb->set_##request(*(bool*) args[0]); }) }
|
||||
|
||||
struct request_handler handlers[] = {
|
||||
{
|
||||
@@ -784,7 +805,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
|
||||
gl->use_alpha = true;
|
||||
|
||||
gl->wcb->set_transparent(gl->w, native_opacity);
|
||||
gl->wcb->set_transparent(native_opacity);
|
||||
|
||||
if (!strcmp("xroot", (char*) args[0]))
|
||||
gl->copy_desktop = true;
|
||||
@@ -870,7 +891,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
{ .name = "setshaderversion", .fmt = "i",
|
||||
.handler = RHANDLER(name, args, { shader_version = *(int*) args[0]; }) },
|
||||
{ .name = "setswap", .fmt = "i",
|
||||
.handler = RHANDLER(name, args, { gl->wcb->set_swap(gl->w, *(int*) args[0]); }) },
|
||||
.handler = RHANDLER(name, args, { gl->wcb->set_swap(*(int*) args[0]); }) },
|
||||
{ .name = "setframerate", .fmt = "i",
|
||||
.handler = RHANDLER(name, args, { gl->rate = *(int*) args[0]; }) },
|
||||
{ .name = "setprintframes", .fmt = "b",
|
||||
@@ -1334,8 +1355,8 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
"out vec4 fragment;" "\n"
|
||||
"in vec4 gl_FragCoord;" "\n"
|
||||
"void main() {" "\n"
|
||||
" fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, " "\n"
|
||||
" (screen.y - gl_FragCoord.y) / screen.y));" "\n"
|
||||
" fragment = texelFetch(tex, ivec2(gl_FragCoord.x, " "\n"
|
||||
" screen.y - gl_FragCoord.y), 0);" "\n"
|
||||
" fragment.a = 1.0F;" "\n"
|
||||
"}" "\n";
|
||||
if (!setup) {
|
||||
|
||||
16
render.h
16
render.h
@@ -12,7 +12,7 @@ typedef struct renderer {
|
||||
} renderer;
|
||||
|
||||
struct renderer* rd_new (const char** paths, const char* entry,
|
||||
const char* force_mod);
|
||||
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*);
|
||||
@@ -22,7 +22,7 @@ struct gl_wcb* rd_get_wcb (struct renderer*);
|
||||
|
||||
/* gl_wcb - OpenGL Window Creation Backend interface */
|
||||
struct gl_wcb {
|
||||
const char* name;\
|
||||
const char* name;
|
||||
void (*init) (void);
|
||||
void* (*create_and_bind)(const char* name, const char* class,
|
||||
const char* type, const char** states,
|
||||
@@ -32,15 +32,15 @@ struct gl_wcb {
|
||||
int version_major, int version_minor);
|
||||
bool (*should_close) (void* ptr);
|
||||
bool (*swap_buffers) (void* ptr);
|
||||
void (*set_swap) (void* ptr, int interval);
|
||||
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_floating) (void* ptr, bool floating);
|
||||
void (*set_decorated) (void* ptr, bool decorated);
|
||||
void (*set_focused) (void* ptr, bool focused);
|
||||
void (*set_maximized) (void* ptr, bool maximized);
|
||||
void (*set_transparent)(void* ptr, bool transparent);
|
||||
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);
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#request settitle "GLava"
|
||||
|
||||
/* GLFW window geometry (x, y, width, height) */
|
||||
#request setgeometry 0 0 400 600
|
||||
#request setgeometry 0 0 800 600
|
||||
|
||||
/* Window background color (RGB format).
|
||||
Only works with `setopacity "none"` */
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
https://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#idm140130317606816
|
||||
*/
|
||||
#request setxwintype "normal"
|
||||
#request setxwintype "desktop"
|
||||
|
||||
/* (X11 only) EWMH Window state atoms (multiple can be specified).
|
||||
Possible values are:
|
||||
|
||||
Reference in New Issue
Block a user