commit d31ebb5431df658a1914ebe73654c11a993fff02
parent e91f3ae17b8994a92566413d0a8a0c19912957e9
Author: Luke Willis <lukejw@loquat.dev>
Date: Mon, 30 Mar 2026 21:06:16 -0400
Rewrite everything and begin using pixman
Diffstat:
| M | .clang-format | | | 144 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
| M | README.md | | | 20 | ++++++++++++++++++-- |
| M | guix.scm | | | 6 | ++++-- |
| M | meson.build | | | 5 | ++--- |
| M | scm/wig.scm | | | 2 | +- |
| M | src/main.c | | | 422 | +++++++++++++++++++++++++++++++------------------------------------------------ |
| A | src/surface.c | | | 162 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/surface.h | | | 26 | ++++++++++++++++++++++++++ |
| A | src/window.c | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/window.h | | | 19 | +++++++++++++++++++ |
| D | src/wl.c | | | 44 | -------------------------------------------- |
| D | src/wl.h | | | 6 | ------ |
12 files changed, 603 insertions(+), 318 deletions(-)
diff --git a/.clang-format b/.clang-format
@@ -1,3 +1,141 @@
----
-BasedOnStyle: Google
-...
+# Stole from suckless' libgrapheme
+# https://git.suckless.org/libgrapheme/file/.clang-format.html
+
+AccessModifierOffset: 0
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveAssignments:
+ Enabled: false
+AlignConsecutiveBitFields:
+ Enabled: true
+ AcrossEmptyLines: false
+ AcrossComments: false
+AlignConsecutiveDeclarations:
+ Enabled: false
+AlignConsecutiveMacros:
+ Enabled: true
+ AcrossEmptyLines: false
+ AcrossComments: false
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments: true
+# Kind: Always
+# OverEmptyLines: 1
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortEnumsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLambdasOnASingleLine: None
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterReturnType: TopLevelDefinitions
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros: []
+BinPackArguments: true
+BinPackParameters: true
+BitFieldColonSpacing: Both
+BreakAfterJavaFieldAnnotations: false
+#BreakArrays: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: WebKit
+BreakBeforeConceptDeclarations: Always
+#BreakBeforeInlineASMColon: Always
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializers: AfterColon
+BreakInheritanceList: AfterComma
+BreakStringLiterals: true
+ColumnLimit: 80
+CommentPragmas: ""
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: false
+DeriveLineEnding: false
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: Never
+FixNamespaceComments: true
+ForEachMacros: []
+IfMacros: []
+IncludeBlocks: Preserve
+IncludeIsMainRegex: ""
+IncludeIsMainSourceRegex: ""
+IndentAccessModifiers: false
+IndentCaseBlocks: false
+IndentCaseLabels: false
+IndentExternBlock: NoIndent
+IndentGotoLabels: false
+IndentPPDirectives: BeforeHash
+IndentRequiresClause: false
+IndentWidth: 8
+IndentWrappedFunctionNames: false
+InsertBraces: true
+InsertTrailingCommas: None
+JavaImportGroups: []
+JavaScriptQuotes: Double
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+LambdaBodyIndentation: Signature
+Language: Cpp
+MacroBlockBegin: ""
+MacroBlockEnd: ""
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: All
+NamespaceMacros: []
+ObjCBinPackProtocolList: Never
+ObjCBlockIndentWidth: 8
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+PPIndentWidth: 0
+PackConstructorInitializers: Never
+PointerAlignment: Right
+QualifierAlignment: Left
+RawStringFormats: []
+ReferenceAlignment: Pointer
+ReflowComments: true
+RemoveBracesLLVM: false
+#RemoveSemicolon: false
+RequiresClausePosition: OwnLine
+#RequiresExpressionIndentation: Keyword
+SeparateDefinitionBlocks: Always
+ShortNamespaceLines: 0
+SortIncludes: CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceAroundPointerQualifiers: Before
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: true
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 4
+SpacesInAngles: Never
+SpacesInCStyleCastParentheses: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: 1
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Auto
+StatementAttributeLikeMacros: []
+StatementMacros: []
+TabWidth: 8
+TypenameMacros: []
+UseCRLF: false
+UseTab: AlignWithSpaces
+#WhitespaceSensitiveMacros: []
diff --git a/README.md b/README.md
@@ -1,3 +1,19 @@
-# wig - Widgets in Guile
+# Widgets in Guile
-Wig is a widget engine for Wayland configured via Guile Scheme.
+`wig` is a lightweight tool for creating custom Wayland widgets via Guile
+Scheme.
+
+## Design
+
+`wig` is split into two main halves, C and Scheme.
+
+The Scheme half both provides methods for the user configuration and prepares
+it for use in C by validating and flattening it.
+
+The C half manages the main event loop, input, rendering and so on.
+
+## TODO
+
+- Improve README
+- Handle callbacks
+- Proper GUI
diff --git a/guix.scm b/guix.scm
@@ -6,7 +6,8 @@
(gnu packages)
(gnu packages freedesktop)
(gnu packages guile)
- (gnu packages pkg-config))
+ (gnu packages pkg-config)
+ (gnu packages xdisorg))
(define wig
(package
@@ -18,7 +19,8 @@
wayland-protocols
wlr-protocols))
(inputs (list wayland
- guile-3.0))
+ guile-3.0
+ pixman))
(synopsis "Widgets in Guile")
(description #f)
(home-page "https://git.monastech.xyz/wig")
diff --git a/meson.build b/meson.build
@@ -9,6 +9,7 @@ deps = [
m_dep,
dependency('wayland-client'),
dependency('guile-3.0'),
+ dependency('pixman-1'),
]
# Set up wayland protocols
@@ -26,9 +27,7 @@ devenv = environment()
devenv.append('GUILE_LOAD_PATH', join_paths(meson.current_source_dir(), 'scm'))
meson.add_devenv(devenv)
-common_sources = files(
- 'src/wl.c'
-)
+common_sources = files('src/surface.c', 'src/window.c')
executable(
'wig',
diff --git a/scm/wig.scm b/scm/wig.scm
@@ -66,7 +66,7 @@
(anchors-left anchors)
(anchors-right anchors)
exclusive)
- (error "A window cannot anchor to all sides and still be exclusive."))
+ (error "A window cannot anchor to all sides and be exclusive."))
(make-window label anchors exclusive width height margin))
(define-record-type <configuration>
diff --git a/src/main.c b/src/main.c
@@ -2,280 +2,188 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
-#include <sys/mman.h>
#include <unistd.h>
#include <wayland-client.h>
-#include "wl.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
-struct wig_window {
- int configured;
-
- char* label;
- uint32_t width;
- uint32_t height;
-
- struct wl_shm* shm;
-
- struct wl_buffer* wl_buffer;
- int wl_buffer_released;
-
- struct wl_surface* wl_surface;
- struct zwlr_layer_surface_v1* wlr_layer_surface;
-
- uint32_t* data;
-};
+#include "surface.h"
+#include "window.h"
struct wig_state {
- struct wl_display* display;
- struct wl_registry* registry;
-
- struct wl_compositor* compositor;
- struct wl_shm* shm;
- struct zwlr_layer_shell_v1* layer_shell;
-
- struct wig_window* windows;
-};
-
-/*
- * Buffer
- */
-
-static void wl_buffer_release(void* data, struct wl_buffer* wl_buffer) {
- struct wig_window* window = data;
- window->wl_buffer_released = 1;
-}
-
-static const struct wl_buffer_listener wl_buffer_listener = {
- .release = wl_buffer_release,
-};
-
-int reconfigure_window(struct wig_window* window, int width, int height) {
- if (window->data != NULL) {
- wl_buffer_destroy(window->wl_buffer);
- munmap(window->data, window->width * window->height * 4);
- }
-
- int stride = width * 4;
- int size = stride * height;
-
- int fd = allocate_shm_file(size);
- if (fd == -1) {
- return 0;
- }
-
- uint32_t* data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- close(fd);
- return 0;
- }
-
- struct wl_shm_pool* pool = wl_shm_create_pool(window->shm, fd, size);
- struct wl_buffer* buffer = wl_shm_pool_create_buffer(
- pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
- wl_shm_pool_destroy(pool);
- close(fd);
-
- /* Draw checkerboxed background */
- for (int y = 0; y < height; ++y) {
- for (int x = 0; x < width; ++x) {
- if ((x + y / 8 * 8) % 16 < 8)
- data[y * width + x] = 0xFF666666;
- else
- data[y * width + x] = 0xFFEEEEEE;
- }
- }
- wl_buffer_add_listener(buffer, &wl_buffer_listener, window);
-
- window->data = data;
- window->wl_buffer = buffer;
- window->configured = 1;
-
- return 0;
-}
-
-/*
- * Surface
- */
-
-static void zwlr_layer_surface_configure(
- void* data, struct zwlr_layer_surface_v1* zwlr_layer_surface_v1,
- uint32_t serial, uint32_t width, uint32_t height) {
- struct wig_window* window = data;
- zwlr_layer_surface_v1_ack_configure(zwlr_layer_surface_v1, serial);
-
- /* Skip reconfiguration if the size hasn't changed */
- if (width == window->width && height == window->height) return;
+ struct wl_display *wl_display;
+ struct wl_registry *wl_registry;
- int result = reconfigure_window(window, width, height);
+ struct wl_compositor *wl_compositor;
+ struct wl_shm *wl_shm;
+ struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1;
- if (result) {
- fprintf(stderr, "Failed to reconfigure \"%s\"", window->label);
- return;
- }
-
- wl_surface_attach(window->wl_surface, window->wl_buffer, 0, 0);
- wl_surface_commit(window->wl_surface);
- window->wl_buffer_released = 0;
-
- window->width = width;
- window->height = height;
-
- fprintf(stderr, "\"%s\" reconfigured\n", window->label);
- fprintf(stderr, " %u x %u\n", width, height);
-}
-
-static void zwlr_layer_surface_closed(
- void* data, struct zwlr_layer_surface_v1* zwlr_layer_surface_v1) {
- /* TODO */
-}
-
-static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
- .configure = zwlr_layer_surface_configure,
- .closed = zwlr_layer_surface_closed,
+ struct wig_window *windows;
};
-/*
- * Registry
- */
-
-static void registry_handle_global(void* data, struct wl_registry* registry,
- uint32_t name, const char* interface,
- uint32_t version) {
- struct wig_state* state = data;
-
- if (strcmp(interface, wl_compositor_interface.name) == 0) {
- state->compositor =
- wl_registry_bind(registry, name, &wl_compositor_interface, 4);
- } else if (strcmp(interface, wl_shm_interface.name) == 0) {
- state->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
- } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
- state->layer_shell =
- wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 2);
- }
+static void
+wl_registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t name, const char *interface,
+ uint32_t version)
+{
+ struct wig_state *state = data;
+
+ if (strcmp(interface, wl_compositor_interface.name) == 0) {
+ state->wl_compositor = wl_registry_bind(
+ registry, name, &wl_compositor_interface, 4);
+ } else if (strcmp(interface, wl_shm_interface.name) == 0) {
+ state->wl_shm =
+ wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
+ state->zwlr_layer_shell_v1 = wl_registry_bind(
+ registry, name, &zwlr_layer_shell_v1_interface, 2);
+ }
}
-static void registry_handle_global_remove(void* data,
- struct wl_registry* registry,
- uint32_t name) {
- /* TODO */
+static void
+wl_registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+ /* TODO */
}
-static const struct wl_registry_listener registry_listener = {
- .global = registry_handle_global,
- .global_remove = registry_handle_global_remove,
+static const struct wl_registry_listener wl_registry_listener = {
+ .global = wl_registry_handle_global,
+ .global_remove = wl_registry_handle_global_remove,
};
-/* Main */
-
-static void inner_main(void* data, int argc, char** argv) {
- struct wig_state* state = data;
-
- /* Evaluate configuration */
- SCM wig_configuration_type = scm_c_private_ref("wig", "<configuration>");
-
- SCM config = scm_c_primitive_load("wig.scm");
-
- /* TODO: Catch errors properly */
- if (scm_is_false(
- scm_eq_p(scm_struct_vtable(config), wig_configuration_type))) {
- fprintf(stderr, "Invalid configuration!\n");
- return;
- }
-
- SCM windows = scm_struct_ref(config, scm_from_int(0));
- size_t num_windows = scm_to_size_t(scm_length(windows));
- state->windows = malloc(num_windows * sizeof(struct wig_window));
-
- for (size_t i = 0; i < num_windows; i++) {
- SCM scm_window = scm_car(windows);
-
- char* label =
- scm_to_utf8_stringn(scm_struct_ref(scm_window, scm_from_int(0)), NULL);
-
- SCM anchors = scm_struct_ref(scm_window, scm_from_int(1));
- uint32_t anchor = 0;
- for (uint32_t i = 0; i < 4; i++)
- if (scm_is_true(scm_struct_ref(anchors, scm_from_uint32(i))))
- anchor |= (1 << i);
-
- int exclusive = scm_is_true(scm_struct_ref(scm_window, scm_from_int(2)));
-
- uint32_t width = scm_to_uint32(scm_struct_ref(scm_window, scm_from_int(3)));
- uint32_t height =
- scm_to_uint32(scm_struct_ref(scm_window, scm_from_int(4)));
- uint32_t margin =
- scm_to_uint32(scm_struct_ref(scm_window, scm_from_int(5)));
-
- struct wig_window* window = &state->windows[i];
- window->label = label;
- window->width = width;
- window->height = height;
-
- window->shm = state->shm;
-
- window->data = NULL;
- window->wl_surface = wl_compositor_create_surface(state->compositor);
- window->wlr_layer_surface = zwlr_layer_shell_v1_get_layer_surface(
- state->layer_shell, window->wl_surface, NULL,
- ZWLR_LAYER_SHELL_V1_LAYER_TOP, label);
-
- zwlr_layer_surface_v1_add_listener(window->wlr_layer_surface,
- &layer_surface_listener, window);
- zwlr_layer_surface_v1_set_size(window->wlr_layer_surface, width, height);
- zwlr_layer_surface_v1_set_anchor(window->wlr_layer_surface, anchor);
- zwlr_layer_surface_v1_set_margin(window->wlr_layer_surface, margin, margin,
- margin, margin);
-
- if (exclusive) {
- if ((anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) &&
- (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
- zwlr_layer_surface_v1_set_exclusive_zone(window->wlr_layer_surface,
- width);
- } else if ((anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) &&
- (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
- zwlr_layer_surface_v1_set_exclusive_zone(window->wlr_layer_surface,
- height);
- }
- }
-
- wl_surface_commit(window->wl_surface);
-
- windows = scm_cdr(windows);
- }
-
- /* Loop */
- while (wl_display_dispatch(state->display) != -1) {
- for (size_t i = 0; i < num_windows; i++) {
- state->windows[i].data[1] = 0xFFFF00FF;
-
- wl_surface_attach(state->windows[i].wl_surface,
- state->windows[i].wl_buffer, 0, 0);
- wl_surface_damage_buffer(state->windows[i].wl_surface, 1, 0, 1, 1);
- wl_surface_commit(state->windows[i].wl_surface);
- }
- }
-
- /* Cleanup */
- wl_display_disconnect(state->display);
+void *
+configure_and_run(void *data)
+{
+ struct wig_state *state = data;
+
+ SCM wig_scm_config_type = scm_c_private_ref("wig", "<configuration>");
+
+ SCM scm_config = scm_c_primitive_load("wig.scm");
+
+ if (scm_is_false(scm_eq_p(scm_struct_vtable(scm_config),
+ wig_scm_config_type))) {
+ fprintf(stderr, "Invalid configuration!\n");
+ return NULL;
+ }
+
+ /* Load and create windows */
+ SCM scm_windows = scm_struct_ref(scm_config, scm_from_int(0));
+ size_t num_windows = scm_to_size_t(scm_length(scm_windows));
+ state->windows = malloc(num_windows * sizeof(struct wig_window));
+
+ for (size_t i = 0; i < num_windows; i++) {
+ SCM scm_window = scm_car(scm_windows);
+ char *label = scm_to_utf8_stringn(
+ scm_struct_ref(scm_window, scm_from_int(0)), NULL);
+
+ SCM scm_anchors = scm_struct_ref(scm_window, scm_from_int(1));
+ uint32_t anchors = 0;
+ for (uint32_t i = 0; i < 4; i++) {
+ if scm_is_true (scm_struct_ref(scm_anchors,
+ scm_from_uint32(i))) {
+ anchors |= (1 << i);
+ }
+ }
+
+ int exclusive = scm_is_true(
+ scm_struct_ref(scm_window, scm_from_int(2)));
+ uint32_t width = scm_to_uint32(
+ scm_struct_ref(scm_window, scm_from_int(3)));
+ uint32_t height = scm_to_uint32(
+ scm_struct_ref(scm_window, scm_from_int(4)));
+ uint32_t margin = scm_to_uint32(
+ scm_struct_ref(scm_window, scm_from_int(5)));
+
+ struct wig_surface surface;
+ wig_surface_init(&surface, state->wl_shm, state->wl_compositor);
+
+ struct wig_window *window = &state->windows[i];
+ wig_window_init(window, label, surface,
+ state->zwlr_layer_shell_v1);
+
+ zwlr_layer_surface_v1_set_size(window->zwlr_layer_surface_v1,
+ width, height);
+ zwlr_layer_surface_v1_set_anchor(window->zwlr_layer_surface_v1,
+ anchors);
+
+ if (exclusive) {
+ if ((anchors & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) &&
+ (anchors & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
+ zwlr_layer_surface_v1_set_exclusive_zone(
+ window->zwlr_layer_surface_v1, width);
+ } else if ((anchors &
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) &&
+ (anchors &
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
+ zwlr_layer_surface_v1_set_exclusive_zone(
+ window->zwlr_layer_surface_v1, height);
+ }
+ }
+
+ zwlr_layer_surface_v1_set_margin(window->zwlr_layer_surface_v1,
+ margin, margin, margin,
+ margin);
+
+ wig_surface_commit(&window->surface);
+
+ scm_windows = scm_cdr(scm_windows);
+ }
+
+ while (wl_display_dispatch(state->wl_display) != -1) {
+ /* TODO */
+ }
+
+ return NULL;
}
-int main(int argc, char* argv[]) {
- struct wig_state state = {NULL};
-
- state.display = wl_display_connect(NULL);
- if (!state.display) {
- fprintf(stderr, "Failed to connect to Wayland display.\n");
- return 1;
- }
-
- state.registry = wl_display_get_registry(state.display);
- wl_registry_add_listener(state.registry, ®istry_listener, &state);
- wl_display_roundtrip(state.display);
-
- /* TODO: Validate registry */
-
- scm_boot_guile(argc, argv, inner_main, &state);
- return 0;
+int
+main(int argc, char *argv[])
+{
+ struct wig_state state = { NULL };
+
+ state.wl_display = wl_display_connect(NULL);
+ if (!state.wl_display) {
+ fprintf(stderr, "Failed to connect to a Wayland display!");
+ return 1;
+ }
+
+ state.wl_registry = wl_display_get_registry(state.wl_display);
+ wl_registry_add_listener(state.wl_registry, &wl_registry_listener,
+ &state);
+ wl_display_roundtrip(state.wl_display);
+
+ if (!state.wl_compositor || !state.wl_shm ||
+ !state.zwlr_layer_shell_v1) {
+ fprintf(stderr, "Failed to bind the necessary globals!\n");
+ return 1;
+ }
+
+ fprintf(stderr, "Entering guile mode\n");
+ scm_with_guile(configure_and_run, &state);
+ fprintf(stderr, "Exiting guile mode\n");
+
+ /* Demo window */
+ /*
+ struct wig_surface surface;
+ wig_surface_init(&surface, state.wl_shm, state.wl_compositor);
+
+ struct wig_window window;
+ wig_window_init(&window, "bottom_bar", surface,
+ state.zwlr_layer_shell_v1);
+
+ zwlr_layer_surface_v1_set_size(window.zwlr_layer_surface_v1, 0, 64);
+ zwlr_layer_surface_v1_set_anchor(
+ window.zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM);
+ zwlr_layer_surface_v1_set_exclusive_zone(window.zwlr_layer_surface_v1,
+ 64);
+ zwlr_layer_surface_v1_set_margin(window.zwlr_layer_surface_v1, 8, 8, 8,
+ 8);
+ wl_surface_commit(window.surface.wl_surface);
+ */
+
+ wl_display_disconnect(state.wl_display);
}
diff --git a/src/surface.c b/src/surface.c
@@ -0,0 +1,162 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <pixman.h>
+#include <wayland-client.h>
+
+#include "surface.h"
+
+/*
+ * SHM Utils
+ */
+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;
+}
+
+static int
+allocate_shm_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;
+}
+
+/*
+ * Surface
+ */
+int
+wig_surface_init(struct wig_surface *surface, struct wl_shm *wl_shm,
+ struct wl_compositor *wl_compositor)
+{
+ surface->wl_shm = wl_shm;
+
+ surface->configured = 0;
+ surface->width = 0;
+ surface->height = 0;
+ surface->wl_surface = wl_compositor_create_surface(wl_compositor);
+
+ surface->free = 0;
+ surface->buffer = NULL;
+ surface->wl_buffer = NULL;
+
+ return 0;
+}
+
+static void
+wl_buffer_release(void *data, struct wl_buffer *wl_buffer)
+{
+ struct wig_surface *surface = data;
+ surface->free = 1;
+}
+
+static const struct wl_buffer_listener wl_buffer_listener = {
+ .release = wl_buffer_release,
+};
+
+int
+wig_surface_reconfigure(struct wig_surface *surface, uint32_t width,
+ uint32_t height)
+{
+ if (surface->buffer != NULL) {
+ wl_buffer_destroy(surface->wl_buffer);
+ munmap(surface->buffer, surface->width * surface->height * 4);
+ }
+
+ size_t stride = width * 4;
+ size_t size = stride * height;
+
+ int fd = allocate_shm_file(size);
+ if (fd < 0) {
+ return -1;
+ }
+
+ uint32_t *buffer =
+ mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (buffer == MAP_FAILED) {
+ close(fd);
+ return -1;
+ }
+
+ struct wl_shm_pool *pool =
+ wl_shm_create_pool(surface->wl_shm, fd, size);
+ struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(
+ pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888);
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ pixman_fill(buffer, width, 32, 0, 0, width, height, 0xFFCECDC3);
+
+ pixman_fill(buffer, width, 32, 2, 2, width - 4, height - 4, 0xFFFFFCF0);
+
+ wl_buffer_add_listener(wl_buffer, &wl_buffer_listener, surface);
+
+ surface->configured = 1;
+ surface->width = width;
+ surface->height = height;
+
+ surface->buffer = buffer;
+ surface->wl_buffer = wl_buffer;
+ surface->free = 1;
+
+ return 0;
+}
+
+int
+wig_surface_commit(struct wig_surface *surface)
+{
+ if (surface->configured) {
+ if (!surface->free) {
+ fprintf(stderr,
+ "Refusing to commit unreleased surface\n");
+ return -1;
+ }
+ wl_surface_attach(surface->wl_surface, surface->wl_buffer, 0,
+ 0);
+ surface->free = 0;
+ }
+
+ wl_surface_commit(surface->wl_surface);
+
+ return 0;
+}
diff --git a/src/surface.h b/src/surface.h
@@ -0,0 +1,26 @@
+#ifndef WIG_SURFACE
+#define WIG_SURFACE
+
+#include <stdint.h>
+#include <wayland-client.h>
+
+struct wig_surface {
+ struct wl_shm *wl_shm;
+
+ int configured;
+ uint32_t width;
+ uint32_t height;
+ struct wl_surface *wl_surface;
+
+ int free;
+ uint32_t *buffer;
+ struct wl_buffer *wl_buffer;
+};
+
+int wig_surface_init(struct wig_surface *surface, struct wl_shm *wl_shm,
+ struct wl_compositor *wl_compositor);
+int wig_surface_reconfigure(struct wig_surface *surface, uint32_t width,
+ uint32_t height);
+int wig_surface_commit(struct wig_surface *surface);
+
+#endif
diff --git a/src/window.c b/src/window.c
@@ -0,0 +1,65 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include "wlr-layer-shell-unstable-v1-client-protocol.h"
+#include <wayland-client.h>
+
+#include "surface.h"
+#include "window.h"
+
+static void
+zwlr_layer_surface_v1_configure(
+ void *data, struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
+ uint32_t serial, uint32_t width, uint32_t height)
+{
+ zwlr_layer_surface_v1_ack_configure(zwlr_layer_surface_v1, serial);
+
+ struct wig_window *window = data;
+
+ /* Skip pointless reconfiguration */
+ if (window->surface.configured && width == window->surface.width &&
+ height == window->surface.height) {
+ return;
+ }
+
+ int result = wig_surface_reconfigure(&window->surface, width, height);
+
+ if (result) {
+ fprintf(stderr, "Failed to reconfigure %s's surface\n",
+ window->label);
+ return;
+ }
+
+ wig_surface_commit(&window->surface);
+}
+
+static void
+zwlr_layer_surface_v1_closed(
+ void *data, struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
+{
+ /* TODO */
+}
+
+static const struct zwlr_layer_surface_v1_listener
+ zwlr_layer_surface_v1_listener = {
+ .configure = zwlr_layer_surface_v1_configure,
+ .closed = zwlr_layer_surface_v1_closed,
+ };
+
+int
+wig_window_init(struct wig_window *window, char *label,
+ struct wig_surface surface,
+ struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
+{
+ window->label = label;
+ window->surface = surface;
+
+ window->zwlr_layer_surface_v1 = zwlr_layer_shell_v1_get_layer_surface(
+ zwlr_layer_shell_v1, window->surface.wl_surface, NULL,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP, label);
+ zwlr_layer_surface_v1_add_listener(window->zwlr_layer_surface_v1,
+ &zwlr_layer_surface_v1_listener,
+ window);
+
+ return 0;
+}
diff --git a/src/window.h b/src/window.h
@@ -0,0 +1,19 @@
+#ifndef WIG_WINDOW
+#define WIG_WINDOW
+
+#include <stdint.h>
+#include <wayland-client.h>
+
+#include "surface.h"
+
+struct wig_window {
+ char *label;
+ struct wig_surface surface;
+ struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1;
+};
+
+int wig_window_init(struct wig_window *window, char *label,
+ struct wig_surface surface,
+ struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1);
+
+#endif
diff --git a/src/wl.c b/src/wl.c
@@ -1,44 +0,0 @@
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <time.h>
-#include <unistd.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 allocate_shm_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/wl.h b/src/wl.h
@@ -1,6 +0,0 @@
-#ifndef WIG_WL
-#define WIG_WL
-
-int allocate_shm_file(size_t size);
-
-#endif