main.c (8506B)
1 #define _POSIX_C_SOURCE 200809L 2 #include <assert.h> 3 #include <cairo/cairo.h> 4 #include <drm_fourcc.h> 5 #include <getopt.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <time.h> 9 #include <wayland-server.h> 10 #include <wlr/backend.h> 11 #include <wlr/render/wlr_renderer.h> 12 #include <wlr/render/wlr_texture.h> 13 #include <wlr/types/wlr_compositor.h> 14 #include <wlr/types/wlr_data_control_v1.h> 15 #include <wlr/types/wlr_data_device.h> 16 #include <wlr/types/wlr_export_dmabuf_v1.h> 17 #include <wlr/types/wlr_gamma_control_v1.h> 18 //#include <wlr/types/wlr_gtk_primary_selection.h> 19 #include <wlr/types/wlr_layer_shell_v1.h> 20 #include <wlr/types/wlr_primary_selection_v1.h> 21 #include <wlr/types/wlr_screencopy_v1.h> 22 #include <wlr/types/wlr_seat.h> 23 #include <wlr/types/wlr_xcursor_manager.h> 24 #include <wlr/types/wlr_xdg_shell.h> 25 #include <wlr/types/wlr_xdg_output_v1.h> 26 #include <wlr/util/log.h> 27 #include "layers.h" 28 #include "server.h" 29 #include "view.h" 30 31 static void gen_menu_textures(struct wio_server *server) { 32 struct wlr_renderer *renderer = server->renderer; 33 cairo_surface_t *surf = cairo_image_surface_create( 34 CAIRO_FORMAT_ARGB32, 128, 128); // numbers pulled from ass 35 cairo_t *cairo = cairo_create(surf); 36 cairo_select_font_face(cairo, "monospace", 37 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 38 cairo_set_font_size(cairo, 14); 39 cairo_set_source_rgb(cairo, 0, 0, 0); 40 41 char *text[] = { "New", "Resize", "Move", "Delete", "Hide" }; 42 for (size_t i = 0; i < sizeof(text) / sizeof(text[0]); ++i) { 43 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 44 cairo_paint(cairo); 45 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 46 cairo_text_extents_t extents; 47 cairo_text_extents(cairo, text[i], &extents); 48 cairo_move_to(cairo, 0, extents.height); 49 cairo_show_text(cairo, text[i]); 50 cairo_surface_flush(surf); 51 unsigned char *data = cairo_image_surface_get_data(surf); 52 server->menu.inactive_textures[i] = wlr_texture_from_pixels(renderer, 53 DRM_FORMAT_ARGB8888, 54 cairo_image_surface_get_stride(surf), 55 extents.width + 2, extents.height + 2, data); 56 } 57 58 cairo_set_source_rgb(cairo, 1, 1, 1); 59 for (size_t i = 0; i < sizeof(text) / sizeof(text[0]); ++i) { 60 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 61 cairo_paint(cairo); 62 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 63 cairo_text_extents_t extents; 64 cairo_text_extents(cairo, text[i], &extents); 65 cairo_move_to(cairo, 0, extents.height); 66 cairo_show_text(cairo, text[i]); 67 cairo_surface_flush(surf); 68 unsigned char *data = cairo_image_surface_get_data(surf); 69 server->menu.active_textures[i] = wlr_texture_from_pixels(renderer, 70 DRM_FORMAT_ARGB8888, 71 cairo_image_surface_get_stride(surf), 72 extents.width + 2, extents.height + 2, data); 73 } 74 75 cairo_destroy(cairo); 76 cairo_surface_destroy(surf); 77 } 78 79 static enum wl_output_transform str_to_transform(const char *str) { 80 if (strcmp(str, "normal") == 0 || strcmp(str, "0") == 0) { 81 return WL_OUTPUT_TRANSFORM_NORMAL; 82 } else if (strcmp(str, "90") == 0) { 83 return WL_OUTPUT_TRANSFORM_90; 84 } else if (strcmp(str, "180") == 0) { 85 return WL_OUTPUT_TRANSFORM_180; 86 } else if (strcmp(str, "270") == 0) { 87 return WL_OUTPUT_TRANSFORM_270; 88 } else if (strcmp(str, "flipped") == 0) { 89 return WL_OUTPUT_TRANSFORM_FLIPPED; 90 } else if (strcmp(str, "flipped-90") == 0) { 91 return WL_OUTPUT_TRANSFORM_FLIPPED_90; 92 } else if (strcmp(str, "flipped-180") == 0) { 93 return WL_OUTPUT_TRANSFORM_FLIPPED_180; 94 } else if (strcmp(str, "flipped-270") == 0) { 95 return WL_OUTPUT_TRANSFORM_FLIPPED_270; 96 } else { 97 fprintf(stderr, "Invalid output transform %s\n", str); 98 exit(1); 99 } 100 } 101 102 int main(int argc, char **argv) { 103 struct wio_server server = { 0 }; 104 server.cage = "cage -d"; 105 server.term = "alacritty"; 106 wlr_log_init(WLR_DEBUG, NULL); 107 wl_list_init(&server.output_configs); 108 109 int c; 110 while ((c = getopt(argc, argv, "c:t:o:h")) != -1) { 111 switch (c) { 112 case 'c': 113 server.cage = optarg; 114 break; 115 case 't': 116 server.term = optarg; 117 break; 118 case 'o':; 119 // name:x:y:width:height:scale:transform 120 struct wio_output_config *config = 121 calloc(1, sizeof(struct wio_output_config)); 122 wl_list_insert(&server.output_configs, &config->link); 123 const char *tok = strtok(optarg, ":"); 124 assert(tok); 125 config->name = strdup(tok); 126 tok = strtok(NULL, ":"); 127 assert(tok); 128 config->x = atoi(tok); 129 tok = strtok(NULL, ":"); 130 assert(tok); 131 config->y = atoi(tok); 132 tok = strtok(NULL, ":"); 133 if (!tok) break; 134 config->width = atoi(tok); 135 tok = strtok(NULL, ":"); 136 assert(tok); 137 config->height = atoi(tok); 138 tok = strtok(NULL, ":"); 139 if (!tok) break; 140 config->scale = atoi(tok); 141 tok = strtok(NULL, ":"); 142 if (!tok) break; 143 config->transform = str_to_transform(tok); 144 break; 145 case 'h': 146 printf("Usage: %s [-t <term>] [-c <cage>] [-o <output config>...]\n", 147 argv[0]); 148 return 0; 149 default: 150 fprintf(stderr, "Unrecognized option %c\n", c); 151 return 1; 152 } 153 } 154 155 server.wl_display = wl_display_create(); 156 server.backend = wlr_backend_autocreate(server.wl_display); 157 server.renderer = wlr_backend_get_renderer(server.backend); 158 wlr_renderer_init_wl_display(server.renderer, server.wl_display); 159 160 wlr_compositor_create(server.wl_display, server.renderer); 161 wlr_data_device_manager_create(server.wl_display); 162 163 wlr_export_dmabuf_manager_v1_create(server.wl_display); 164 wlr_screencopy_manager_v1_create(server.wl_display); 165 wlr_data_control_manager_v1_create(server.wl_display); 166 wlr_primary_selection_v1_device_manager_create(server.wl_display); 167 168 wlr_gamma_control_manager_v1_create(server.wl_display); 169 // wlr_gtk_primary_selection_device_manager_create(server.wl_display); 170 171 wl_list_init(&server.outputs); 172 server.new_output.notify = server_new_output; 173 wl_signal_add(&server.backend->events.new_output, &server.new_output); 174 175 server.output_layout = wlr_output_layout_create(); 176 wlr_xdg_output_manager_v1_create(server.wl_display, server.output_layout); 177 178 server.cursor = wlr_cursor_create(); 179 wlr_cursor_attach_output_layout(server.cursor, server.output_layout); 180 server.cursor_mgr = wlr_xcursor_manager_create(NULL, 24); 181 wlr_xcursor_manager_load(server.cursor_mgr, 1); 182 183 struct wio_output_config *config; 184 wl_list_for_each(config, &server.output_configs, link) { 185 if (config->scale > 1){ 186 wlr_xcursor_manager_load(server.cursor_mgr, config->scale); 187 } 188 } 189 190 server.cursor_motion.notify = server_cursor_motion; 191 wl_signal_add(&server.cursor->events.motion, &server.cursor_motion); 192 server.cursor_motion_absolute.notify = server_cursor_motion_absolute; 193 wl_signal_add(&server.cursor->events.motion_absolute, 194 &server.cursor_motion_absolute); 195 server.cursor_button.notify = server_cursor_button; 196 wl_signal_add(&server.cursor->events.button, &server.cursor_button); 197 server.cursor_axis.notify = server_cursor_axis; 198 wl_signal_add(&server.cursor->events.axis, &server.cursor_axis); 199 server.cursor_frame.notify = server_cursor_frame; 200 wl_signal_add(&server.cursor->events.frame, &server.cursor_frame); 201 202 wl_list_init(&server.inputs); 203 server.new_input.notify = server_new_input; 204 wl_signal_add(&server.backend->events.new_input, &server.new_input); 205 206 server.seat = wlr_seat_create(server.wl_display, "seat0"); 207 server.request_cursor.notify = seat_request_cursor; 208 wl_signal_add(&server.seat->events.request_set_cursor, 209 &server.request_cursor); 210 wl_list_init(&server.keyboards); 211 wl_list_init(&server.pointers); 212 213 wl_list_init(&server.views); 214 server.xdg_shell = wlr_xdg_shell_create(server.wl_display); 215 server.new_xdg_surface.notify = server_new_xdg_surface; 216 wl_signal_add(&server.xdg_shell->events.new_surface, 217 &server.new_xdg_surface); 218 219 wl_list_init(&server.new_views); 220 221 server.layer_shell = wlr_layer_shell_v1_create(server.wl_display); 222 server.new_layer_surface.notify = server_new_layer_surface; 223 wl_signal_add(&server.layer_shell->events.new_surface, 224 &server.new_layer_surface); 225 226 server.menu.x = server.menu.y = -1; 227 gen_menu_textures(&server); 228 server.input_state = INPUT_STATE_NONE; 229 230 const char *socket = wl_display_add_socket_auto(server.wl_display); 231 if (!socket) { 232 wlr_backend_destroy(server.backend); 233 return 1; 234 } 235 236 if (!wlr_backend_start(server.backend)) { 237 wlr_backend_destroy(server.backend); 238 wl_display_destroy(server.wl_display); 239 return 1; 240 } 241 242 setenv("WAYLAND_DISPLAY", socket, true); 243 wlr_log(WLR_INFO, 244 "Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); 245 wl_display_run(server.wl_display); 246 247 wl_display_destroy_clients(server.wl_display); 248 wl_display_destroy(server.wl_display); 249 return 0; 250 }