191 lines
7.4 KiB
C
191 lines
7.4 KiB
C
#define _POSIX_C_SOURCE 200112L
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
#include <wlr/util/log.h>
|
|
#include "output.h"
|
|
#include "xdg.h"
|
|
#include "cursor.h"
|
|
#include "seat.h"
|
|
#include "layer.h"
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
wlr_log_init(WLR_INFO, NULL);
|
|
char *startup_cmd = NULL;
|
|
|
|
int c;
|
|
while ((c = getopt(argc, argv, "s:h")) != -1)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 's':
|
|
startup_cmd = optarg;
|
|
break;
|
|
default:
|
|
printf("Usage: %s [-s startup command]\n", argv[0]);
|
|
return 0;
|
|
}
|
|
}
|
|
if (optind < argc)
|
|
{
|
|
printf("Usage: %s [-s startup command]\n", argv[0]);
|
|
return 0;
|
|
}
|
|
|
|
struct diyac_server server = {0};
|
|
/* 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. */
|
|
server.backend = wlr_backend_autocreate(server.wl_display, NULL);
|
|
if (server.backend == NULL)
|
|
{
|
|
wlr_log(WLR_ERROR, "failed to create wlr_backend");
|
|
return 1;
|
|
}
|
|
|
|
/* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user
|
|
* can also specify a renderer using the WLR_RENDERER env var.
|
|
* The renderer is responsible for defining the various pixel formats it
|
|
* supports for shared memory, this configures that for clients. */
|
|
server.renderer = wlr_renderer_autocreate(server.backend);
|
|
if (server.renderer == NULL)
|
|
{
|
|
wlr_log(WLR_ERROR, "failed to create wlr_renderer");
|
|
return 1;
|
|
}
|
|
|
|
wlr_renderer_init_wl_display(server.renderer, server.wl_display);
|
|
|
|
/* Autocreates an allocator for us.
|
|
* The allocator is the bridge between the renderer and the backend. It
|
|
* handles the buffer creation, allowing wlroots to render onto the
|
|
* screen */
|
|
server.allocator = wlr_allocator_autocreate(server.backend,
|
|
server.renderer);
|
|
if (server.allocator == NULL)
|
|
{
|
|
wlr_log(WLR_ERROR, "failed to create wlr_allocator");
|
|
return 1;
|
|
}
|
|
|
|
/* This creates some hands-off wlroots interfaces. The compositor is
|
|
* necessary for clients to allocate surfaces, the subcompositor allows to
|
|
* assign the role of subsurfaces to 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. Note that
|
|
* the clients cannot set the selection directly without compositor approval,
|
|
* see the handling of the request_set_selection event below.*/
|
|
wlr_compositor_create(server.wl_display, 5, server.renderer);
|
|
wlr_subcompositor_create(server.wl_display);
|
|
wlr_data_device_manager_create(server.wl_display);
|
|
/*
|
|
* Empirically, primary selection doesn't work with Gtk apps unless the
|
|
* device manager is one of the earliest globals to be advertised. All
|
|
* credit to Wayfire for discovering this, though their symptoms
|
|
* (crash) are not the same as ours (silently does nothing). When adding
|
|
* more globals above this line it would be as well to check that
|
|
* middle-button paste still works with any Gtk app of your choice
|
|
*
|
|
* https://wayfire.org/2020/08/04/Wayfire-0-5.html
|
|
*/
|
|
wlr_primary_selection_v1_device_manager_create(server.wl_display);
|
|
|
|
/* 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();
|
|
|
|
/* Configure a listener to be notified when new outputs are available on the
|
|
* backend. */
|
|
wl_list_init(&server.outputs);
|
|
server.new_output.notify = diyac_server_new_output;
|
|
wl_signal_add(&server.backend->events.new_output, &server.new_output);
|
|
|
|
/* Create a scene graph. This is a wlroots abstraction that handles all
|
|
* rendering and damage tracking. All the compositor author needs to do
|
|
* is add things that should be rendered to the scene graph at the proper
|
|
* positions and then call wlr_scene_output_commit() to render a frame if
|
|
* necessary.
|
|
*/
|
|
server.scene = wlr_scene_create();
|
|
server.scene_layout = wlr_scene_attach_output_layout(server.scene, server.output_layout);
|
|
wlr_fractional_scale_manager_v1_create(server.wl_display,1);
|
|
/* Set up xdg-shell version 6 The xdg-shell is a Wayland protocol which is
|
|
* used for application windows. For more detail on shells, refer to
|
|
* https://drewdevault.com/2018/07/29/Wayland-shells.html.
|
|
*/
|
|
wl_list_init(&server.views);
|
|
server.view_tree = wlr_scene_tree_create(&server.scene->tree);
|
|
server.xdg_popup_tree = wlr_scene_tree_create(&server.scene->tree);
|
|
|
|
server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 6);
|
|
server.new_xdg_surface.notify = diyac_new_xdg_surface;
|
|
wl_signal_add(&server.xdg_shell->events.new_surface,
|
|
&server.new_xdg_surface);
|
|
|
|
server.layer_shell = wlr_layer_shell_v1_create(server.wl_display, 4);
|
|
server.new_layer_surface.notify = diyac_new_layer_surface;
|
|
wl_signal_add(&server.layer_shell->events.new_surface,
|
|
&server.new_layer_surface);
|
|
|
|
diyac_init_cursor_manager(&server);
|
|
|
|
/*
|
|
* 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.seat.keyboards);
|
|
diyac_init_seat(&server);
|
|
|
|
/* 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);
|
|
return 1;
|
|
}
|
|
|
|
/* Set the WAYLAND_DISPLAY environment variable to our socket and run the
|
|
* startup command if requested. */
|
|
setenv("WAYLAND_DISPLAY", socket, true);
|
|
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 destroy all clients then shut down the
|
|
* server. */
|
|
wl_display_destroy_clients(server.wl_display);
|
|
wlr_scene_node_destroy(&server.scene->tree.node);
|
|
wlr_xcursor_manager_destroy(server.seat.cursor_mgr);
|
|
wlr_output_layout_destroy(server.output_layout);
|
|
wl_display_destroy(server.wl_display);
|
|
return 0;
|
|
}
|