From 705ad3bee5de67725311d4085f0481fa7107ba41 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 11 Jan 2024 23:47:35 +0100 Subject: Render wallpaper --- build.sh | 1 + src/compositor.c | 74 +++++++++++++++++++++------ src/compositor.h | 4 ++ src/pixmap_texture.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/pixmap_texture.h | 28 +++++++++++ src/window_texture.c | 10 ++-- 6 files changed, 239 insertions(+), 18 deletions(-) create mode 100644 src/pixmap_texture.c create mode 100644 src/pixmap_texture.h diff --git a/build.sh b/build.sh index 4ae804d..b749f9f 100755 --- a/build.sh +++ b/build.sh @@ -13,5 +13,6 @@ includes="$(pkg-config --cflags $dependencies)" mkdir -p build $CC -c src/compositor.c -o build/compositor.o $opts $includes $CC -c src/window_texture.c -o build/window_texture.o $opts $includes +$CC -c src/pixmap_texture.c -o build/pixmap_texture.o $opts $includes $CC -c src/main.c -o build/main.o $opts $includes $CC build/*.o -o ngxc $opts $libs diff --git a/src/compositor.c b/src/compositor.c index 1e75d77..994404e 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1,9 +1,14 @@ #include "compositor.h" + #include #include #include #include +#include + +/* TODO: Handle wallpaper change and update on root window resize */ + static double clock_get_monotonic_seconds(void) { struct timespec ts; ts.tv_sec = 0; @@ -24,15 +29,50 @@ static ngxc_window* ngxc_compositor_get_window_by_id(ngxc_compositor *self, Wind return NULL; } +static Pixmap x11_wallpaper_get_pixmap(ngxc_compositor *self) { + const char *background_props[] = { + "_XROOTPMAP_ID", + "_XSETROOT_ID", + NULL + }; + + const Window root_window = DefaultRootWindow(self->dpy); + Pixmap wallpaper_pixmap = None; + + for(int i = 0; background_props[i]; ++i) { + const Atom atom = XInternAtom(self->dpy, background_props[i], False); + Atom actual_type; + int actual_format; + unsigned long items_count; + unsigned long bytes_after; + unsigned char *prop = NULL; + if(XGetWindowProperty(self->dpy, root_window, atom, 0, 1, False, XA_PIXMAP, &actual_type, &actual_format, &items_count, &bytes_after, &prop) == Success && prop) { + wallpaper_pixmap = *(Pixmap*)prop; + XFree(prop); + break; + } + + if(prop) + XFree(prop); + } + + return wallpaper_pixmap; +} + void ngxc_compositor_init(ngxc_compositor *self, Display *dpy, Window composite_window) { memset(self, 0, sizeof(*self)); self->dpy = dpy; self->composite_window = composite_window; self->frame_timer = clock_get_monotonic_seconds(); + + const Pixmap wallpaper_pixmap = x11_wallpaper_get_pixmap(self); + if(!ngxc_pixmap_texture_init(&self->wallpaper_texture, self->dpy, wallpaper_pixmap)) { + fprintf(stderr, "error: failed to create texture for wallpaper pixmap %ld\n", wallpaper_pixmap); + } } void ngxc_compositor_deinit(ngxc_compositor *self) { - + /* TODO: Cleanup? */ } void ngxc_compositor_add_window(ngxc_compositor *self, Window window) { @@ -101,7 +141,7 @@ void ngxc_compositor_remove_window(ngxc_compositor *self, Window window) { } } -static void render_texture(const ngxc_window *window) { +static void render_texture(GLuint texture_id, int x, int y, int width, int height) { float matrix[16] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -109,28 +149,28 @@ static void render_texture(const ngxc_window *window) { 0.0f, 0.0f, 0.0f, 1.0f, }; - matrix[0] = 1.0f / (float)window->texture.width; - matrix[5] = 1.0f / (float)window->texture.height; + matrix[0] = 1.0f / (float)width; + matrix[5] = 1.0f / (float)height; glMatrixMode(GL_TEXTURE); glLoadMatrixf(matrix); glMatrixMode(GL_MODELVIEW); - glBindTexture(GL_TEXTURE_2D, window->texture.texture_id); + glBindTexture(GL_TEXTURE_2D, texture_id); glColor4ub(255, 255, 255, 255); - //glTranslatef(window->x, window->y, 0.0f); + //glTranslatef(x, y, 0.0f); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); - glVertex2f(window->x, window->y); + glVertex2f(x, y); - glTexCoord2f(window->texture.width, 0.0f); - glVertex2f(window->x + window->texture.width, window->y); + glTexCoord2f(width, 0.0f); + glVertex2f(x + width, y); - glTexCoord2f(window->texture.width, window->texture.height); - glVertex2f(window->x + window->texture.width, window->y + window->texture.height); + glTexCoord2f(width, height); + glVertex2f(x + width, y + height); - glTexCoord2f(0.0f, window->texture.height); - glVertex2f(window->x, window->y + window->texture.height); + glTexCoord2f(0.0f, height); + glVertex2f(x, y + height); glEnd(); glLoadIdentity(); @@ -140,12 +180,16 @@ static void render_texture(const ngxc_window *window) { /* TODO: Skip windows that are not visible on the screen */ /* TODO: Disable compositing for fullscreen windows, if that option is enabled */ void ngxc_compositor_render(ngxc_compositor *self) { - glClearColor(1.0f, 0.0f, 0.0f, 1.0f); + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); + if(self->wallpaper_texture.texture_id > 0) { + render_texture(self->wallpaper_texture.texture_id, 0, 0, self->wallpaper_texture.width, self->wallpaper_texture.height); + } + for(int i = 0; i < self->num_windows; ++i) { const ngxc_window *window_obj = &self->windows[i]; - render_texture(window_obj); + render_texture(window_obj->texture.texture_id, window_obj->x, window_obj->y, window_obj->texture.width, window_obj->texture.height); } const double now = clock_get_monotonic_seconds(); diff --git a/src/compositor.h b/src/compositor.h index cf520d5..f6db300 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -2,6 +2,7 @@ #define NGXC_COMPOSITOR_H #include "window_texture.h" +#include "pixmap_texture.h" // TODO: Make dynamic #define NGXC_COMPOSITOR_MAX_WINDOWS 100 @@ -16,6 +17,9 @@ typedef struct { Display *dpy; Window composite_window; double frame_timer; + + ngxc_pixmap_texture wallpaper_texture; + ngxc_window windows[NGXC_COMPOSITOR_MAX_WINDOWS]; int num_windows; } ngxc_compositor; diff --git a/src/pixmap_texture.c b/src/pixmap_texture.c new file mode 100644 index 0000000..b31b346 --- /dev/null +++ b/src/pixmap_texture.c @@ -0,0 +1,140 @@ +#include "pixmap_texture.h" + +#include + +bool ngxc_pixmap_texture_init(ngxc_pixmap_texture *window_texture, Display *display, Pixmap pixmap) { + window_texture->display = display; + window_texture->pixmap = pixmap; + window_texture->glx_pixmap = None; + window_texture->texture_id = 0; + window_texture->width = 0; + window_texture->height = 0; + return ngxc_pixmap_texture_on_resize(window_texture); +} + +static void ngxc_pixmap_texture_cleanup(ngxc_pixmap_texture *self, int delete_texture) { + if(delete_texture && self->texture_id) { + glDeleteTextures(1, &self->texture_id); + self->texture_id = 0; + } + + if(self->glx_pixmap) { + glXDestroyPixmap(self->display, self->glx_pixmap); + glXReleaseTexImageEXT(self->display, self->glx_pixmap, GLX_FRONT_EXT); + self->glx_pixmap = None; + } +} + +void ngxc_pixmap_texture_deinit(ngxc_pixmap_texture *self) { + ngxc_pixmap_texture_cleanup(self, 1); +} + +bool ngxc_pixmap_texture_on_resize(ngxc_pixmap_texture *self) { + ngxc_pixmap_texture_cleanup(self, 0); + + GLXFBConfig *configs = NULL; + GLXPixmap glx_pixmap = None; + GLuint texture_id = 0; + int glx_pixmap_bound = 0; + + const int pixmap_config[] = { + GLX_BIND_TO_TEXTURE_RGB_EXT, True, + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT, + GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, + /*GLX_BIND_TO_MIPMAP_TEXTURE_EXT, True,*/ + GLX_BUFFER_SIZE, 24, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 0, + None + }; + + const int pixmap_attribs[] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, + /*GLX_MIPMAP_TEXTURE_EXT, True,*/ + None + }; + + Window root_window; + int x, y; + unsigned int width = 0; + unsigned int height = 0; + unsigned int border_width; + unsigned int depth = 32; + if(!XGetGeometry(self->display, self->pixmap, &root_window, &x, &y, &width, &height, &border_width, &depth)) { + fprintf(stderr, "Failed to get pixmap attributes\n"); + return false; + } + + GLXFBConfig config; + int c; + configs = glXChooseFBConfig(self->display, 0, pixmap_config, &c); + if(!configs) { + fprintf(stderr, "Failed to choose fb config\n"); + return false; + } + + int found = 0; + for (int i = 0; i < c; i++) { + config = configs[i]; + XVisualInfo *visual = glXGetVisualFromFBConfig(self->display, config); + if(!visual) + continue; + + if((int)depth != visual->depth) { + XFree(visual); + continue; + } + XFree(visual); + found = 1; + break; + } + + if(!found) { + fprintf(stderr, "No matching fb config found\n"); + goto cleanup; + } + + glx_pixmap = glXCreatePixmap(self->display, config, self->pixmap, pixmap_attribs); + if(!glx_pixmap) { + goto cleanup; + } + + if(self->texture_id == 0) { + glGenTextures(1, &texture_id); + if(texture_id == 0) { + goto cleanup; + } + glBindTexture(GL_TEXTURE_2D, texture_id); + } else { + glBindTexture(GL_TEXTURE_2D, self->texture_id); + } + + glXBindTexImageEXT(self->display, glx_pixmap, GLX_FRONT_EXT, NULL); + glx_pixmap_bound = 1; + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + + glBindTexture(GL_TEXTURE_2D, 0); + + self->width = width; + self->height = height; + + XFree(configs); + self->glx_pixmap = glx_pixmap; + if(texture_id != 0) + self->texture_id = texture_id; + return true; + + cleanup: + if(texture_id != 0) glDeleteTextures(1, &texture_id); + if(glx_pixmap) glXDestroyPixmap(self->display, glx_pixmap); + if(glx_pixmap_bound) glXReleaseTexImageEXT(self->display, glx_pixmap, GLX_FRONT_EXT); + if(configs) XFree(configs); + return false; +} diff --git a/src/pixmap_texture.h b/src/pixmap_texture.h new file mode 100644 index 0000000..37f7ec4 --- /dev/null +++ b/src/pixmap_texture.h @@ -0,0 +1,28 @@ +#ifndef NGXC_PIXMAP_TEXTURE_H +#define NGXC_PIXMAP_TEXTURE_H + +#include + +#define GLX_GLXEXT_PROTOTYPES +#include +#include +#include + +typedef struct { + Display *display; + Pixmap pixmap; + GLXPixmap glx_pixmap; + GLuint texture_id; + int width; + int height; +} ngxc_pixmap_texture; + +bool ngxc_pixmap_texture_init(ngxc_pixmap_texture *self, Display *display, Pixmap pixmap); +void ngxc_pixmap_texture_deinit(ngxc_pixmap_texture *self); + +/* + This should ONLY be called when the pixmap is resized. +*/ +bool ngxc_pixmap_texture_on_resize(ngxc_pixmap_texture *self); + +#endif /* NGXC_PIXMAP_TEXTURE_H */ diff --git a/src/window_texture.c b/src/window_texture.c index c3bde72..bd4c558 100644 --- a/src/window_texture.c +++ b/src/window_texture.c @@ -1,7 +1,11 @@ #include "window_texture.h" -#include + #include +#include + +/* TODO: Use pixmap_texture for window_texture */ + int window_texture_init(WindowTexture *window_texture, Display *display, Window window) { window_texture->display = display; window_texture->window = window; @@ -137,8 +141,8 @@ int window_texture_on_resize(WindowTexture *self) { glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); /* float fLargest = 0.0f; -- cgit v1.2.3