main.c (6740B)
1 /* 2 * Wig --- Widgets in Guile 3 * Copyright © 2026 Luke Willis <lukejw@monastech.xyz> 4 * 5 * This file is part of Wig. 6 * 7 * Wig is free software: you can redistribute it and/or modify it under 8 * the terms of the GNU General Public License as published by the Free 9 * Software Foundation, either version 3 of the License, or (at your option) 10 * any later version. 11 * 12 * Wig is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with Wig. If not, see <https://www.gnu.org/licenses/>. 19 */ 20 21 #include <libguile.h> 22 #include <stdint.h> 23 #include <stdio.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #include "wlr-layer-shell-unstable-v1-client-protocol.h" 28 #include <wayland-client.h> 29 30 #include "globals.h" 31 #include "surface.h" 32 #include "window.h" 33 34 struct wig_state { 35 struct wl_display *wl_display; 36 struct wl_registry *wl_registry; 37 38 struct wl_compositor *wl_compositor; 39 struct wl_shm *wl_shm; 40 struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1; 41 42 struct wig_window *windows; 43 }; 44 45 static void 46 wl_registry_handle_global(void *data, struct wl_registry *registry, 47 uint32_t name, const char *interface, 48 uint32_t version) 49 { 50 struct wig_state *state = data; 51 52 if (strcmp(interface, wl_compositor_interface.name) == 0) { 53 state->wl_compositor = wl_registry_bind( 54 registry, name, &wl_compositor_interface, 4); 55 } else if (strcmp(interface, wl_shm_interface.name) == 0) { 56 state->wl_shm = 57 wl_registry_bind(registry, name, &wl_shm_interface, 1); 58 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { 59 state->zwlr_layer_shell_v1 = wl_registry_bind( 60 registry, name, &zwlr_layer_shell_v1_interface, 2); 61 } 62 } 63 64 static void 65 wl_registry_handle_global_remove(void *data, struct wl_registry *registry, 66 uint32_t name) 67 { 68 /* TODO */ 69 } 70 71 static const struct wl_registry_listener wl_registry_listener = { 72 .global = wl_registry_handle_global, 73 .global_remove = wl_registry_handle_global_remove, 74 }; 75 76 void * 77 configure_and_run(void *data) 78 { 79 struct wig_state *state = data; 80 81 /* Load global functions/types */ 82 scm_count_widgets = scm_c_private_ref("wig", "count-widgets"); 83 scm_compile_widgets = scm_c_private_ref("wig", "compile-widgets"); 84 85 SCM wig_scm_config_type = scm_c_private_ref("wig", "<configuration>"); 86 SCM scm_config = scm_c_primitive_load("wig.scm"); 87 88 if (scm_is_false(scm_eq_p(scm_struct_vtable(scm_config), 89 wig_scm_config_type))) { 90 fprintf(stderr, "Invalid configuration!\n"); 91 return NULL; 92 } 93 94 /* Load and create windows */ 95 SCM scm_windows = scm_struct_ref(scm_config, scm_from_int(1)); 96 size_t num_windows = scm_to_size_t(scm_length(scm_windows)); 97 state->windows = malloc(num_windows * sizeof(struct wig_window)); 98 99 for (size_t i = 0; i < num_windows; i++) { 100 SCM scm_window = scm_car(scm_windows); 101 char *label = scm_to_utf8_stringn( 102 scm_struct_ref(scm_window, scm_from_int(0)), NULL); 103 104 SCM scm_anchors = scm_struct_ref(scm_window, scm_from_int(1)); 105 uint32_t anchors = 0; 106 for (uint32_t i = 0; i < 4; i++) { 107 if scm_is_true (scm_struct_ref(scm_anchors, 108 scm_from_uint32(i))) { 109 anchors |= (1 << i); 110 } 111 } 112 113 int exclusive = scm_is_true( 114 scm_struct_ref(scm_window, scm_from_int(2))); 115 uint32_t width = scm_to_uint32( 116 scm_struct_ref(scm_window, scm_from_int(3))); 117 uint32_t height = scm_to_uint32( 118 scm_struct_ref(scm_window, scm_from_int(4))); 119 uint32_t margin = scm_to_uint32( 120 scm_struct_ref(scm_window, scm_from_int(5))); 121 122 SCM widgets = scm_struct_ref(scm_window, scm_from_int(6)); 123 124 struct wig_surface surface; 125 wig_surface_init(&surface, state->wl_shm, state->wl_compositor); 126 127 struct wig_window *window = &state->windows[i]; 128 window->widgets = widgets; 129 wig_window_init(window, label, surface, 130 state->zwlr_layer_shell_v1); 131 132 zwlr_layer_surface_v1_set_size(window->zwlr_layer_surface_v1, 133 width, height); 134 zwlr_layer_surface_v1_set_anchor(window->zwlr_layer_surface_v1, 135 anchors); 136 137 if (exclusive) { 138 if ((anchors & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) && 139 (anchors & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { 140 zwlr_layer_surface_v1_set_exclusive_zone( 141 window->zwlr_layer_surface_v1, width); 142 } else if ((anchors & 143 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) && 144 (anchors & 145 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { 146 zwlr_layer_surface_v1_set_exclusive_zone( 147 window->zwlr_layer_surface_v1, height); 148 } 149 } 150 151 zwlr_layer_surface_v1_set_margin(window->zwlr_layer_surface_v1, 152 margin, margin, margin, 153 margin); 154 155 wig_surface_commit(&window->surface); 156 157 scm_windows = scm_cdr(scm_windows); 158 } 159 160 while (wl_display_dispatch(state->wl_display) != -1) { 161 /* TODO */ 162 } 163 164 return NULL; 165 } 166 167 int 168 main(int argc, char *argv[]) 169 { 170 struct wig_state state = { NULL }; 171 172 state.wl_display = wl_display_connect(NULL); 173 if (!state.wl_display) { 174 fprintf(stderr, "Failed to connect to a Wayland display!"); 175 return 1; 176 } 177 178 state.wl_registry = wl_display_get_registry(state.wl_display); 179 wl_registry_add_listener(state.wl_registry, &wl_registry_listener, 180 &state); 181 wl_display_roundtrip(state.wl_display); 182 183 if (!state.wl_compositor || !state.wl_shm || 184 !state.zwlr_layer_shell_v1) { 185 fprintf(stderr, "Failed to bind the necessary globals!\n"); 186 return 1; 187 } 188 189 fprintf(stderr, "Entering guile mode\n"); 190 scm_with_guile(configure_and_run, &state); 191 fprintf(stderr, "Exiting guile mode\n"); 192 193 /* Demo window */ 194 /* 195 struct wig_surface surface; 196 wig_surface_init(&surface, state.wl_shm, state.wl_compositor); 197 198 struct wig_window window; 199 wig_window_init(&window, "bottom_bar", surface, 200 state.zwlr_layer_shell_v1); 201 202 zwlr_layer_surface_v1_set_size(window.zwlr_layer_surface_v1, 0, 64); 203 zwlr_layer_surface_v1_set_anchor( 204 window.zwlr_layer_surface_v1, 205 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 206 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | 207 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM); 208 zwlr_layer_surface_v1_set_exclusive_zone(window.zwlr_layer_surface_v1, 209 64); 210 zwlr_layer_surface_v1_set_margin(window.zwlr_layer_surface_v1, 8, 8, 8, 211 8); 212 wl_surface_commit(window.surface.wl_surface); 213 */ 214 215 wl_display_disconnect(state.wl_display); 216 }