main.c 8.5 KB

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