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 }