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
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
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
|
- 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) |  | 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/)
|
| 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
|
||||||
| 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
|
| Herbstluftwm |  | `hc rule windowtype~'_NET_WM_WINDOW_TYPE_DESKTOP' manage=off` can be used to unmanage desktop windows
|
||||||
| Budgie Desktop |  | `"xroot"` transparency breaks with Budgie's wallpaper window
|
| 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
|
| 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
|
||||||
| Unity |  | Needs testing
|
| Unity |  | Needs testing
|
||||||
| Enlightenment |  | Needs testing
|
| Enlightenment |  | Needs testing
|
||||||
| Bspwm |  | Needs testing
|
| Bspwm |  | Needs testing
|
||||||
| Herbstluftwm |  | Needs testing
|
|
||||||
| xmonad |  | 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.
|
| 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 "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;
|
||||||
|
|||||||
10
glfw_wcb.c
10
glfw_wcb.c
@@ -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
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 \
|
#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) {
|
||||||
|
|||||||
16
render.h
16
render.h
@@ -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);
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user