diff options
-rw-r--r-- | meson.build | 21 | ||||
-rw-r--r-- | shaders/frag.frag | 23 | ||||
-rw-r--r-- | shaders/vert.vert | 24 | ||||
-rw-r--r-- | src/egl.c | 166 | ||||
-rw-r--r-- | src/egl.h | 25 | ||||
-rw-r--r-- | src/entry.c | 15 | ||||
-rw-r--r-- | src/gl.c | 325 | ||||
-rw-r--r-- | src/gl.h | 27 | ||||
-rw-r--r-- | src/image.h | 1 | ||||
-rw-r--r-- | src/ipc.c | 121 | ||||
-rw-r--r-- | src/ipc.h | 13 | ||||
-rw-r--r-- | src/log.c | 13 | ||||
-rw-r--r-- | src/main.c | 38 | ||||
-rw-r--r-- | src/shm.c | 49 | ||||
-rw-r--r-- | src/shm.h | 8 | ||||
-rw-r--r-- | src/string_vec.c | 2 | ||||
-rw-r--r-- | src/surface.c | 90 | ||||
-rw-r--r-- | src/surface.h | 17 | ||||
-rw-r--r-- | src/tofi.h | 3 | ||||
-rw-r--r-- | src/xmalloc.c | 7 |
20 files changed, 171 insertions, 817 deletions
diff --git a/meson.build b/meson.build index e00635b..06ce596 100644 --- a/meson.build +++ b/meson.build @@ -25,12 +25,6 @@ data_location = join_paths( 'tofi' ) -shader_location = join_paths( - debug ? '' : data_location, - 'shaders', - '' -) - completion_location = join_paths( get_option('prefix'), get_option('datadir'), @@ -38,11 +32,6 @@ completion_location = join_paths( 'completions' ) -install_subdir( - 'shaders', - install_dir: data_location -) - install_data( 'completions/tofi', install_dir: completion_location @@ -55,7 +44,6 @@ add_project_arguments( '-Wshadow', '-Wno-unused-parameter', '-D_POSIX_C_SOURCE=200809L', - '-DSHADER_PATH="@0@"'.format(shader_location), ], language: 'c' ) @@ -64,12 +52,10 @@ sources = files( 'src/main.c', 'src/color.c', 'src/compgen.c', - 'src/egl.c', 'src/entry.c', - 'src/gl.c', 'src/history.c', - 'src/ipc.c', 'src/log.c', + 'src/shm.c', 'src/string_vec.c', 'src/surface.c', 'src/wlr-layer-shell-unstable-v1.c', @@ -77,12 +63,9 @@ sources = files( ) cc = meson.get_compiler('c') -epoxy = dependency('epoxy') glib = dependency('glib-2.0') -json = dependency('json-c') pangocairo = dependency('pangocairo') wayland_client = dependency('wayland-client') -wayland_egl = dependency('wayland-egl') wayland_protocols = dependency('wayland-protocols', native: true) wayland_scanner_dep = dependency('wayland-scanner', native: true) xkbcommon = dependency('xkbcommon') @@ -119,7 +102,7 @@ endforeach executable( 'tofi', sources, wl_proto_src, wl_proto_headers, - dependencies: [epoxy, json, glib, pangocairo, wayland_egl, xkbcommon], + dependencies: [glib, pangocairo, wayland_client, xkbcommon], install: true ) diff --git a/shaders/frag.frag b/shaders/frag.frag deleted file mode 100644 index 88d2337..0000000 --- a/shaders/frag.frag +++ /dev/null @@ -1,23 +0,0 @@ -#version 100 - -/* - * Copyright (C) 2021 Philip Jones - * - * Licensed under the MIT License. - * See either the LICENSE file, or: - * - * https://opensource.org/licenses/MIT - * - * I don't think you can really copyright this shader though :) - */ - -precision lowp float; - -varying vec2 Texcoord; - -uniform sampler2D tex; - -void main() -{ - gl_FragColor = texture2D(tex, Texcoord); -} diff --git a/shaders/vert.vert b/shaders/vert.vert deleted file mode 100644 index 3364718..0000000 --- a/shaders/vert.vert +++ /dev/null @@ -1,24 +0,0 @@ -#version 100 - -/* - * Copyright (C) 2017-2020 Philip Jones - * - * Licensed under the MIT License. - * See either the LICENSE file, or: - * - * https://opensource.org/licenses/MIT - * - */ - -precision lowp float; - -attribute vec2 position; -attribute vec2 texcoord; - -varying vec2 Texcoord; - -void main() -{ - Texcoord = texcoord; - gl_Position = vec4(position, 0.0, 1.0); -} diff --git a/src/egl.c b/src/egl.c deleted file mode 100644 index 8ae70f2..0000000 --- a/src/egl.c +++ /dev/null @@ -1,166 +0,0 @@ -#include <assert.h> -#include <string.h> -#include <wayland-egl.h> -#include "egl.h" -#include "log.h" - -static const char *egl_error_string(); - -void egl_create_window( - struct egl *egl, - struct wl_surface *wl_surface, - uint32_t width, - uint32_t height) -{ - egl->window = wl_egl_window_create(wl_surface, width, height); - - if (egl->window == EGL_NO_SURFACE) { - egl_log_error("Couldn't create EGL window"); - } -} - -void egl_create_context(struct egl *egl, struct wl_display *wl_display) -{ - egl->display = eglGetDisplay(wl_display); - if (egl->display == EGL_NO_DISPLAY) { - egl_log_error("Couldn't get EGL display"); - return; - } - - if (!eglInitialize(egl->display, NULL, NULL)) { - egl_log_error("Couldn't initialise EGL"); - return; - } - - EGLBoolean result; - EGLConfig config; - EGLint num_configs; - static const EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_NONE - }; - - result = eglGetConfigs(egl->display, NULL, 0, &num_configs); - if ((result != EGL_TRUE) || (num_configs == 0)) { - egl_log_error("No EGL configs available"); - return; - } - - result = eglChooseConfig( - egl->display, - config_attribs, - &config, - 1, - &num_configs); - if ((result != EGL_TRUE) || (num_configs != 1)) { - egl_log_error("Failed to choose EGL config"); - return; - } - - egl->surface = eglCreateWindowSurface( - egl->display, - config, - egl->window, - NULL); - if (egl->surface == EGL_NO_SURFACE) { - egl_log_error("Couldn't create EGL window surface"); - return; - } - - static const EGLint context_attribs[] = { - EGL_CONTEXT_MAJOR_VERSION, 2, - EGL_NONE - }; - - egl->context = eglCreateContext( - egl->display, - config, - EGL_NO_CONTEXT, - context_attribs); - if (egl->context == EGL_NO_CONTEXT) { - egl_log_error("Couldn't create EGL context"); - return; - } - - result = eglMakeCurrent( - egl->display, - egl->surface, - egl->surface, - egl->context); - if (!result) { - egl_log_error("Couldn't make EGL context current"); - return; - } -} - -void egl_destroy(struct egl *egl) -{ - eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(egl->display, egl->surface); - wl_egl_window_destroy(egl->window); -} - -void egl_log_error(const char *msg) -{ - log_error("%s: %s\n", msg, egl_error_string()); -} - -void egl_make_current(struct egl *egl) -{ - bool result = eglMakeCurrent( - egl->display, - egl->surface, - egl->surface, - egl->context); - if (!result) { - egl_log_error("Couldn't make EGL context current"); - return; - } -} - -void egl_swap_buffers(struct egl *egl) -{ - eglSwapBuffers(egl->display, egl->surface); -} - -const char *egl_error_string() -{ - switch(eglGetError()) { - case EGL_SUCCESS: - return "EGL_SUCCESS"; - case EGL_NOT_INITIALIZED: - return "EGL_NOT_INITIALIZED"; - case EGL_BAD_ACCESS: - return "EGL_BAD_ACCESS"; - case EGL_BAD_ALLOC: - return "EGL_BAD_ALLOC"; - case EGL_BAD_ATTRIBUTE: - return "EGL_BAD_ATTRIBUTE"; - case EGL_BAD_CONTEXT: - return "EGL_BAD_CONTEXT"; - case EGL_BAD_CONFIG: - return "EGL_BAD_CONFIG"; - case EGL_BAD_CURRENT_SURFACE: - return "EGL_BAD_CURRENT_SURFACE"; - case EGL_BAD_DISPLAY: - return "EGL_BAD_DISPLAY"; - case EGL_BAD_SURFACE: - return "EGL_BAD_SURFACE"; - case EGL_BAD_MATCH: - return "EGL_BAD_MATCH"; - case EGL_BAD_PARAMETER: - return "EGL_BAD_PARAMETER"; - case EGL_BAD_NATIVE_PIXMAP: - return "EGL_BAD_NATIVE_PIXMAP"; - case EGL_BAD_NATIVE_WINDOW: - return "EGL_BAD_NATIVE_WINDOW"; - case EGL_CONTEXT_LOST: - return "EGL_CONTEXT_LOST"; - } - return "Unknown EGL error"; -} diff --git a/src/egl.h b/src/egl.h deleted file mode 100644 index a3f17a2..0000000 --- a/src/egl.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EGL_H -#define EGL_H - -#include <wayland-egl.h> -#include <epoxy/egl.h> - -struct egl { - EGLNativeWindowType window; - EGLDisplay display; - EGLContext context; - EGLSurface surface; -}; - -void egl_create_window( - struct egl *egl, - struct wl_surface *wl_surface, - uint32_t width, - uint32_t height); -void egl_create_context(struct egl *egl, struct wl_display *wl_display); -void egl_destroy(struct egl *egl); -void egl_log_error(const char *msg); -void egl_make_current(struct egl *egl); -void egl_swap_buffers(struct egl *egl); - -#endif /* EGL_H */ diff --git a/src/entry.c b/src/entry.c index 644fe39..845df0a 100644 --- a/src/entry.c +++ b/src/entry.c @@ -1,4 +1,3 @@ -#include <arpa/inet.h> #include <cairo/cairo.h> #include <glib.h> #include <pango/pangocairo.h> @@ -17,14 +16,6 @@ void entry_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t s height /= scale; /* - * Cairo uses native 32 bit integers for pixels, so if this processor - * is little endian we have to tell OpenGL to swizzle the texture. - */ - if (htonl(0xFFu) != 0xFFu) { - entry->image.swizzle = true; - } - - /* * Create the cairo surface and context we'll be using. */ cairo_surface_t *surface = cairo_image_surface_create( @@ -90,8 +81,10 @@ void entry_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t s cairo_clip(cr); /* Setup Pango. */ + log_debug("Creating Pango context.\n"); PangoContext *context = pango_cairo_create_context(cr); + log_debug("Creating Pango font description.\n"); PangoFontDescription *font_description = pango_font_description_from_string(entry->font_name); pango_font_description_set_size( @@ -101,10 +94,13 @@ void entry_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t s pango_font_description_free(font_description); entry->pango.prompt_layout = pango_layout_new(context); + log_debug("Setting Pango text.\n"); pango_layout_set_text(entry->pango.prompt_layout, "run: ", -1); int prompt_width; int prompt_height; + log_debug("Get Pango pixel size.\n"); pango_layout_get_pixel_size(entry->pango.prompt_layout, &prompt_width, &prompt_height); + log_debug("First Pango draw.\n"); pango_cairo_update_layout(cr, entry->pango.prompt_layout); /* Draw the prompt now, as this only needs to be done once */ @@ -118,6 +114,7 @@ void entry_init(struct entry *entry, uint32_t width, uint32_t height, uint32_t s cairo_rectangle(cr, 0, 0, width, height); cairo_clip(cr); + log_debug("Creating Pango layout.\n"); entry->pango.entry_layout = pango_layout_new(context); pango_layout_set_text(entry->pango.entry_layout, "", -1); diff --git a/src/gl.c b/src/gl.c deleted file mode 100644 index 09c7e1d..0000000 --- a/src/gl.c +++ /dev/null @@ -1,325 +0,0 @@ -#include <epoxy/gl.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "gl.h" -#include "log.h" -#include "xmalloc.h" - -#define max(a, b) ((a) > (b) ? (a) : (b)) - -static void load_shader(GLuint shader, const char *filename); -static GLuint create_shader_program(const char *vert, const char *frag); -static void GLAPIENTRY MessageCallback( - GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* userParam); -static const char *gl_debug_source_string(GLenum type); -static const char *gl_debug_type_string(GLenum type); -static const char *gl_debug_severity_string(GLenum type); - - -void gl_initialise(struct gl *gl, struct image *texture) -{ -#ifdef DEBUG - //glEnable(GL_DEBUG_OUTPUT); - //glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - //glDebugMessageCallback(MessageCallback, 0); -#endif - if (texture == NULL || texture->buffer == NULL) { - return; - } - - /* Compile and link the shader programs */ - gl->shader = create_shader_program( - SHADER_PATH "vert.vert", - SHADER_PATH "frag.frag" - ); - glUseProgram(gl->shader); - glUniform1i(glGetUniformLocation(gl->shader, "tex"), 0); - - /* Create a vertex buffer for a quad filling the screen */ - float vertices[] = { - // Position Texcoords - -1.0f, 1.0f, 0.0f, 0.0f, // Top-left - 1.0f, 1.0f, 1.0f, 0.0f, // Top-right - 1.0f, -1.0f, 1.0f, 1.0f, // Bottom-right - -1.0f, -1.0f, 0.0f, 1.0f // Bottom-left - }; - - glGenBuffers(1, &gl->vbo); - glBindBuffer(GL_ARRAY_BUFFER, gl->vbo); - glBufferData( - GL_ARRAY_BUFFER, - sizeof(vertices), - vertices, - GL_STATIC_DRAW); - - /* - * Create a vertex array and enable vertex attributes for the shaders. - */ - glGenVertexArrays(1, &gl->vao); - glBindVertexArray(gl->vao); - - GLint posAttrib = glGetAttribLocation(gl->shader, "position"); - glVertexAttribPointer( - posAttrib, - 2, - GL_FLOAT, - GL_FALSE, - 4*sizeof(float), - 0); - glEnableVertexAttribArray(posAttrib); - - GLint texAttrib = glGetAttribLocation(gl->shader, "texcoord"); - glVertexAttribPointer( - texAttrib, - 2, - GL_FLOAT, - GL_FALSE, - 4*sizeof(float), - (void *)(2*sizeof(float))); - glEnableVertexAttribArray(texAttrib); - - glBindVertexArray(0); - - /* - * Create the element buffer object that will actually be drawn via - * glDrawElements(). - */ - GLubyte elements[] = { - 0, 1, 2, - 2, 3, 0 - }; - - glGenBuffers(1, &gl->ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl->ebo); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - sizeof(elements), - elements, - GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - /* Create the texture we'll draw to */ - glGenTextures(1, &gl->texture); - glBindTexture(GL_TEXTURE_2D, gl->texture); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA, - texture->width, - texture->height, - 0, - /* - * On little-endian processors, textures from Cairo - * have to have their red and blue channels swapped. - */ - texture->swizzle ? GL_BGRA : GL_RGBA, - GL_UNSIGNED_BYTE, - (GLvoid *)texture->buffer); - 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_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - /* Bind the actual bits we'll be using to render */ - glBindVertexArray(gl->vao); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl->ebo); -} - -void gl_destroy(struct gl *gl) -{ - glDeleteProgram(gl->shader); - glDeleteTextures(1, &gl->texture); - glDeleteBuffers(1, &gl->ebo); - glDeleteVertexArrays(1, &gl->vao); - glDeleteBuffers(1, &gl->vbo); -} - -void gl_clear(struct gl *gl, struct color *color) -{ - glClearColor(color->r, color->g, color->b, color->a); - glClear(GL_COLOR_BUFFER_BIT); -} - -void gl_draw_texture( - struct gl *gl, - struct image *texture, - int32_t x, - int32_t y, - int32_t width, - int32_t height) -{ - if (texture->redraw) { - glTexSubImage2D( - GL_TEXTURE_2D, - 0, - 0, - 0, - texture->width, - texture->height, - texture->swizzle ? GL_BGRA : GL_RGBA, - GL_UNSIGNED_BYTE, - (GLvoid *)texture->buffer); - texture->redraw = false; - } - - glViewport(x, y, width, height); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL); -} - -void load_shader(GLuint shader, const char *filename) -{ - errno = 0; - FILE *fp = fopen(filename, "rb"); - if (!fp) { - log_error("Failed to load shader %s: %s.\n", - filename, strerror(errno)); - exit(EXIT_FAILURE); - } - if (fseek(fp, 0, SEEK_END) != 0) { - log_error("Failed to load shader %s: %s.\n", - filename, strerror(errno)); - fclose(fp); - exit(EXIT_FAILURE); - } - long size = ftell(fp); - if (size <= 0) { - log_error("Failed to load shader %s: %s.\n", - filename, strerror(errno)); - fclose(fp); - exit(EXIT_FAILURE); - } - unsigned long usize = (unsigned long) size; - GLchar *source = xmalloc(usize + 1); - rewind(fp); - if (fread(source, 1, usize, fp) != usize) { - log_error("Failed to load shader %s: %s.\n", - filename, strerror(errno)); - fclose(fp); - exit(EXIT_FAILURE); - } - fclose(fp); - source[usize] = '\0'; - glShaderSource(shader, 1, (const GLchar *const *)&source, NULL); - free(source); - - glCompileShader(shader); - - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status != GL_TRUE) { - log_error("Failed to compile shader %s!\n", filename); - - GLint info_length = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_length); - if (info_length > 1) { - char *log = xmalloc((unsigned)info_length * sizeof(*log)); - glGetShaderInfoLog(shader, info_length, NULL, log); - log_error("\t%s\n", log); - free(log); - } - exit(EXIT_FAILURE); - } -} - -GLuint create_shader_program(const char *vert, const char *frag) -{ - GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); - load_shader(vertex_shader, vert); - - GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - load_shader(fragment_shader, frag); - - GLuint shader = glCreateProgram(); - glAttachShader(shader, vertex_shader); - glAttachShader(shader, fragment_shader); - glLinkProgram(shader); - glDetachShader(shader, fragment_shader); - glDetachShader(shader, vertex_shader); - glDeleteShader(fragment_shader); - glDeleteShader(vertex_shader); - return shader; -} - -void GLAPIENTRY MessageCallback( - GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* userParam) -{ - log_debug("Message from OpenGL:\n"); - log_debug("\tSource: %s\n", gl_debug_source_string(source)); - log_debug("\tType: %s\n", gl_debug_type_string(type)); - log_debug("\tSeverity: %s\n", gl_debug_severity_string(severity)); - log_debug("\tMessage: %s\n", message); -} - -const char *gl_debug_source_string(GLenum type) -{ - switch(type) { - case GL_DEBUG_SOURCE_API: - return "API"; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: - return "Window system"; - case GL_DEBUG_SOURCE_SHADER_COMPILER: - return "Shader compiler"; - case GL_DEBUG_SOURCE_THIRD_PARTY: - return "Third party"; - case GL_DEBUG_SOURCE_APPLICATION: - return "Application"; - case GL_DEBUG_SOURCE_OTHER: - return "Other"; - } - return "unknown"; -} - -const char *gl_debug_type_string(GLenum type) -{ - switch(type) { - case GL_DEBUG_TYPE_ERROR: - return "Error"; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: - return "Deprecated behavior"; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: - return "Undefined behavior"; - case GL_DEBUG_TYPE_PORTABILITY: - return "Portability"; - case GL_DEBUG_TYPE_PERFORMANCE: - return "Performance"; - case GL_DEBUG_TYPE_MARKER: - return "Marker"; - case GL_DEBUG_TYPE_PUSH_GROUP: - return "Push group"; - case GL_DEBUG_TYPE_POP_GROUP: - return "Pop group"; - case GL_DEBUG_TYPE_OTHER: - return "Other"; - } - return "Unknown"; -} - -const char *gl_debug_severity_string(GLenum type) -{ - switch(type) { - case GL_DEBUG_SEVERITY_HIGH: - return "High"; - case GL_DEBUG_SEVERITY_MEDIUM: - return "Medium"; - case GL_DEBUG_SEVERITY_LOW: - return "Low"; - case GL_DEBUG_SEVERITY_NOTIFICATION: - return "Notification"; - } - return "Unknown"; -} diff --git a/src/gl.h b/src/gl.h deleted file mode 100644 index 8d4b6f9..0000000 --- a/src/gl.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef GL_H -#define GL_H - -#include <epoxy/gl.h> -#include "color.h" -#include "image.h" - -struct gl { - GLuint vbo; - GLuint vao; - GLuint ebo; - GLuint texture; - GLuint shader; -}; - -void gl_initialise(struct gl *gl, struct image *texture); -void gl_destroy(struct gl *gl); -void gl_clear(struct gl *gl, struct color *color); -void gl_draw_texture( - struct gl *gl, - struct image *texture, - int32_t x, - int32_t y, - int32_t width, - int32_t height); - -#endif /* GL_H */ diff --git a/src/image.h b/src/image.h index a66e0cb..2afaa4d 100644 --- a/src/image.h +++ b/src/image.h @@ -8,7 +8,6 @@ struct image { uint8_t *buffer; uint32_t width; uint32_t height; - bool swizzle; bool redraw; struct { uint32_t x; diff --git a/src/ipc.c b/src/ipc.c deleted file mode 100644 index 2af5dbf..0000000 --- a/src/ipc.c +++ /dev/null @@ -1,121 +0,0 @@ -#include <json-c/json_object.h> -#include <json-c/json_tokener.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <unistd.h> -#include "ipc.h" -#include "log.h" -#include "xmalloc.h" - -static int ipc_open(void); -static int ipc_send(int socket, struct json_object *request); -static struct json_object *ipc_receive(int socket); - -struct json_object *ipc_submit(struct json_object *request) -{ - int sock = ipc_open(); - if (sock == -1) { - return NULL; - } - - if (ipc_send(sock, request) == -1) { - close(sock); - return NULL; - } - - struct json_object *resp = ipc_receive(sock); - close(sock); - return resp; -} - -/* - * Open a connection to the UNIX socket specified by - * the environment variable GREETD_SOCK. - * - * Returns the socket file descriptor on success, or -1 on failure. - */ -int ipc_open(void) -{ - char *greetd_sock = getenv("GREETD_SOCK"); - - if (greetd_sock == NULL) { - log_error("GREETD_SOCK not set.\n"); - return -1; - } - - int sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock == -1) { - log_error("Unable to create socket: %s\n", strerror(errno)); - return -1; - } - - struct sockaddr_un remote = { .sun_family = AF_UNIX }; - strncpy(remote.sun_path, greetd_sock, sizeof(remote.sun_path)); - - if (connect(sock, (struct sockaddr *)&remote, sizeof(remote)) == -1) { - log_error("Unable to connect to greetd: %s\n", strerror(errno)); - close(sock); - return -1; - } - return sock; -} - -/* - * Send an IPC request to the specified socket. - * - * Returns 0 on success, or -1 on failure. - */ -int ipc_send(int sock, struct json_object *request) -{ - const char *str = json_object_to_json_string(request); - uint32_t len = strlen(str); - - if (send(sock, &len, sizeof(len), 0) == -1) { - log_error("Error sending request size: %s\n", strerror(errno)); - return -1; - } - - if (send(sock, str, len, 0) == -1) { - log_error("Error sending request: %s\n", strerror(errno)); - return -1; - } - return 0; -} - -/* - * Receive an IPC response on the specified socket. - * - * Returns the response on success, or NULL on failure. - */ -struct json_object *ipc_receive(int sock) -{ - uint32_t len = 0; - - if (recv(sock, &len, sizeof(len), 0) != sizeof(len)) { - log_error("Error receiving response size: %s\n", strerror(errno)); - return NULL; - } - - char *buf = xmalloc(len + 1); - if (recv(sock, buf, len, 0) != len) { - log_error("Error receiving response: %s\n", strerror(errno)); - free(buf); - return NULL; - } - - buf[len] = '\0'; - - enum json_tokener_error error; - struct json_object *resp = json_tokener_parse_verbose(buf, &error); - free(buf); - - if (resp == NULL) { - log_error("Error parsing response: %s\n", json_tokener_error_desc(error)); - } - return resp; - -} diff --git a/src/ipc.h b/src/ipc.h deleted file mode 100644 index 30a953a..0000000 --- a/src/ipc.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef IPC_H -#define IPC_H - -#include <json-c/json_object.h> - -/* - * Submit an IPC request to greetd. - * - * Returns the response on success, or NULL on failure. - */ -struct json_object *ipc_submit(struct json_object *request); - -#endif /* IPC_H */ @@ -1,6 +1,7 @@ #include <stdarg.h> #include <stdint.h> #include <stdio.h> +#include <sys/resource.h> #include <time.h> #define SECOND 1000000000ul @@ -34,7 +35,7 @@ void log_debug(const char *const fmt, ...) #endif static struct timespec start_time; if (start_time.tv_nsec == 0) { - fprintf(stderr, "[ real, cpu]\n"); + fprintf(stderr, "[ real, cpu, maxRSS]\n"); clock_gettime(CLOCK_REALTIME, &start_time); } struct timespec real_time; @@ -42,15 +43,21 @@ void log_debug(const char *const fmt, ...) clock_gettime(CLOCK_REALTIME, &real_time); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cpu_time); real_time = time_diff(real_time, start_time); + + struct rusage usage; + getrusage(RUSAGE_SELF, &usage); + va_list args; va_start(args, fmt); fprintf( stderr, - "[%ld.%03ld, %ld.%03ld][DEBUG]: ", + "[%ld.%03ld, %ld.%03ld, %ld KB][DEBUG]: ", real_time.tv_sec, real_time.tv_nsec / 1000000, cpu_time.tv_sec, - cpu_time.tv_nsec / 1000000); + cpu_time.tv_nsec / 1000000, + usage.ru_maxrss + ); vfprintf(stderr, fmt, args); va_end(args); } @@ -1,6 +1,4 @@ #include <assert.h> -#include <wayland-egl.h> -#include <epoxy/gl.h> #include <errno.h> #include <getopt.h> #include <locale.h> @@ -14,16 +12,14 @@ #include <wayland-client.h> #include <wchar.h> #include <wctype.h> -#include <xdg-shell.h> #include <xkbcommon/xkbcommon.h> #include "tofi.h" #include "compgen.h" -#include "egl.h" #include "entry.h" #include "image.h" -#include "gl.h" #include "log.h" #include "nelem.h" +#include "shm.h" #include "string_vec.h" #undef MAX @@ -49,7 +45,7 @@ static void zwlr_layer_surface_configure( /* * Resize the main window. - * EGL wants actual pixel width / height, so we have to scale the + * We want actual pixel width / height, so we have to scale the * values provided by Wayland. */ tofi->window.surface.width = @@ -57,9 +53,13 @@ static void zwlr_layer_surface_configure( tofi->window.surface.height = tofi->window.height * tofi->window.scale; + /* Assume 4 bytes per pixel for WL_SHM_FORMAT_XRGB8888 */ + tofi->window.surface.stride = + tofi->window.surface.width * 4; + /* - * Need to redraw the background at the new size. This entails a - * wl_surface_commit, so no need to do so explicitly here. + * Need to redraw the background at the new size. This entails + * a wl_surface_commit, so no need to do so explicitly here. */ tofi->window.surface.redraw = true; } @@ -443,7 +443,7 @@ static void registry_global( uint32_t version) { struct tofi *tofi = data; - //log_debug("Registry %s %u.\n", interface, name); + log_debug("Registry %u: %s v%u.\n", name, interface, version); if (!strcmp(interface, wl_compositor_interface.name)) { tofi->wl_compositor = wl_registry_bind( wl_registry, @@ -473,12 +473,19 @@ static void registry_global( &wl_output_listener, tofi); log_debug("Bound to output %u.\n", name); + } else if (!strcmp(interface, wl_shm_interface.name)) { + tofi->wl_shm = wl_registry_bind( + wl_registry, + name, + &wl_shm_interface, + 1); + log_debug("Bound to shm %u.\n", name); } else if (!strcmp(interface, zwlr_layer_shell_v1_interface.name)) { tofi->zwlr_layer_shell = wl_registry_bind( wl_registry, name, &zwlr_layer_shell_v1_interface, - 1); + 4); log_debug("Bound to zwlr_layer_shell_v1 %u.\n", name); } } @@ -797,19 +804,21 @@ int main(int argc, char *argv[]) log_debug("Pango / Cairo initialised.\n"); /* - * Create the various EGL and GL structures for each surface, and + * Create the various structures for each surface, and * perform an initial render of everything. */ log_debug("Initialising main window surface.\n"); + surface_initialise( &tofi.window.surface, - tofi.wl_display, + tofi.wl_shm, &tofi.window.entry.image); surface_draw( &tofi.window.surface, &tofi.window.entry.background_color, &tofi.window.entry.image); + /* We've just rendered, so we don't need to do it again right now. */ tofi.window.surface.redraw = false; @@ -842,11 +851,10 @@ int main(int argc, char *argv[]) /* * For debug builds, try to cleanup as much as possible, to make using * e.g. Valgrind easier. There's still a few unavoidable leaks though, - * mostly from OpenGL libs and Pango. + * mostly from Pango. */ - entry_destroy(&tofi.window.entry); surface_destroy(&tofi.window.surface); - eglTerminate(tofi.window.surface.egl.display); + entry_destroy(&tofi.window.entry); wl_surface_destroy(tofi.window.surface.wl_surface); if (tofi.wl_keyboard != NULL) { wl_keyboard_release(tofi.wl_keyboard); diff --git a/src/shm.c b/src/shm.c new file mode 100644 index 0000000..e145d4a --- /dev/null +++ b/src/shm.c @@ -0,0 +1,49 @@ +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <time.h> +#include <unistd.h> +#include "shm.h" + +static void randname(char *buf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} + +static int create_shm_file(void) +{ + int retries = 100; + do { + char name[] = "/wl_shm-XXXXXX"; + randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} + +int shm_allocate_file(size_t size) +{ + int fd = create_shm_file(); + if (fd < 0) + return -1; + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + return fd; +} diff --git a/src/shm.h b/src/shm.h new file mode 100644 index 0000000..559ff5c --- /dev/null +++ b/src/shm.h @@ -0,0 +1,8 @@ +#ifndef SHM_H +#define SHM_H + +#include <stddef.h> + +int shm_allocate_file(size_t size); + +#endif /* SHM_H */ diff --git a/src/string_vec.c b/src/string_vec.c index 3c77f6f..0bcd7f2 100644 --- a/src/string_vec.c +++ b/src/string_vec.c @@ -23,7 +23,7 @@ static int cmpstringp(const void *restrict a, const void *restrict b) if (str2 == NULL) { return -1; } - return strcasecmp(str1, str2); + return strcmp(str1, str2); } struct string_vec string_vec_create(void) diff --git a/src/surface.c b/src/surface.c index 8052d5e..90e7bb0 100644 --- a/src/surface.c +++ b/src/surface.c @@ -1,4 +1,8 @@ -#include "gl.h" +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> +#include "log.h" +#include "shm.h" #include "surface.h" #undef MAX @@ -6,23 +10,56 @@ void surface_initialise( struct surface *surface, - struct wl_display *wl_display, + struct wl_shm *wl_shm, struct image *texture) { - egl_create_window( - &surface->egl, - surface->wl_surface, - surface->width, - surface->height); - egl_create_context(&surface->egl, wl_display); - gl_initialise(&surface->gl, texture); + + const int height = surface->height; + const int stride = surface->stride; + + /* Double-buffered pool, so allocate space for two windows */ + surface->shm_pool_size = + height + * stride + * 2; + surface->shm_pool_fd = shm_allocate_file(surface->shm_pool_size); + surface->shm_pool_data = mmap( + NULL, + surface->shm_pool_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + surface->shm_pool_fd, + 0); + surface->wl_shm_pool = wl_shm_create_pool( + wl_shm, + surface->shm_pool_fd, + surface->shm_pool_size); + + for (int i = 0; i < 2; i++) { + int offset = surface->height * surface->stride * i; + surface->buffers[i] = wl_shm_pool_create_buffer( + surface->wl_shm_pool, + offset, + surface->width, + surface->height, + surface->stride, + WL_SHM_FORMAT_XRGB8888); + } + + log_debug("Created shm file with size %d KiB.\n", + surface->shm_pool_size / 1024); + + surface->index = 0; } void surface_destroy(struct surface *surface) { - egl_make_current(&surface->egl); - gl_destroy(&surface->gl); - egl_destroy(&surface->egl); + wl_shm_pool_destroy(surface->wl_shm_pool); + munmap(surface->shm_pool_data, surface->shm_pool_size); + surface->shm_pool_data = NULL; + close(surface->shm_pool_fd); + wl_buffer_destroy(surface->buffers[0]); + wl_buffer_destroy(surface->buffers[1]); } void surface_draw( @@ -30,29 +67,12 @@ void surface_draw( struct color *color, struct image *texture) { - wl_egl_window_resize( - surface->egl.window, - surface->width, - surface->height, - 0, - 0); - egl_make_current(&surface->egl); - gl_clear(&surface->gl, color); - - if (texture != NULL && texture->buffer != NULL) { - double scale = MAX( - (double)surface->width / texture->width, - (double)surface->height / texture->height - ); - int32_t width = (int32_t)(scale * texture->width); - int32_t height = (int32_t)(scale * texture->height); - int32_t x = -((int32_t)width - (int32_t)surface->width) / 2; - int32_t y = -((int32_t)height - (int32_t)surface->height) / 2; - - gl_draw_texture(&surface->gl, texture, x, y, width, height); - } + surface->index = !surface->index; + int offset = surface->height * surface->stride * surface->index; + uint32_t *pixels = (uint32_t *)&surface->shm_pool_data[offset]; + memcpy(pixels, texture->buffer, surface->height * surface->stride); + wl_surface_attach(surface->wl_surface, surface->buffers[surface->index], 0, 0); wl_surface_damage_buffer(surface->wl_surface, 0, 0, INT32_MAX, INT32_MAX); - - egl_swap_buffers(&surface->egl); + wl_surface_commit(surface->wl_surface); } diff --git a/src/surface.h b/src/surface.h index b8b132f..8abd1e1 100644 --- a/src/surface.h +++ b/src/surface.h @@ -3,21 +3,28 @@ #include <stdbool.h> #include <stdint.h> -#include "egl.h" -#include "gl.h" +#include <wayland-client.h> +#include "color.h" +#include "image.h" struct surface { - struct egl egl; - struct gl gl; struct wl_surface *wl_surface; + struct wl_shm_pool *wl_shm_pool; int32_t width; int32_t height; + int32_t stride; + int index; + struct wl_buffer *buffers[2]; + + int shm_pool_size; + int shm_pool_fd; + uint8_t *shm_pool_data; bool redraw; }; void surface_initialise( struct surface *surface, - struct wl_display *wl_display, + struct wl_shm *wl_shm, struct image *texture); void surface_destroy(struct surface *surface); void surface_draw( @@ -3,7 +3,6 @@ #include <stdbool.h> #include <stdint.h> -#include <xdg-shell.h> #include "color.h" #include "entry.h" #include "image.h" @@ -17,6 +16,7 @@ struct tofi { struct wl_compositor *wl_compositor; struct wl_seat *wl_seat; struct wl_output *wl_output; + struct wl_shm *wl_shm; struct zwlr_layer_shell_v1 *zwlr_layer_shell; uint32_t wl_display_name; @@ -24,6 +24,7 @@ struct tofi { uint32_t wl_compositor_name; uint32_t wl_seat_name; uint32_t wl_output_name; + uint32_t wl_shm_name; uint32_t zwlr_layer_shell_name; /* Objects */ diff --git a/src/xmalloc.c b/src/xmalloc.c index 1c2a9dc..2bb07d2 100644 --- a/src/xmalloc.c +++ b/src/xmalloc.c @@ -8,7 +8,7 @@ void *xmalloc(size_t size) void *ptr = malloc(size); if (ptr != NULL) { - //log_debug("Allocated %zu bytes.\n", size); + log_debug("Allocated %zu bytes.\n", size); return ptr; } else { log_error("Out of memory, exiting.\n"); @@ -21,7 +21,7 @@ void *xcalloc(size_t nmemb, size_t size) void *ptr = calloc(nmemb, size); if (ptr != NULL) { - //log_debug("Allocated %zux%zu bytes.\n", nmemb, size); + log_debug("Allocated %zux%zu bytes.\n", nmemb, size); return ptr; } else { log_error("Out of memory, exiting.\n"); @@ -34,7 +34,7 @@ void *xrealloc(void *ptr, size_t size) ptr = realloc(ptr, size); if (ptr != NULL) { - //log_debug("Reallocated to %zu bytes.\n", size); + log_debug("Reallocated to %zu bytes.\n", size); return ptr; } else { log_error("Out of memory, exiting.\n"); @@ -47,7 +47,6 @@ char *xstrdup(const char *s) char *ptr = strdup(s); if (ptr != NULL) { - //log_debug("Allocated %zu bytes.\n", size); return ptr; } else { log_error("Out of memory, exiting.\n"); |