mirror of
https://github.com/swaywm/sway.git
synced 2026-04-16 08:21:30 -04:00
Don't ignore initialisation errors
server_init ignores all errors. In practice, theses result in a
segfault, potentially much later and losing any unsaved work.
Properly handle initialisation errors and bail immediately.
(cherry picked from commit 1606311553)
This commit is contained in:
parent
faedde4e77
commit
0df0173102
5 changed files with 222 additions and 23 deletions
|
|
@ -176,7 +176,7 @@ void handle_new_output(struct wl_listener *listener, void *data);
|
|||
|
||||
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
|
||||
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
|
||||
void sway_session_lock_init(void);
|
||||
bool sway_session_lock_init(void);
|
||||
void sway_session_lock_add_output(struct sway_session_lock *lock,
|
||||
struct sway_output *output);
|
||||
bool sway_session_lock_has_surface(struct sway_session_lock *lock,
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ void workspace_squash(struct sway_workspace *workspace);
|
|||
void workspace_move_to_output(struct sway_workspace *workspace,
|
||||
struct sway_output *output);
|
||||
|
||||
void sway_ext_workspace_init(void);
|
||||
bool sway_ext_workspace_init(void);
|
||||
void sway_ext_workspace_output_enable(struct sway_output *output);
|
||||
void sway_ext_workspace_output_disable(struct sway_output *output);
|
||||
|
||||
|
|
|
|||
|
|
@ -344,8 +344,12 @@ bool sway_session_lock_has_surface(struct sway_session_lock *lock,
|
|||
return false;
|
||||
}
|
||||
|
||||
void sway_session_lock_init(void) {
|
||||
bool sway_session_lock_init(void) {
|
||||
server.session_lock.manager = wlr_session_lock_manager_v1_create(server.wl_display);
|
||||
if (!server.session_lock.manager) {
|
||||
sway_log(SWAY_ERROR, "Failed to create session lock manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
server.session_lock.new_lock.notify = handle_session_lock;
|
||||
server.session_lock.manager_destroy.notify = handle_session_lock_destroy;
|
||||
|
|
@ -353,4 +357,5 @@ void sway_session_lock_init(void) {
|
|||
&server.session_lock.new_lock);
|
||||
wl_signal_add(&server.session_lock.manager->events.destroy,
|
||||
&server.session_lock.manager_destroy);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
229
sway/server.c
229
sway/server.c
|
|
@ -244,13 +244,25 @@ static void handle_new_foreign_toplevel_capture_request(struct wl_listener *list
|
|||
bool server_init(struct sway_server *server) {
|
||||
sway_log(SWAY_DEBUG, "Initializing Wayland server");
|
||||
server->wl_display = wl_display_create();
|
||||
if (!server->wl_display) {
|
||||
sway_log(SWAY_ERROR, "Failed to create wl_display");
|
||||
return false;
|
||||
}
|
||||
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
|
||||
|
||||
wl_display_set_global_filter(server->wl_display, filter_global, NULL);
|
||||
wl_display_set_default_max_buffer_size(server->wl_display, 1024 * 1024);
|
||||
|
||||
wlr_fixes_create(server->wl_display, 1);
|
||||
if (!wlr_fixes_create(server->wl_display, 1)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create wp_fixes global");
|
||||
return false;
|
||||
}
|
||||
root = root_create(server->wl_display);
|
||||
if (!root) {
|
||||
sway_log(SWAY_ERROR, "Failed to create root");
|
||||
wl_display_destroy(server->wl_display);
|
||||
return false;
|
||||
}
|
||||
|
||||
server->backend = wlr_backend_autocreate(server->wl_event_loop, &server->session);
|
||||
if (!server->backend) {
|
||||
|
|
@ -271,15 +283,23 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
wlr_renderer_init_wl_shm(server->renderer, server->wl_display);
|
||||
|
||||
if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) {
|
||||
if (wlr_renderer_get_drm_fd(server->renderer) >= 0 &&
|
||||
wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) {
|
||||
server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer(
|
||||
server->wl_display, 5, server->renderer);
|
||||
if (!server->linux_dmabuf_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create linux-dmabuf v1");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (wlr_renderer_get_drm_fd(server->renderer) >= 0 &&
|
||||
server->renderer->features.timeline &&
|
||||
server->backend->features.timeline) {
|
||||
wlr_linux_drm_syncobj_manager_v1_create(server->wl_display, 1,
|
||||
wlr_renderer_get_drm_fd(server->renderer));
|
||||
if (!wlr_linux_drm_syncobj_manager_v1_create(server->wl_display, 1,
|
||||
wlr_renderer_get_drm_fd(server->renderer))) {
|
||||
sway_log(SWAY_ERROR, "Failed to create linux-drm-syncobj v1");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
server->allocator = wlr_allocator_autocreate(server->backend,
|
||||
|
|
@ -291,14 +311,29 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
server->compositor = wlr_compositor_create(server->wl_display, 6,
|
||||
server->renderer);
|
||||
if (!server->compositor) {
|
||||
sway_log(SWAY_ERROR, "Failed to create compositor");
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_subcompositor_create(server->wl_display);
|
||||
if (!wlr_subcompositor_create(server->wl_display)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create subcompositor");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->data_device_manager =
|
||||
wlr_data_device_manager_create(server->wl_display);
|
||||
if (!server->data_device_manager) {
|
||||
sway_log(SWAY_ERROR, "Failed to create data device manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->gamma_control_manager_v1 =
|
||||
wlr_gamma_control_manager_v1_create(server->wl_display);
|
||||
if (!server->gamma_control_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create gamma control manager");
|
||||
return false;
|
||||
}
|
||||
wlr_scene_set_gamma_control_manager_v1(root->root_scene,
|
||||
server->gamma_control_manager_v1);
|
||||
|
||||
|
|
@ -307,26 +342,53 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
server->xdg_output_manager_v1 =
|
||||
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
|
||||
if (!server->xdg_output_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG output manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display);
|
||||
sway_idle_inhibit_manager_v1_init();
|
||||
if (!server->idle_notifier_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create idle notifier");
|
||||
return false;
|
||||
}
|
||||
if (!sway_idle_inhibit_manager_v1_init()) {
|
||||
sway_log(SWAY_ERROR, "Failed to init idle inhibit manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->layer_shell = wlr_layer_shell_v1_create(server->wl_display,
|
||||
SWAY_LAYER_SHELL_VERSION);
|
||||
if (!server->layer_shell) {
|
||||
sway_log(SWAY_ERROR, "Failed to create layer shell");
|
||||
return false;
|
||||
}
|
||||
wl_signal_add(&server->layer_shell->events.new_surface,
|
||||
&server->layer_shell_surface);
|
||||
server->layer_shell_surface.notify = handle_layer_shell_surface;
|
||||
|
||||
server->xdg_shell = wlr_xdg_shell_create(server->wl_display,
|
||||
SWAY_XDG_SHELL_VERSION);
|
||||
if (!server->xdg_shell) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG shell");
|
||||
return false;
|
||||
}
|
||||
wl_signal_add(&server->xdg_shell->events.new_toplevel,
|
||||
&server->xdg_shell_toplevel);
|
||||
server->xdg_shell_toplevel.notify = handle_xdg_shell_toplevel;
|
||||
|
||||
server->tablet_v2 = wlr_tablet_v2_create(server->wl_display);
|
||||
if (!server->tablet_v2) {
|
||||
sway_log(SWAY_ERROR, "Failed to create tablet manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->server_decoration_manager =
|
||||
wlr_server_decoration_manager_create(server->wl_display);
|
||||
if (!server->server_decoration_manager) {
|
||||
sway_log(SWAY_ERROR, "Failed to create server decoration manager");
|
||||
return false;
|
||||
}
|
||||
wlr_server_decoration_manager_set_default_mode(
|
||||
server->server_decoration_manager,
|
||||
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
||||
|
|
@ -337,6 +399,10 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
server->xdg_decoration_manager =
|
||||
wlr_xdg_decoration_manager_v1_create(server->wl_display);
|
||||
if (!server->xdg_decoration_manager) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG decoration manager");
|
||||
return false;
|
||||
}
|
||||
wl_signal_add(
|
||||
&server->xdg_decoration_manager->events.new_toplevel_decoration,
|
||||
&server->xdg_decoration);
|
||||
|
|
@ -345,18 +411,36 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
server->relative_pointer_manager =
|
||||
wlr_relative_pointer_manager_v1_create(server->wl_display);
|
||||
if (!server->relative_pointer_manager) {
|
||||
sway_log(SWAY_ERROR, "Failed to create relative pointer manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->pointer_constraints =
|
||||
wlr_pointer_constraints_v1_create(server->wl_display);
|
||||
if (!server->pointer_constraints) {
|
||||
sway_log(SWAY_ERROR, "Failed to create pointer constraints");
|
||||
return false;
|
||||
}
|
||||
server->pointer_constraint.notify = handle_pointer_constraint;
|
||||
wl_signal_add(&server->pointer_constraints->events.new_constraint,
|
||||
&server->pointer_constraint);
|
||||
|
||||
wlr_presentation_create(server->wl_display, server->backend, SWAY_PRESENTATION_VERSION);
|
||||
wlr_alpha_modifier_v1_create(server->wl_display);
|
||||
if (!wlr_presentation_create(server->wl_display, server->backend, SWAY_PRESENTATION_VERSION)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create presentation");
|
||||
return false;
|
||||
}
|
||||
if (!wlr_alpha_modifier_v1_create(server->wl_display)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create alpha modifier");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->output_manager_v1 =
|
||||
wlr_output_manager_v1_create(server->wl_display);
|
||||
if (!server->output_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create output manager");
|
||||
return false;
|
||||
}
|
||||
server->output_manager_apply.notify = handle_output_manager_apply;
|
||||
wl_signal_add(&server->output_manager_v1->events.apply,
|
||||
&server->output_manager_apply);
|
||||
|
|
@ -366,19 +450,43 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
server->output_power_manager_v1 =
|
||||
wlr_output_power_manager_v1_create(server->wl_display);
|
||||
if (!server->output_power_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create output power manager");
|
||||
return false;
|
||||
}
|
||||
server->output_power_manager_set_mode.notify =
|
||||
handle_output_power_manager_set_mode;
|
||||
wl_signal_add(&server->output_power_manager_v1->events.set_mode,
|
||||
&server->output_power_manager_set_mode);
|
||||
server->input_method = wlr_input_method_manager_v2_create(server->wl_display);
|
||||
if (!server->input_method) {
|
||||
sway_log(SWAY_ERROR, "Failed to create input method manager");
|
||||
return false;
|
||||
}
|
||||
server->text_input = wlr_text_input_manager_v3_create(server->wl_display);
|
||||
if (!server->text_input) {
|
||||
sway_log(SWAY_ERROR, "Failed to create text input manager");
|
||||
return false;
|
||||
}
|
||||
server->foreign_toplevel_list =
|
||||
wlr_ext_foreign_toplevel_list_v1_create(server->wl_display, SWAY_FOREIGN_TOPLEVEL_LIST_VERSION);
|
||||
if (!server->foreign_toplevel_list) {
|
||||
sway_log(SWAY_ERROR, "Failed to create foreign toplevel list");
|
||||
return false;
|
||||
}
|
||||
server->foreign_toplevel_manager =
|
||||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||
if (!server->foreign_toplevel_manager) {
|
||||
sway_log(SWAY_ERROR, "Failed to create foreign toplevel manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
sway_session_lock_init();
|
||||
sway_ext_workspace_init();
|
||||
if (!sway_session_lock_init()) {
|
||||
return false;
|
||||
}
|
||||
if (!sway_ext_workspace_init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
server->drm_lease_manager=
|
||||
|
|
@ -394,26 +502,74 @@ bool server_init(struct sway_server *server) {
|
|||
#endif
|
||||
|
||||
server->export_dmabuf_manager_v1 = wlr_export_dmabuf_manager_v1_create(server->wl_display);
|
||||
if (!server->export_dmabuf_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create export dmabuf manager");
|
||||
return false;
|
||||
}
|
||||
server->screencopy_manager_v1 = wlr_screencopy_manager_v1_create(server->wl_display);
|
||||
if (!server->screencopy_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create screencopy manager");
|
||||
return false;
|
||||
}
|
||||
server->ext_image_copy_capture_manager_v1 = wlr_ext_image_copy_capture_manager_v1_create(server->wl_display, 1);
|
||||
wlr_ext_output_image_capture_source_manager_v1_create(server->wl_display, 1);
|
||||
if (!server->ext_image_copy_capture_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create ext image copy capture manager");
|
||||
return false;
|
||||
}
|
||||
if (!wlr_ext_output_image_capture_source_manager_v1_create(server->wl_display, 1)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create ext output image capture source manager");
|
||||
return false;
|
||||
}
|
||||
server->wlr_data_control_manager_v1 = wlr_data_control_manager_v1_create(server->wl_display);
|
||||
if (!server->wlr_data_control_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create data control manager");
|
||||
return false;
|
||||
}
|
||||
server->ext_data_control_manager_v1 = wlr_ext_data_control_manager_v1_create(server->wl_display, 1);
|
||||
if (!server->ext_data_control_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create ext data control manager");
|
||||
return false;
|
||||
}
|
||||
server->security_context_manager_v1 = wlr_security_context_manager_v1_create(server->wl_display);
|
||||
wlr_viewporter_create(server->wl_display);
|
||||
wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
|
||||
if (!server->security_context_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create security context manager");
|
||||
return false;
|
||||
}
|
||||
if (!wlr_viewporter_create(server->wl_display)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create viewporter");
|
||||
return false;
|
||||
}
|
||||
if (!wlr_single_pixel_buffer_manager_v1_create(server->wl_display)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create single pixel buffer manager");
|
||||
return false;
|
||||
}
|
||||
server->content_type_manager_v1 =
|
||||
wlr_content_type_manager_v1_create(server->wl_display, 1);
|
||||
wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
|
||||
if (!server->content_type_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create content type manager");
|
||||
return false;
|
||||
}
|
||||
if (!wlr_fractional_scale_manager_v1_create(server->wl_display, 1)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create fractional scale manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->ext_foreign_toplevel_image_capture_source_manager_v1 =
|
||||
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(server->wl_display, 1);
|
||||
if (!server->ext_foreign_toplevel_image_capture_source_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create ext foreign toplevel image capture source manager");
|
||||
return false;
|
||||
}
|
||||
server->new_foreign_toplevel_capture_request.notify = handle_new_foreign_toplevel_capture_request;
|
||||
wl_signal_add(&server->ext_foreign_toplevel_image_capture_source_manager_v1->events.new_request,
|
||||
&server->new_foreign_toplevel_capture_request);
|
||||
|
||||
server->tearing_control_v1 =
|
||||
wlr_tearing_control_manager_v1_create(server->wl_display, 1);
|
||||
if (!server->tearing_control_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create tearing control manager");
|
||||
return false;
|
||||
}
|
||||
server->tearing_control_new_object.notify = handle_new_tearing_hint;
|
||||
wl_signal_add(&server->tearing_control_v1->events.new_object,
|
||||
&server->tearing_control_new_object);
|
||||
|
|
@ -421,10 +577,24 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
struct wlr_xdg_foreign_registry *foreign_registry =
|
||||
wlr_xdg_foreign_registry_create(server->wl_display);
|
||||
wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
|
||||
wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry);
|
||||
if (!foreign_registry) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG foreign registry");
|
||||
return false;
|
||||
}
|
||||
if (!wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG foreign v1");
|
||||
return false;
|
||||
}
|
||||
if (!wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG foreign v2");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->xdg_activation_v1 = wlr_xdg_activation_v1_create(server->wl_display);
|
||||
if (!server->xdg_activation_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG activation");
|
||||
return false;
|
||||
}
|
||||
server->xdg_activation_v1_request_activate.notify =
|
||||
xdg_activation_v1_handle_request_activate;
|
||||
wl_signal_add(&server->xdg_activation_v1->events.request_activate,
|
||||
|
|
@ -436,6 +606,10 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
struct wlr_xdg_toplevel_tag_manager_v1 *xdg_toplevel_tag_manager_v1 =
|
||||
wlr_xdg_toplevel_tag_manager_v1_create(server->wl_display, 1);
|
||||
if (!xdg_toplevel_tag_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create XDG toplevel tag manager");
|
||||
return false;
|
||||
}
|
||||
server->xdg_toplevel_tag_manager_v1_set_tag.notify =
|
||||
xdg_toplevel_tag_manager_v1_handle_set_tag;
|
||||
wl_signal_add(&xdg_toplevel_tag_manager_v1->events.set_tag,
|
||||
|
|
@ -443,6 +617,10 @@ bool server_init(struct sway_server *server) {
|
|||
|
||||
struct wlr_cursor_shape_manager_v1 *cursor_shape_manager =
|
||||
wlr_cursor_shape_manager_v1_create(server->wl_display, 2);
|
||||
if (!cursor_shape_manager) {
|
||||
sway_log(SWAY_ERROR, "Failed to create cursor shape manager");
|
||||
return false;
|
||||
}
|
||||
server->request_set_cursor_shape.notify = handle_request_set_cursor_shape;
|
||||
wl_signal_add(&cursor_shape_manager->events.request_set_shape, &server->request_set_cursor_shape);
|
||||
|
||||
|
|
@ -471,11 +649,18 @@ bool server_init(struct sway_server *server) {
|
|||
});
|
||||
free(transfer_functions);
|
||||
free(primaries);
|
||||
if (!cm) {
|
||||
sway_log(SWAY_ERROR, "Failed to create color manager");
|
||||
return false;
|
||||
}
|
||||
wlr_scene_set_color_manager_v1(root->root_scene, cm);
|
||||
}
|
||||
|
||||
wlr_color_representation_manager_v1_create_with_renderer(
|
||||
server->wl_display, 1, server->renderer);
|
||||
if (!wlr_color_representation_manager_v1_create_with_renderer(
|
||||
server->wl_display, 1, server->renderer)) {
|
||||
sway_log(SWAY_ERROR, "Failed to create color representation manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
wl_list_init(&server->pending_launcher_ctxs);
|
||||
|
||||
|
|
@ -515,8 +700,16 @@ bool server_init(struct sway_server *server) {
|
|||
}
|
||||
|
||||
server->dirty_nodes = create_list();
|
||||
if (!server->dirty_nodes) {
|
||||
sway_log(SWAY_ERROR, "Failed to create dirty nodes list");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->input = input_manager_create(server);
|
||||
if (!server->input) {
|
||||
sway_log(SWAY_ERROR, "Failed to create input manager");
|
||||
return false;
|
||||
}
|
||||
input_manager_get_default_seat(); // create seat0
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -97,17 +97,18 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
|
||||
// Initialize ext-workspace. Must be called once at startup.
|
||||
void sway_ext_workspace_init(void) {
|
||||
bool sway_ext_workspace_init(void) {
|
||||
server.workspace_manager_v1 =
|
||||
wlr_ext_workspace_manager_v1_create(server.wl_display, 1);
|
||||
if (!server.workspace_manager_v1) {
|
||||
sway_log(SWAY_ERROR, "Failed to create ext_workspace_manager_v1");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
server.workspace_manager_v1_commit.notify = handle_commit;
|
||||
wl_signal_add(&server.workspace_manager_v1->events.commit,
|
||||
&server.workspace_manager_v1_commit);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Must be called whenever an output is enabled.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue