aboutsummaryrefslogtreecommitdiff
path: root/src/compositor.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2024-01-11 20:18:34 +0100
committerdec05eba <dec05eba@protonmail.com>2024-01-11 20:18:34 +0100
commit2b9389ae016c8048a16ba033f27ca5c256985e4d (patch)
tree56665698e299fe9a5754be2607719369059e5c53 /src/compositor.c
parentf3d89d03acaad7ebd750d9a39e4ca8c589de4782 (diff)
Display windows with minimal delay, locked to 60 fps
Diffstat (limited to 'src/compositor.c')
-rw-r--r--src/compositor.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/compositor.c b/src/compositor.c
new file mode 100644
index 0000000..4b622c0
--- /dev/null
+++ b/src/compositor.c
@@ -0,0 +1,150 @@
+#include "compositor.h"
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
+static double clock_get_monotonic_seconds(void) {
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (double)ts.tv_sec + (double)ts.tv_nsec * 0.000000001;
+}
+
+static ngxc_window* ngxc_compositor_get_window_by_id(ngxc_compositor *self, Window window) {
+ for(int i = 0; i < self->num_windows; ++i) {
+ ngxc_window *window_obj = &self->windows[i];
+ if(window_obj->texture.window == window)
+ return window_obj;
+ }
+ return NULL;
+}
+
+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();
+}
+
+void ngxc_compositor_deinit(ngxc_compositor *self) {
+
+}
+
+void ngxc_compositor_add_window(ngxc_compositor *self, Window window) {
+ if(self->num_windows == NGXC_COMPOSITOR_MAX_WINDOWS) {
+ fprintf(stderr, "error: reached max number of trackable windows (%d), ignoring window with id %ld\n", NGXC_COMPOSITOR_MAX_WINDOWS, window);
+ return;
+ }
+
+ XWindowAttributes xattr;
+ if(!XGetWindowAttributes(self->dpy, window, &xattr)) {
+ fprintf(stderr, "error: failed to get window attributes, ignoring window with id %ld\n", window);
+ return;
+ }
+
+ //Window c;
+ //XTranslateCoordinates(self->dpy, window, DefaultRootWindow(self->dpy), 0, 0, &xattr.x, &xattr.y, &c);
+
+ ngxc_window *window_obj = &self->windows[self->num_windows];
+ if(window_texture_init(&window_obj->texture, self->dpy, window) != 0) {
+ fprintf(stderr, "error: failed to create window texture, ignoring window with id %ld\n", window);
+ return;
+ }
+
+ window_obj->x = xattr.x;
+ window_obj->y = xattr.y;
+ ++self->num_windows;
+
+ fprintf(stderr, "ADDED WINDOW: %ld, x: %d, y: %d\n", window, xattr.x, xattr.y);
+}
+
+void ngxc_compositor_remove_window(ngxc_compositor *self, Window window) {
+ for(int i = 0; i < self->num_windows; ++i) {
+ if(self->windows[i].texture.window != window)
+ continue;
+
+ window_texture_deinit(&self->windows[i].texture);
+ for(int j = i + 1; j < self->num_windows; ++j) {
+ self->windows[j - 1] = self->windows[j];
+ }
+ break;
+ }
+}
+
+static void render_texture(const ngxc_window *window) {
+ float matrix[16] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ };
+
+ matrix[0] = 1.0f / (float)window->texture.width;
+ matrix[5] = 1.0f / (float)window->texture.height;
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadMatrixf(matrix);
+ glMatrixMode(GL_MODELVIEW);
+ glBindTexture(GL_TEXTURE_2D, window->texture.texture_id);
+
+ glColor4ub(255, 255, 255, 255);
+ //glTranslatef(window->x, window->y, 0.0f);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(window->x, window->y);
+
+ glTexCoord2f(window->texture.width, 0.0f);
+ glVertex2f(window->x + window->texture.width, window->y);
+
+ glTexCoord2f(window->texture.width, window->texture.height);
+ glVertex2f(window->x + window->texture.width, window->y + window->texture.height);
+
+ glTexCoord2f(0.0f, window->texture.height);
+ glVertex2f(window->x, window->y + window->texture.height);
+ glEnd();
+ glLoadIdentity();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+/* 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);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ for(int i = 0; i < self->num_windows; ++i) {
+ const ngxc_window *window_obj = &self->windows[i];
+ render_texture(window_obj);
+ }
+
+ const double now = clock_get_monotonic_seconds();
+ const double frame_duration = now - self->frame_timer;
+
+ glXSwapBuffers(self->dpy, self->composite_window);
+ glFlush();
+ glFinish();
+
+ const double time_limit = 1.0f / 60.0f; // TODO: Get from randr
+ const double delayed_update = time_limit - frame_duration - 0.002;
+ //fprintf(stderr, "delayed update: %f\n", delayed_update);
+ if(delayed_update > 0.0)
+ usleep(delayed_update * 1000000.0);
+
+ self->frame_timer = clock_get_monotonic_seconds();
+}
+
+void ngxc_compositor_on_configure(ngxc_compositor *self, const XConfigureEvent *configure_event) {
+ ngxc_window *window_obj = ngxc_compositor_get_window_by_id(self, configure_event->window);
+ if(!window_obj)
+ return;
+
+ window_obj->x = configure_event->x;
+ window_obj->y = configure_event->y;
+
+ if(configure_event->width != window_obj->texture.width || configure_event->height != window_obj->texture.height) {
+ window_texture_on_resize(&window_obj->texture);
+ }
+}