Added GLX window creation backend, addresses #18

This commit is contained in:
Jarcode
2018-02-12 12:47:59 -08:00
parent 4fd4ce4c3f
commit f021457abd
8 changed files with 365 additions and 51 deletions

View File

@@ -38,20 +38,30 @@ 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 -lXcomposite LDFLAGS = $(ASAN) -lpulse -lpulse-simple -pthread $(LDFLAGS_GLFW) -ldl -lm -lX11 -lXext $(LDFLAGS_GLX)
PYTHON = python PYTHON = python
GLAD_INSTALL_DIR = glad 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 = -DGLAVA_GLFW -DGLAVA_GLX -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

View File

@@ -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,8 +27,9 @@ 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 and run GLava: **Ubuntu/Debian users:** the following command ensures you have all the needed packages and headers to compile GLava:
```bash ```bash
sudo apt-get install libpulse libpulse-dev libglfw3 libglfw3-dev libxext6 libxext6-dev python make gcc 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. \* 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
| :---: | --- | --- | | :---: | --- | --- |
| GNOME (on X11) | ![-](https://placehold.it/15/118932/000000?text=+) | No notable issues | Mutter (GNOME, Budgie) | ![-](https://placehold.it/15/118932/000000?text=+) | `"native"` (default) opacity should be used
| Openbox (LXDE or standalone) | ![-](https://placehold.it/15/118932/000000?text=+) | [Some tweaks may be required](https://www.reddit.com/r/unixporn/comments/7vcgi4/oc_after_receiving_positive_feedback_here_i/dtrkvja/) | Openbox (LXDE or standalone) | ![-](https://placehold.it/15/118932/000000?text=+) | [Some tweaks may be required](https://www.reddit.com/r/unixporn/comments/7vcgi4/oc_after_receiving_positive_feedback_here_i/dtrkvja/)
| Xfwm (XFCE) | ![-](https://placehold.it/15/118932/000000?text=+) | Untested, but should work without issues | Xfwm (XFCE) | ![-](https://placehold.it/15/118932/000000?text=+) | Untested, but should work without issues
| Fluxbox | ![-](https://placehold.it/15/118932/000000?text=+) | Untested, but should work without issues | Fluxbox | ![-](https://placehold.it/15/118932/000000?text=+) | Untested, but should work without issues
| iceWM | ![-](https://placehold.it/15/118932/000000?text=+) | No notable issues | iceWM | ![-](https://placehold.it/15/118932/000000?text=+) | No notable issues
| AwesomeWM | ![-](https://placehold.it/15/f09c00/000000?text=+) | Requires the WM to be restarted (`Super + Ctl + R`) in order for new desktop windows to behave correctly, can still be focused, may require other changes to config depending on layout | Herbstluftwm | ![-](https://placehold.it/15/118932/000000?text=+) | `hc rule windowtype~'_NET_WM_WINDOW_TYPE_DESKTOP' manage=off` can be used to unmanage desktop windows
| Budgie Desktop | ![-](https://placehold.it/15/f09c00/000000?text=+) | `"xroot"` transparency breaks with Budgie's wallpaper window | AwesomeWM | ![-](https://placehold.it/15/f09c00/000000?text=+) | Can still be focused, may require other changes to config depending on layout
| kwin (KDE) | ![-](https://placehold.it/15/f09c00/000000?text=+) | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing | kwin (KDE) | ![-](https://placehold.it/15/f09c00/000000?text=+) | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing
| i3 (and i3-gaps) | ![-](https://placehold.it/15/f03c15/000000?text=+) | [i3 does not respect the `"desktop"` window type](https://github.com/wacossusca34/glava/issues/6) | i3 (and i3-gaps) | ![-](https://placehold.it/15/f03c15/000000?text=+) | [i3 does not respect the `"desktop"` window type](https://github.com/wacossusca34/glava/issues/6)
| EXWM | ![-](https://placehold.it/15/f03c15/000000?text=+) | EXWM does not have a desktop, and forces window decorations | EXWM | ![-](https://placehold.it/15/f03c15/000000?text=+) | EXWM does not have a desktop, and forces window decorations
| Unity | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing | Unity | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Enlightenment | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing | Enlightenment | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Bspwm | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing | Bspwm | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Herbstluftwm | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| xmonad | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing | xmonad | ![-](https://placehold.it/15/1589F0/000000?text=+) | Needs testing
| Any non EWMH-compliant WM | ![-](https://placehold.it/15/f03c15/000000?text=+) | Window types and hints will not work if the window manager does not support the EWMH standards. | Any non EWMH-compliant WM | ![-](https://placehold.it/15/f03c15/000000?text=+) | Window types and hints will not work if the window manager does not support the EWMH standards.

12
glava.c
View File

@@ -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;

View File

@@ -37,9 +37,9 @@
#endif #endif
#define DECL_WINDOW_HINT(F, H) \ #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) \ #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) { static void init(void) {
if (!glfwInit()) { if (!glfwInit()) {
@@ -97,7 +97,7 @@ static void* create_and_bind(const char* name, const char* class,
return w; return w;
} }
static void set_transparent(GLFWwindow* w, bool transparent) { static void set_transparent(bool transparent) {
#ifdef GLFW_TRANSPARENT_FRAMEBUFFER #ifdef GLFW_TRANSPARENT_FRAMEBUFFER
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, transparent ? GLFW_TRUE : GLFW_FALSE); glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, transparent ? GLFW_TRUE : GLFW_FALSE);
#elif GLFW_TRANSPARENT #elif GLFW_TRANSPARENT
@@ -124,14 +124,14 @@ static bool swap_buffers(GLFWwindow* w) {
glfwPollEvents(); 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 Window get_x11_window (GLFWwindow* w) { return glfwGetX11Window(w); }
static bool should_close (GLFWwindow* w) { return glfwWindowShouldClose(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_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 void get_pos (GLFWwindow* w, int* x, int* y) { glfwGetWindowPos(w, x, y); }
static double get_time (GLFWwindow* w) { return glfwGetTime(); } static double get_time (GLFWwindow* w) { return glfwGetTime(); }
static void set_time (GLFWwindow* w, double time) { glfwSetTime(time); } 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); WCB_ATTACH("glfw", wcb_glfw);

279
glx_wcb.c Normal file
View 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 */

View File

@@ -35,18 +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); }"
/* Window creation backend interfaces */ struct gl_wcb* wcbs[2] = {};
#ifdef GLAVA_GLFW static size_t wcbs_idx = 0;
extern struct gl_wcb wcb_glfw;
#endif
#define INIT_WCBS() \ static inline void register_wcb(struct gl_wcb* wcb) { wcbs[wcbs_idx++] = wcb; }
#define DECL_WCB(N) \
do { \ do { \
wcbs[0] = wcb_glfw; \ extern struct gl_wcb N; \
register_wcb(&N); \
} while (0) } while (0)
struct gl_wcb wcbs[2] = {};
/* GLSL bind source */ /* GLSL bind source */
struct gl_bind_src { struct gl_bind_src {
@@ -682,7 +681,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) {
@@ -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 } .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 #ifdef GLAVA_GLX
if (!getenv("WAYLAND_DISPLAY") && getenv("DISPLAY")) { DECL_WCB(wcb_glx);
// backend = "glx"; if (!forced && !getenv("WAYLAND_DISPLAY") && getenv("DISPLAY")) {
backend = "glx";
} }
#endif #endif
for (size_t t = 0; t < sizeof(wcbs) / sizeof(*wcbs); ++t) { if (!backend) {
if (wcbs[t].name && !strcmp(wcbs[t].name, backend)) { fprintf(stderr, "No backend available for the active windowing system\n");
gl->wcb = &wcbs[t]; 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; break;
} }
}; };
@@ -773,7 +794,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
#define WINDOW_HINT(request) \ #define WINDOW_HINT(request) \
{ .name = "set" #request, .fmt = "b", \ { .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[] = { 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->use_alpha = true;
gl->wcb->set_transparent(gl->w, native_opacity); gl->wcb->set_transparent(native_opacity);
if (!strcmp("xroot", (char*) args[0])) if (!strcmp("xroot", (char*) args[0]))
gl->copy_desktop = true; 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", { .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, { gl->wcb->set_swap(gl->w, *(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",
@@ -1334,8 +1355,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) {

View File

@@ -12,7 +12,7 @@ typedef struct renderer {
} renderer; } renderer;
struct renderer* rd_new (const char** paths, const char* entry, 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, void rd_update (struct renderer*, float* lb, float* rb,
size_t bsz, bool modified); size_t bsz, bool modified);
void rd_destroy (struct renderer*); void rd_destroy (struct renderer*);
@@ -22,7 +22,7 @@ struct gl_wcb* rd_get_wcb (struct renderer*);
/* gl_wcb - OpenGL Window Creation Backend interface */ /* gl_wcb - OpenGL Window Creation Backend interface */
struct gl_wcb { struct gl_wcb {
const char* name;\ const char* name;
void (*init) (void); void (*init) (void);
void* (*create_and_bind)(const char* name, const char* class, void* (*create_and_bind)(const char* name, const char* class,
const char* type, const char** states, const char* type, const char** states,
@@ -32,15 +32,15 @@ struct gl_wcb {
int version_major, int version_minor); int version_major, int version_minor);
bool (*should_close) (void* ptr); bool (*should_close) (void* ptr);
bool (*swap_buffers) (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_pos) (void* ptr, int* x, int* y);
void (*get_fbsize) (void* ptr, int* w, int* h); void (*get_fbsize) (void* ptr, int* w, int* h);
void (*set_geometry) (void* ptr, int x, int y, 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_swap) (int interval);
void (*set_decorated) (void* ptr, bool decorated); void (*set_floating) (bool floating);
void (*set_focused) (void* ptr, bool focused); void (*set_decorated) (bool decorated);
void (*set_maximized) (void* ptr, bool maximized); void (*set_focused) (bool focused);
void (*set_transparent)(void* ptr, bool transparent); void (*set_maximized) (bool maximized);
void (*set_transparent)(bool transparent);
double (*get_time) (void* ptr); double (*get_time) (void* ptr);
void (*set_time) (void* ptr, double time); void (*set_time) (void* ptr, double time);
void (*set_visible) (void* ptr, bool visible); void (*set_visible) (void* ptr, bool visible);

View File

@@ -51,7 +51,7 @@
#request settitle "GLava" #request settitle "GLava"
/* GLFW window geometry (x, y, width, height) */ /* GLFW 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"` */ Only works with `setopacity "none"` */
@@ -68,7 +68,7 @@
https://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#idm140130317606816 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). /* (X11 only) EWMH Window state atoms (multiple can be specified).
Possible values are: Possible values are: