From: Johan Malm Date: Mon, 11 May 2020 05:59:27 +0000 (+0100) Subject: main.c: refactor main() X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=afdadb004b31705f8e29a8e8a8dcdea27e947785;p=proto%2Flabwc.git main.c: refactor main() --- diff --git a/main.c b/main.c index e55dbe9e..b0099f27 100644 --- a/main.c +++ b/main.c @@ -8,9 +8,11 @@ int main(int argc, char *argv[]) { - wlr_log_init(WLR_ERROR, NULL); + struct server server = { 0 }; char *startup_cmd = NULL; + wlr_log_init(WLR_ERROR, NULL); + int c; while ((c = getopt(argc, argv, "s:h")) != -1) { switch (c) { @@ -27,84 +29,115 @@ int main(int argc, char *argv[]) return 0; } - struct server server; - /* The Wayland display is managed by libwayland. It handles accepting - * clients from the Unix socket, manging Wayland globals, and so on. */ + /* Wayland requires XDG_RUNTIME_DIR to be set */ + if (!getenv("XDG_RUNTIME_DIR")) { + wlr_log(WLR_ERROR, "XDG_RUNTIME_DIR is not set"); + return 1; + } + + /* + * The Wayland display is managed by libwayland. It handles accepting + * clients from the Unix socket, manging Wayland globals, and so on. + */ server.wl_display = wl_display_create(); - /* The backend is a wlroots feature which abstracts the underlying input - * and output hardware. The autocreate option will choose the most - * suitable backend based on the current environment, such as opening an - * X11 window if an X11 server is running. The NULL argument here - * optionally allows you to pass in a custom renderer if wlr_renderer - * doesn't meet your needs. The backend uses the renderer, for example, - * to fall back to software cursors if the backend does not support - * hardware cursors (some older GPUs don't). */ + if (!server.wl_display) { + wlr_log(WLR_ERROR, "cannot allocate a wayland display"); + return 1; + } + + /* TODO: Catch signals. Maybe SIGHUP for reconfigure */ + + /* + * The backend is a wlroots feature which abstracts the underlying + * input and output hardware. the autocreate option will choose the + * most suitable backend based on the current environment, such as + * opening an x11 window if an x11 server is running. the null + * argument here optionally allows you to pass in a custom renderer if + * wlr_renderer doesn't meet your needs. the backend uses the + * renderer, for example, to fall back to software cursors if the + * backend does not support hardware cursors (some older gpus don't). + */ server.backend = wlr_backend_autocreate(server.wl_display, NULL); + if (!server.backend) { + wlr_log(WLR_ERROR, "unable to create the wlroots backend"); + return 1; + } - /* If we don't provide a renderer, autocreate makes a GLES2 renderer for - * us. The renderer is responsible for defining the various pixel + /* + * If we don't provide a renderer, autocreate makes a GLES2 renderer + * for us. The renderer is responsible for defining the various pixel * formats it supports for shared memory, this configures that for - * clients. */ + * clients. + */ server.renderer = wlr_backend_get_renderer(server.backend); wlr_renderer_init_wl_display(server.renderer, server.wl_display); - /* This creates some hands-off wlroots interfaces. The compositor is + wl_list_init(&server.views); + wl_list_init(&server.outputs); + + /* + * Create an output layout, which a wlroots utility for working with + * an arrangement of screens in a physical layout. + */ + server.output_layout = wlr_output_layout_create(); + if (!server.output_layout) { + wlr_log(WLR_ERROR, "unable to create output layout"); + return 1; + } + + /* + * Create some hands-off wlroots interfaces. The compositor is * necessary for clients to allocate surfaces and the data device * manager handles the clipboard. Each of these wlroots interfaces has * room for you to dig your fingers in and play with their behavior if - * you want. */ - server.compositor = - wlr_compositor_create(server.wl_display, server.renderer); - wlr_data_device_manager_create(server.wl_display); - - wlr_export_dmabuf_manager_v1_create(server.wl_display); - wlr_screencopy_manager_v1_create(server.wl_display); - wlr_data_control_manager_v1_create(server.wl_display); - wlr_gamma_control_manager_v1_create(server.wl_display); - wlr_primary_selection_v1_device_manager_create(server.wl_display); + * you want. + */ + server.compositor = wlr_compositor_create(server.wl_display, + server.renderer); + if (!server.compositor) { + wlr_log(WLR_ERROR, "unable to create the wlroots compositor"); + return 1; + } - /* Creates an output layout, which a wlroots utility for working with an - * arrangement of screens in a physical layout. */ - server.output_layout = wlr_output_layout_create(); + struct wlr_data_device_manager *device_manager = NULL; + device_manager = wlr_data_device_manager_create(server.wl_display); + if (!device_manager) { + wlr_log(WLR_ERROR, "unable to create data device manager"); + return 1; + } - /* Configure a listener to be notified when new outputs are available on - * the backend. */ - wl_list_init(&server.outputs); + /* + * Configure a listener to be notified when new outputs are available + * on the backend. + */ server.new_output.notify = server_new_output; wl_signal_add(&server.backend->events.new_output, &server.new_output); - /* Set up our list of views and the xdg-shell. The xdg-shell is a - * Wayland protocol which is used for application windows. For more - * detail on shells, refer to my article: - * - * https://drewdevault.com/2018/07/29/Wayland-shells.html - */ - wl_list_init(&server.views); - server.xdg_shell = wlr_xdg_shell_create(server.wl_display); - server.new_xdg_surface.notify = xdg_surface_new; - wl_signal_add(&server.xdg_shell->events.new_surface, - &server.new_xdg_surface); - /* - * Creates a cursor, which is a wlroots utility for tracking the cursor - * image shown on screen. + * Configures a seat, which is a single "seat" at which a user sits + * and operates the computer. This conceptually includes up to one + * keyboard, pointer, touch, and drawing tablet device. We also rig up + * a listener to let us know when new input devices are available on + * the backend. */ + server.seat = wlr_seat_create(server.wl_display, "seat0"); + if (!server.seat) { + wlr_log(WLR_ERROR, "cannot allocate seat0"); + return 1; + } + server.cursor = wlr_cursor_create(); + if (!server.cursor) { + wlr_log(WLR_ERROR, "unable to create cursor"); + return 1; + } wlr_cursor_attach_output_layout(server.cursor, server.output_layout); + server.cursor_mgr = wlr_xcursor_manager_create(NULL, XCURSOR_SIZE); + if (!server.cursor_mgr) { + wlr_log(WLR_ERROR, "cannot create xcursor manager"); + return 1; + } - /* - * wlr_cursor *only* displays an image on screen. It does not move - * around when the pointer moves. However, we can attach input devices - * to it, and it will generate aggregate events for all of them. In - * these events, we can choose how we want to process them, forwarding - * them to clients and moving the cursor around. More detail on this - * process is described in my input handling blog post: - * - * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html - * - * And more comments are sprinkled throughout the notify functions - * above. - */ server.cursor_motion.notify = server_cursor_motion; wl_signal_add(&server.cursor->events.motion, &server.cursor_motion); server.cursor_motion_absolute.notify = server_cursor_motion_absolute; @@ -117,62 +150,63 @@ int main(int argc, char *argv[]) server.cursor_frame.notify = server_cursor_frame; wl_signal_add(&server.cursor->events.frame, &server.cursor_frame); - /* - * Configures a seat, which is a single "seat" at which a user sits and - * operates the computer. This conceptually includes up to one keyboard, - * pointer, touch, and drawing tablet device. We also rig up a listener - * to let us know when new input devices are available on the backend. - */ wl_list_init(&server.keyboards); server.new_input.notify = server_new_input; wl_signal_add(&server.backend->events.new_input, &server.new_input); - server.seat = wlr_seat_create(server.wl_display, "seat0"); server.request_cursor.notify = seat_request_cursor; wl_signal_add(&server.seat->events.request_set_cursor, &server.request_cursor); - /* Add a Unix socket to the Wayland display. */ - const char *socket = wl_display_add_socket_auto(server.wl_display); - if (!socket) { - wlr_backend_destroy(server.backend); - return 1; - } - - /* Start the backend. This will enumerate outputs and inputs, become the - * DRM master, etc */ - if (!wlr_backend_start(server.backend)) { - wlr_backend_destroy(server.backend); - wl_display_destroy(server.wl_display); + /* Init xdg-shell */ + server.xdg_shell = wlr_xdg_shell_create(server.wl_display); + if (!server.xdg_shell) { + wlr_log(WLR_ERROR, "unable to create the XDG shell interface"); return 1; } + server.new_xdg_surface.notify = xdg_surface_new; + wl_signal_add(&server.xdg_shell->events.new_surface, + &server.new_xdg_surface); - /* Set the WAYLAND_DISPLAY environment variable to our socket and run - * the startup command if requested. */ - setenv("WAYLAND_DISPLAY", socket, true); + /* TODO: wlr_xdg_decoration_manager_v1_create() */ - wl_display_init_shm(server.wl_display); + /* FIXME: Check return values */ + wlr_export_dmabuf_manager_v1_create(server.wl_display); + wlr_screencopy_manager_v1_create(server.wl_display); + wlr_data_control_manager_v1_create(server.wl_display); + wlr_gamma_control_manager_v1_create(server.wl_display); + wlr_primary_selection_v1_device_manager_create(server.wl_display); /* Init xwayland */ server.xwayland = wlr_xwayland_create(server.wl_display, server.compositor, false); + if (!server.xwayland) { + wlr_log(WLR_ERROR, "cannot create xwayland server"); + return 1; + } server.new_xwayland_surface.notify = xwl_surface_new; wl_signal_add(&server.xwayland->events.new_surface, &server.new_xwayland_surface); - setenv("DISPLAY", server.xwayland->display_name, true); - wlr_xwayland_set_seat(server.xwayland, server.seat); - /* Creates an xcursor manager, another wlroots utility which loads up - * Xcursor themes to source cursor images from and makes sure that - * cursor images are available at all scale factors on the screen - * (necessary for - * HiDPI support). We add a cursor theme at scale factor 1 to begin - * with. */ - server.cursor_mgr = - wlr_xcursor_manager_create(XCURSOR_DEFAULT, XCURSOR_SIZE); - wlr_xcursor_manager_load(server.cursor_mgr, 1); - - struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( - server.cursor_mgr, XCURSOR_DEFAULT, 1); + server.cursor_mgr = wlr_xcursor_manager_create(XCURSOR_DEFAULT, + XCURSOR_SIZE); + if (!server.cursor_mgr) { + wlr_log(WLR_ERROR, "cannot create xwayland xcursor manager"); + return 1; + } + + if (setenv("DISPLAY", server.xwayland->display_name, true) < 0) + wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland." + " Clients may not be able to connect"); + else + wlr_log(WLR_DEBUG, "XWayland is running on display %s", + server.xwayland->display_name); + + if (wlr_xcursor_manager_load(server.cursor_mgr, 1)) + wlr_log(WLR_ERROR, "cannot load xwayland xcursor theme"); + + struct wlr_xcursor *xcursor; + xcursor = wlr_xcursor_manager_get_xcursor(server.cursor_mgr, + XCURSOR_DEFAULT, 1); if (xcursor) { struct wlr_xcursor_image *image = xcursor->images[0]; wlr_xwayland_set_cursor(server.xwayland, image->buffer, @@ -181,21 +215,41 @@ int main(int argc, char *argv[]) image->hotspot_y); } + /* Add a Unix socket to the Wayland display. */ + const char *socket = wl_display_add_socket_auto(server.wl_display); + if (!socket) { + wlr_log_errno(WLR_ERROR, "unable to open wayland socket"); + return 1; + } + + /* + * Start the backend. This will enumerate outputs and inputs, become + * the DRM master, etc + */ + if (!wlr_backend_start(server.backend)) { + wlr_log(WLR_ERROR, "unable to start the wlroots backend"); + return 1; + } + + setenv("WAYLAND_DISPLAY", socket, true); + if (setenv("WAYLAND_DISPLAY", socket, true) < 0) + wlr_log_errno(WLR_ERROR, "unable to set WAYLAND_DISPLAY"); + else + wlr_log(WLR_DEBUG, "WAYLAND_DISPLAY=%s", socket); + + wl_display_init_shm(server.wl_display); + + wlr_xwayland_set_seat(server.xwayland, server.seat); + if (startup_cmd) { if (fork() == 0) { execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL); } } - /* Run the Wayland event loop. This does not return until you exit the - * compositor. Starting the backend rigged up all of the necessary event - * loop configuration to listen to libinput events, DRM events, generate - * frame events at the refresh rate, and so on. */ - wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s", - socket); + wl_display_run(server.wl_display); - /* Once wl_display_run returns, we shut down the server. */ wlr_xwayland_destroy(server.xwayland); wlr_xcursor_manager_destroy(server.cursor_mgr); wl_display_destroy_clients(server.wl_display);