structtinywl_server server; /* 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);
/* 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); 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);
/* This creates 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. 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, server.renderer); wlr_data_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 = 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(); wlr_scene_attach_output_layout(server.scene, server.output_layout);
/* Add a Unix socket to the Wayland display. */ constchar *socket = wl_display_add_socket_auto(server.wl_display); if (!socket) { wlr_backend_destroy(server.backend); return1; }
/* 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); return1; }
/* Set the WAYLAND_DISPLAY environment variable to our socket and run the * startup command if requested. */ setenv("WAYLAND_DISPLAY", socket, true); /* 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. */ wl_display_destroy_clients(server.wl_display); wl_display_destroy(server.wl_display); return0; }
staticvoidserver_new_output(struct wl_listener *listener, void *data){ /* This event is raised by the backend when a new output (aka a display or * monitor) becomes available. */ structtinywl_server *server = wl_container_of(listener, server, new_output); structwlr_output *wlr_output = data;
/* Configures the output created by the backend to use our allocator * and our renderer. Must be done once, before commiting the output */ wlr_output_init_render(wlr_output, server->allocator, server->renderer);
/* Some backends don't have modes. DRM+KMS does, and we need to set a mode * before we can use the output. The mode is a tuple of (width, height, * refresh rate), and each monitor supports only a specific set of modes. We * just pick the monitor's preferred mode, a more sophisticated compositor * would let the user configure it. */ if (!wl_list_empty(&wlr_output->modes)) { structwlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); wlr_output_set_mode(wlr_output, mode); wlr_output_enable(wlr_output, true); if (!wlr_output_commit(wlr_output)) { return; } }
/* Allocates and configures our state for this output */ structtinywl_output *output = calloc(1, sizeof(struct tinywl_output)); output->wlr_output = wlr_output; output->server = server; /* Sets up a listener for the frame notify event. */ output->frame.notify = output_frame; wl_signal_add(&wlr_output->events.frame, &output->frame); wl_list_insert(&server->outputs, &output->link);
/* Adds this to the output layout. The add_auto function arranges outputs * from left-to-right in the order they appear. A more sophisticated * compositor would let the user configure the arrangement of outputs in the * layout. * * The output layout utility automatically adds a wl_output global to the * display, which Wayland clients can see to find out information about the * output (such as DPI, scale factor, manufacturer, etc). */ wlr_output_layout_add_auto(server->output_layout, wlr_output); }
每次刷新时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
staticvoidoutput_frame(struct wl_listener *listener, void *data){ /* This function is called every time an output is ready to display a frame, * generally at the output's refresh rate (e.g. 60Hz). */ printf("output frame\n"); structtinywl_output *output = wl_container_of(listener, output, frame); structwlr_scene *scene = output->server->scene;