diff --git a/include/sway/commands.h b/include/sway/commands.h index 941bb619e..3f8840b03 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -144,9 +144,6 @@ sway_cmd cmd_workspace; sway_cmd cmd_ws_auto_back_and_forth; sway_cmd cmd_workspace_layout; -sway_cmd backend_cmd_add; -sway_cmd backend_cmd_del; - sway_cmd bar_cmd_activate_button; sway_cmd bar_cmd_binding_mode_indicator; sway_cmd bar_cmd_bindsym; diff --git a/include/sway/server.h b/include/sway/server.h index b1c951e3c..80d7d57da 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -7,6 +7,7 @@ #include #include #include +#include #include // TODO WLR: make Xwayland optional #include @@ -22,9 +23,14 @@ struct sway_subbackend { char *name; enum sway_subbackend_type type; struct wlr_backend *backend; - struct wl_list link; // sway_server::subbackends + + struct wl_list outputs; + struct wl_list inputs; struct wl_listener backend_destroy; + + struct wl_list link; // sway_server::subbackends + }; struct sway_server { @@ -73,5 +79,18 @@ struct sway_subbackend *sway_subbackend_create(enum sway_subbackend_type type, void sway_server_add_subbackend(struct sway_server *server, struct sway_subbackend *subbackend); void sway_server_remove_subbackend(struct sway_server *server, char *name); +struct sway_subbackend *sway_server_get_subbackend(struct sway_server *server, + char *name); + +void sway_subbackend_add_output(struct sway_server *server, + struct sway_subbackend *subbackend, char *name); +void sway_subbackend_remove_output(struct sway_server *server, + struct sway_subbackend *subbackend, char *name); + +void sway_subbackend_add_input(struct sway_server *server, + struct sway_subbackend *subbackend, enum wlr_input_device_type type, + char *name); +void sway_subbackend_remove_input(struct sway_server *server, + struct sway_subbackend *subbackend, char *name); #endif diff --git a/sway/commands/backend.c b/sway/commands/backend.c index 3024a5471..8551b4ec3 100644 --- a/sway/commands/backend.c +++ b/sway/commands/backend.c @@ -1,7 +1,73 @@ #include #include "sway/commands.h" +#include "sway/server.h" #include "log.h" +static struct cmd_results *backend_cmd_del(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "del", EXPECTED_AT_LEAST, 1))) { + return error; + } + + sway_server_remove_subbackend(&server, argv[0]); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *backend_cmd_add(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "add", EXPECTED_AT_LEAST, 1))) { + return error; + } + + const char *type_name = argv[0]; + enum sway_subbackend_type type; + if (strcasecmp(type_name, "wayland") == 0) { + type = SWAY_SUBBACKEND_WAYLAND; + } else if (strcasecmp(type_name, "x11") == 0) { + type = SWAY_SUBBACKEND_X11; + } else if (strcasecmp(type_name, "drm") == 0) { + type = SWAY_SUBBACKEND_DRM; + } else if (strcasecmp(type_name, "headless") == 0) { + type = SWAY_SUBBACKEND_HEADLESS; + } else { + error = + cmd_results_new(CMD_INVALID, + "add", "Expected 'add '"); + return error; + } + + struct sway_subbackend *subbackend = + sway_subbackend_create(type, NULL); + sway_server_add_subbackend(&server, subbackend); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *backend_cmd_add_output(int argc, char **argv, + struct sway_subbackend *backend) { + sway_log(L_DEBUG, "TODO: backend cmd add_output"); + return NULL; +} + +static struct cmd_results *backend_cmd_del_output(int argc, char **argv, + struct sway_subbackend *backend) { + sway_log(L_DEBUG, "TODO: backend cmd del_output"); + return NULL; +} + +static struct cmd_results *backend_cmd_add_input(int argc, char **argv, + struct sway_subbackend *backend) { + sway_log(L_DEBUG, "TODO: backend cmd add_input"); + return NULL; +} + +static struct cmd_results *backend_cmd_del_input(int argc, char **argv, + struct sway_subbackend *backend) { + sway_log(L_DEBUG, "TODO: backend cmd del_input"); + return NULL; +} + struct cmd_results *cmd_backend(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "backend", EXPECTED_AT_LEAST, 2))) { @@ -11,13 +77,29 @@ struct cmd_results *cmd_backend(int argc, char **argv) { int argc_new = argc-1; char **argv_new = argv+1; - struct cmd_results *res; if (strcasecmp("add", argv[0]) == 0) { - res = backend_cmd_add(argc_new, argv_new); + return backend_cmd_add(argc_new, argv_new); } else if (strcasecmp("del", argv[0]) == 0) { - res = backend_cmd_del(argc_new, argv_new); - } else { - res = cmd_results_new(CMD_INVALID, "backend [args]", "Unknown command %s", argv[1]); + return backend_cmd_del(argc_new, argv_new); } - return res; + + struct sway_subbackend *subbackend = + sway_server_get_subbackend(&server, argv[0]); + + if (subbackend == NULL) { + return cmd_results_new(CMD_INVALID, "backend [args]", + "Cannot find backend: %s", argv[0]); + } + + if (strcasecmp("add-output", argv[1]) == 0) { + return backend_cmd_add_output(argc_new, argv_new, subbackend); + } else if (strcasecmp("del-output", argv[1]) == 0) { + return backend_cmd_del_output(argc_new, argv_new, subbackend); + } else if (strcasecmp("add-input", argv[1]) == 0) { + return backend_cmd_add_input(argc_new, argv_new, subbackend); + } else if (strcasecmp("del-input", argv[1]) == 0) { + return backend_cmd_del_input(argc_new, argv_new, subbackend); + } + + return cmd_results_new(CMD_INVALID, "backend [args]", "Unknown command %s", argv[1]); } diff --git a/sway/commands/backend/add.c b/sway/commands/backend/add.c deleted file mode 100644 index 14d387d18..000000000 --- a/sway/commands/backend/add.c +++ /dev/null @@ -1,38 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/server.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *backend_cmd_add(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "add", EXPECTED_AT_LEAST, 1))) { - return error; - } - - const char *type_name = argv[0]; - enum sway_subbackend_type type; - if (strcasecmp(type_name, "wayland") == 0) { - type = SWAY_SUBBACKEND_WAYLAND; - } else if (strcasecmp(type_name, "x11") == 0) { - type = SWAY_SUBBACKEND_X11; - } else if (strcasecmp(type_name, "drm") == 0) { - type = SWAY_SUBBACKEND_DRM; - } else if (strcasecmp(type_name, "headless") == 0) { - type = SWAY_SUBBACKEND_HEADLESS; - } else { - error = - cmd_results_new(CMD_INVALID, - "add", "Expected 'add '"); - return error; - } - - struct sway_subbackend *subbackend = - sway_subbackend_create(type, NULL); - sway_server_add_subbackend(&server, subbackend); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/backend/del.c b/sway/commands/backend/del.c deleted file mode 100644 index 206b14aea..000000000 --- a/sway/commands/backend/del.c +++ /dev/null @@ -1,19 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include "sway/commands.h" -#include "sway/config.h" -#include "sway/server.h" -#include "log.h" -#include "stringop.h" - -struct cmd_results *backend_cmd_del(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "del", EXPECTED_AT_LEAST, 1))) { - return error; - } - - sway_server_remove_subbackend(&server, argv[0]); - - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/meson.build b/sway/meson.build index 558f8ec53..344fdb4f7 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -7,8 +7,6 @@ sway_sources = files( 'input/cursor.c', 'input/keyboard.c', 'commands/backend.c', - 'commands/backend/add.c', - 'commands/backend/del.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', diff --git a/sway/server.c b/sway/server.c index eb7202349..21fb13f4c 100644 --- a/sway/server.c +++ b/sway/server.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include // TODO WLR: make Xwayland optional #include #include "sway/server.h" @@ -95,6 +97,18 @@ static void sway_subbackend_destroy(struct sway_subbackend *subbackend) { free(subbackend); } +struct sway_subbackend *sway_server_get_subbackend(struct sway_server *server, + char *name) { + struct sway_subbackend *subbackend = NULL; + wl_list_for_each(subbackend, &server->subbackends, link) { + if (strcasecmp(subbackend->name, name) == 0) { + return subbackend; + } + } + + return NULL; +} + struct sway_subbackend *sway_subbackend_create(enum sway_subbackend_type type, char *name) { struct sway_subbackend *subbackend = @@ -113,6 +127,8 @@ struct sway_subbackend *sway_subbackend_create(enum sway_subbackend_type type, } subbackend->type = type; + wl_list_init(&subbackend->outputs); + wl_list_init(&subbackend->inputs); wl_list_init(&subbackend->link); return subbackend; @@ -159,6 +175,13 @@ static struct wlr_backend *drm_backend_create(struct sway_server *server) { void sway_server_add_subbackend(struct sway_server *server, struct sway_subbackend *subbackend) { + if (sway_server_get_subbackend(server, subbackend->name)) { + sway_log(L_ERROR, "cannot add subbackend '%s': already exists", + subbackend->name); + sway_subbackend_destroy(subbackend); + return; + } + struct wlr_backend *backend = NULL; switch (subbackend->type) { @@ -193,12 +216,8 @@ void sway_server_add_subbackend(struct sway_server *server, } void sway_server_remove_subbackend(struct sway_server *server, char *name) { - struct sway_subbackend *subbackend = NULL; - wl_list_for_each(subbackend, &server->subbackends, link) { - if (strcasecmp(subbackend->name, name) == 0) { - break; - } - } + struct sway_subbackend *subbackend = + sway_server_get_subbackend(server, name); if (!subbackend) { sway_log(L_DEBUG, "could not find subbackend named '%s'", name); @@ -207,3 +226,136 @@ void sway_server_remove_subbackend(struct sway_server *server, char *name) { wlr_backend_destroy(subbackend->backend); } + +struct subbackend_output { + struct sway_subbackend *backend; + struct wlr_output *wlr_output; + + struct wl_listener output_destroy; + + struct wl_list link; // sway_subbackend::outputs +}; + +static void subbackend_output_destroy(struct subbackend_output *output) { + wl_list_remove(&output->link); + wl_list_remove(&output->output_destroy.link); + free(output); +} + +static void handle_subbackend_output_destroy(struct wl_listener *listener, + void *data) { + struct subbackend_output *output = + wl_container_of(listener, output, output_destroy); + subbackend_output_destroy(output); +} + +void sway_subbackend_add_output(struct sway_server *server, + struct sway_subbackend *subbackend, char *name) { + struct wlr_output *wlr_output = NULL; + + switch(subbackend->type) { + case SWAY_SUBBACKEND_WAYLAND: + sway_log(L_DEBUG, "TODO: create wayland subbackend output"); + break; + case SWAY_SUBBACKEND_X11: + sway_log(L_DEBUG, "TODO: create x11 subbackend output"); + break; + case SWAY_SUBBACKEND_DRM: + sway_log(L_DEBUG, "creating DRM subbackend outputs is not supported"); + break; + case SWAY_SUBBACKEND_HEADLESS: + wlr_output = + wlr_headless_add_output(subbackend->backend, 500, 500, name); + break; + } + + if (wlr_output == NULL) { + sway_log(L_ERROR, "could not create subbackend output '%s'", name); + return; + } + + struct subbackend_output *output = + calloc(1, sizeof(struct subbackend_output)); + if (output == NULL) { + sway_log(L_ERROR, "could not allocate subbackend output"); + return; + } + + output->wlr_output = wlr_output; + + wl_signal_add(&wlr_output->events.destroy, &output->output_destroy); + output->output_destroy.notify = handle_subbackend_output_destroy; + + wl_list_insert(&subbackend->outputs, &output->link); +} + +void sway_subbackend_remove_output(struct sway_server *server, + struct sway_subbackend *subbackend, char *name) { + struct subbackend_output *output = NULL, *tmp = NULL; + wl_list_for_each_safe(output, tmp, &subbackend->outputs, link) { + if (strcasecmp(output->wlr_output->name, name) == 0) { + wlr_output_destroy(output->wlr_output); + } + } +} + +struct subbackend_input { + struct sway_subbackend *backend; + struct wlr_input_device *device; + + struct wl_listener input_destroy; + + struct wl_list link; // sway_subbackend::inputs +}; + +static void subbackend_input_destroy(struct subbackend_input *input) { + wl_list_remove(&input->link); + wl_list_remove(&input->input_destroy.link); + free(input); +} + +static void handle_subbackend_device_destroy(struct wl_listener *listener, + void *data) { + struct subbackend_input *input = + wl_container_of(listener, input, input_destroy); + subbackend_input_destroy(input); +} + +void sway_subbackend_add_input(struct sway_server *server, + struct sway_subbackend *subbackend, enum wlr_input_device_type type, + char *name) { + if (subbackend->type != SWAY_SUBBACKEND_HEADLESS) { + sway_log(L_DEBUG, "adding inputs is only supported for the headless backend"); + return; + } + + struct wlr_input_device *device = + wlr_headless_add_input_device(subbackend->backend, type, name); + if (device == NULL) { + return; + } + + struct subbackend_input *input = + calloc(1, sizeof(struct subbackend_input)); + if (input == NULL) { + sway_log(L_ERROR, "could not allocate subbackend input device"); + return; + } + + input->device = device; + + wl_signal_add(&device->events.destroy, &input->input_destroy); + input->input_destroy.notify = handle_subbackend_device_destroy; + + wl_list_insert(&subbackend->inputs, &input->link); +} + +void sway_subbackend_remove_input(struct sway_server *server, + struct sway_subbackend *subbackend, char *name) { + struct subbackend_input *input = NULL, *tmp = NULL; + wl_list_for_each_safe(input, tmp, &subbackend->inputs, link) { + if (strcasecmp(input->device->name, name) == 0) { + wlr_input_device_destroy(input->device); + } + } +}