From 7c448b408126aef0561be0761871f968921d7db0 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 22 Oct 2017 10:37:30 -0400 Subject: [PATCH] Fire up the wlroots backend and run the event loop --- include/sway/extensions.h | 56 ------ include/sway/server.h | 31 +++ sway/CMakeLists.txt | 3 +- sway/commands.c | 2 + sway/extensions.c | 407 -------------------------------------- sway/focus.c | 3 +- sway/ipc-server.c | 389 +++--------------------------------- sway/layout.c | 5 +- sway/main.c | 113 +++++------ sway/server.c | 54 +++++ sway/workspace.c | 1 - 11 files changed, 160 insertions(+), 904 deletions(-) delete mode 100644 include/sway/extensions.h create mode 100644 include/sway/server.h delete mode 100644 sway/extensions.c create mode 100644 sway/server.c diff --git a/include/sway/extensions.h b/include/sway/extensions.h deleted file mode 100644 index 5212eb3a..00000000 --- a/include/sway/extensions.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _SWAY_EXTENSIONS_H -#define _SWAY_EXTENSIONS_H - -#include -#include -#include "wayland-desktop-shell-server-protocol.h" -#include "list.h" - -struct background_config { - wlc_handle output; - wlc_resource surface; - // we need the wl_resource of the surface in the destructor - struct wl_resource *wl_surface_res; - struct wl_client *client; - wlc_handle handle; -}; - -struct panel_config { - // wayland resource used in callbacks, is used to track this panel - struct wl_resource *wl_resource; - wlc_handle output; - wlc_resource surface; - // we need the wl_resource of the surface in the destructor - struct wl_resource *wl_surface_res; - enum desktop_shell_panel_position panel_position; - // used to determine if client is a panel - struct wl_client *client; - // wlc handle for this panel's surface, not set until panel is created - wlc_handle handle; -}; - -struct desktop_shell_state { - list_t *backgrounds; - list_t *panels; - list_t *lock_surfaces; - bool is_locked; -}; - -struct swaylock_state { - bool active; - wlc_handle output; - wlc_resource surface; -}; - -struct decoration_state { - list_t *csd_resources; -}; - -extern struct desktop_shell_state desktop_shell; -extern struct decoration_state decoration_state; - -void register_extensions(void); - -void server_decoration_enable_csd(wlc_handle handle); - -#endif diff --git a/include/sway/server.h b/include/sway/server.h new file mode 100644 index 00000000..471a0270 --- /dev/null +++ b/include/sway/server.h @@ -0,0 +1,31 @@ +#ifndef _SWAY_SERVER_H +#define _SWAY_SERVER_H +#include +#include +#include +#include +#include +#include +// TODO WLR: make Xwayland optional +#include + +struct sway_server { + // TODO WLR + //struct roots_desktop *desktop; + //struct roots_input *input; + + struct wl_display *wl_display; + struct wl_event_loop *wl_event_loop; + + struct wlr_backend *backend; + struct wlr_renderer *renderer; + + struct wlr_data_device_manager *data_device_manager; +}; + +bool server_init(struct sway_server *server); +void server_fini(struct sway_server *server); + +struct sway_server server; + +#endif diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index 67af0f70..ac0530e5 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt @@ -25,9 +25,7 @@ add_executable(sway container.c criteria.c debug_log.c - extensions.c focus.c - handlers.c input.c input_state.c ipc-json.c @@ -38,6 +36,7 @@ add_executable(sway workspace.c border.c security.c + server.c ) add_definitions( diff --git a/sway/commands.c b/sway/commands.c index c7dbf731..e1181893 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -120,6 +120,7 @@ void input_cmd_apply(struct input_config *input) { // Try to find the input device and apply configuration now. If // this is during startup then there will be no container and config // will be applied during normal "new input" event from wlc. + /* TODO WLR struct libinput_device *device = NULL; for (int i = 0; i < input_devices->length; ++i) { device = input_devices->items[i]; @@ -134,6 +135,7 @@ void input_cmd_apply(struct input_config *input) { break; } } + */ } } diff --git a/sway/extensions.c b/sway/extensions.c deleted file mode 100644 index 91746561..00000000 --- a/sway/extensions.c +++ /dev/null @@ -1,407 +0,0 @@ -#include -#include -#include -#include -#include "wayland-desktop-shell-server-protocol.h" -#include "wayland-swaylock-server-protocol.h" -#include "wayland-gamma-control-server-protocol.h" -#include "wayland-server-decoration-server-protocol.h" -#include "sway/layout.h" -#include "sway/input_state.h" -#include "sway/extensions.h" -#include "sway/security.h" -#include "sway/ipc-server.h" -#include "log.h" - -struct desktop_shell_state desktop_shell; -struct decoration_state decoration_state; - -static struct panel_config *find_or_create_panel_config(struct wl_resource *resource) { - for (int i = 0; i < desktop_shell.panels->length; i++) { - struct panel_config *conf = desktop_shell.panels->items[i]; - if (conf->wl_resource == resource) { - sway_log(L_DEBUG, "Found existing panel config for resource %p", resource); - return conf; - } - } - sway_log(L_DEBUG, "Creating panel config for resource %p", resource); - struct panel_config *config = calloc(1, sizeof(struct panel_config)); - if (!config) { - sway_log(L_ERROR, "Unable to create panel config"); - return NULL; - } - list_add(desktop_shell.panels, config); - config->wl_resource = resource; - return config; -} - -void background_surface_destructor(struct wl_resource *resource) { - sway_log(L_DEBUG, "Background surface killed"); - int i; - for (i = 0; i < desktop_shell.backgrounds->length; ++i) { - struct background_config *config = desktop_shell.backgrounds->items[i]; - if (config->wl_surface_res == resource) { - list_del(desktop_shell.backgrounds, i); - break; - } - } -} - -void panel_surface_destructor(struct wl_resource *resource) { - sway_log(L_DEBUG, "Panel surface killed"); - int i; - for (i = 0; i < desktop_shell.panels->length; ++i) { - struct panel_config *config = desktop_shell.panels->items[i]; - if (config->wl_surface_res == resource) { - list_del(desktop_shell.panels, i); - arrange_windows(&root_container, -1, -1); - break; - } - } -} - -void lock_surface_destructor(struct wl_resource *resource) { - sway_log(L_DEBUG, "Lock surface killed"); - int i; - for (i = 0; i < desktop_shell.lock_surfaces->length; ++i) { - struct wl_resource *surface = desktop_shell.lock_surfaces->items[i]; - if (surface == resource) { - list_del(desktop_shell.lock_surfaces, i); - arrange_windows(&root_container, -1, -1); - break; - } - } - if (desktop_shell.lock_surfaces->length == 0) { - sway_log(L_DEBUG, "Desktop shell unlocked"); - desktop_shell.is_locked = false; - - // We need to now give focus back to the focus which we internally - // track, since when we lock sway we don't actually change our internal - // focus tracking. - swayc_t *focus = get_focused_container(swayc_active_workspace()); - set_focused_container(focus); - wlc_view_focus(focus->handle); - } -} - -static void set_background(struct wl_client *client, struct wl_resource *resource, - struct wl_resource *_output, struct wl_resource *surface) { - pid_t pid; - wl_client_get_credentials(client, &pid, NULL, NULL); - if (!(get_feature_policy_mask(pid) & FEATURE_BACKGROUND)) { - sway_log(L_INFO, "Denying background feature to %d", pid); - return; - } - wlc_handle output = wlc_handle_from_wl_output_resource(_output); - if (!output) { - return; - } - sway_log(L_DEBUG, "Setting surface %p as background for output %d", surface, (int)output); - struct background_config *config = malloc(sizeof(struct background_config)); - if (!config) { - sway_log(L_ERROR, "Unable to allocate background config"); - return; - } - config->client = client; - config->output = output; - config->surface = wlc_resource_from_wl_surface_resource(surface); - config->wl_surface_res = surface; - list_add(desktop_shell.backgrounds, config); - wl_resource_set_destructor(surface, background_surface_destructor); - arrange_windows(swayc_by_handle(output), -1, -1); - wlc_output_schedule_render(config->output); -} - -static void set_panel(struct wl_client *client, struct wl_resource *resource, - struct wl_resource *_output, struct wl_resource *surface) { - pid_t pid; - wl_client_get_credentials(client, &pid, NULL, NULL); - if (!(get_feature_policy_mask(pid) & FEATURE_PANEL)) { - sway_log(L_INFO, "Denying panel feature to %d", pid); - return; - } - wlc_handle output = wlc_handle_from_wl_output_resource(_output); - if (!output) { - return; - } - sway_log(L_DEBUG, "Setting surface %p as panel for output %d (wl_resource: %p)", surface, (int)output, resource); - struct panel_config *config = find_or_create_panel_config(resource); - config->output = output; - config->client = client; - config->surface = wlc_resource_from_wl_surface_resource(surface); - config->wl_surface_res = surface; - wl_resource_set_destructor(surface, panel_surface_destructor); - arrange_windows(&root_container, -1, -1); - wlc_output_schedule_render(config->output); -} - -static void desktop_set_lock_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) { - sway_log(L_ERROR, "desktop_set_lock_surface is not currently supported"); -} - -static void desktop_unlock(struct wl_client *client, struct wl_resource *resource) { - sway_log(L_ERROR, "desktop_unlock is not currently supported"); -} - -static void set_grab_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) { - sway_log(L_ERROR, "desktop_set_grab_surface is not currently supported"); -} - -static void desktop_ready(struct wl_client *client, struct wl_resource *resource) { - // nop -} - -static void set_panel_position(struct wl_client *client, struct wl_resource *resource, uint32_t position) { - pid_t pid; - wl_client_get_credentials(client, &pid, NULL, NULL); - if (!(get_feature_policy_mask(pid) & FEATURE_PANEL)) { - sway_log(L_INFO, "Denying panel feature to %d", pid); - return; - } - struct panel_config *config = find_or_create_panel_config(resource); - sway_log(L_DEBUG, "Panel position for wl_resource %p changed %d => %d", resource, config->panel_position, position); - config->panel_position = position; - arrange_windows(&root_container, -1, -1); -} - -static struct desktop_shell_interface desktop_shell_implementation = { - .set_background = set_background, - .set_panel = set_panel, - .set_lock_surface = desktop_set_lock_surface, - .unlock = desktop_unlock, - .set_grab_surface = set_grab_surface, - .desktop_ready = desktop_ready, - .set_panel_position = set_panel_position -}; - -static void desktop_shell_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id) { - if (version > 3) { - // Unsupported version - return; - } - - struct wl_resource *resource = wl_resource_create(client, &desktop_shell_interface, version, id); - if (!resource) { - wl_client_post_no_memory(client); - } - - wl_resource_set_implementation(resource, &desktop_shell_implementation, NULL, NULL); -} - -static void set_lock_surface(struct wl_client *client, struct wl_resource *resource, - struct wl_resource *_output, struct wl_resource *surface) { - pid_t pid; - wl_client_get_credentials(client, &pid, NULL, NULL); - if (!(get_feature_policy_mask(pid) & FEATURE_LOCK)) { - sway_log(L_INFO, "Denying lock feature to %d", pid); - return; - } - swayc_t *output = swayc_by_handle(wlc_handle_from_wl_output_resource(_output)); - swayc_t *view = swayc_by_handle(wlc_handle_from_wl_surface_resource(surface)); - sway_log(L_DEBUG, "Setting lock surface to %p", view); - if (view && output) { - swayc_t *workspace = output->focused; - if (!swayc_is_child_of(view, workspace)) { - move_container_to(view, workspace); - } - // make the view floating so it doesn't rearrange other siblings. - if (!view->is_floating) { - destroy_container(remove_child(view)); - add_floating(workspace, view); - } - wlc_view_set_state(view->handle, WLC_BIT_FULLSCREEN, true); - wlc_view_bring_to_front(view->handle); - wlc_view_focus(view->handle); - desktop_shell.is_locked = true; - input_init(); - arrange_windows(workspace, -1, -1); - list_add(desktop_shell.lock_surfaces, surface); - wl_resource_set_destructor(surface, lock_surface_destructor); - } else { - sway_log(L_ERROR, "Attempted to set lock surface to non-view"); - } -} - -static void unlock(struct wl_client *client, struct wl_resource *resource) { - sway_log(L_ERROR, "unlock is not currently supported"); - // This isn't really necessary, we just unlock when the client exits. -} - -static struct lock_interface swaylock_implementation = { - .set_lock_surface = set_lock_surface, - .unlock = unlock -}; - -static void swaylock_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id) { - if (version > 1) { - // Unsupported version - return; - } - - struct wl_resource *resource = wl_resource_create(client, &lock_interface, version, id); - if (!resource) { - wl_client_post_no_memory(client); - } - - wl_resource_set_implementation(resource, &swaylock_implementation, NULL, NULL); -} - -static void gamma_control_destroy(struct wl_client *client, struct wl_resource *res) { - wl_resource_destroy(res); -} - -static void gamma_control_set_gamma(struct wl_client *client, - struct wl_resource *res, struct wl_array *red, - struct wl_array *green, struct wl_array *blue) { - if (red->size != green->size || red->size != blue->size) { - wl_resource_post_error(res, GAMMA_CONTROL_ERROR_INVALID_GAMMA, - "The gamma ramps don't have the same size"); - return; - } - uint16_t *r = (uint16_t *)red->data; - uint16_t *g = (uint16_t *)green->data; - uint16_t *b = (uint16_t *)blue->data; - wlc_handle output = wlc_handle_from_wl_output_resource( - wl_resource_get_user_data(res)); - if (!output) { - return; - } - sway_log(L_DEBUG, "Setting gamma for output"); - wlc_output_set_gamma(output, red->size / sizeof(uint16_t), r, g, b); -} - -static void gamma_control_reset_gamma(struct wl_client *client, - struct wl_resource *resource) { - // This space intentionally left blank -} - -static struct gamma_control_interface gamma_control_implementation = { - .destroy = gamma_control_destroy, - .set_gamma = gamma_control_set_gamma, - .reset_gamma = gamma_control_reset_gamma -}; - -static void gamma_control_manager_destroy(struct wl_client *client, - struct wl_resource *res) { - wl_resource_destroy(res); -} - -static void gamma_control_manager_get(struct wl_client *client, - struct wl_resource *res, uint32_t id, struct wl_resource *_output) { - struct wl_resource *manager_res = wl_resource_create(client, - &gamma_control_interface, wl_resource_get_version(res), id); - wlc_handle output = wlc_handle_from_wl_output_resource(_output); - if (!output) { - return; - } - wl_resource_set_implementation(manager_res, &gamma_control_implementation, - _output, NULL); - gamma_control_send_gamma_size(manager_res, wlc_output_get_gamma_size(output)); -} - -static struct gamma_control_manager_interface gamma_manager_implementation = { - .destroy = gamma_control_manager_destroy, - .get_gamma_control = gamma_control_manager_get -}; - -static void gamma_control_manager_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id) { - if (version > 1) { - // Unsupported version - return; - } - struct wl_resource *resource = wl_resource_create(client, - &gamma_control_manager_interface, version, id); - if (!resource) { - wl_client_post_no_memory(client); - } - wl_resource_set_implementation(resource, &gamma_manager_implementation, NULL, NULL); -} - -static void server_decoration_release(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -void server_decoration_enable_csd(wlc_handle handle) { - swayc_t *view = swayc_by_handle(handle); - if (!view) { - sway_log(L_DEBUG, "view invalid"); - return; - } - sway_log(L_DEBUG, "%s requested client side decorations", view->name); - view->border_type = B_NONE; - update_geometry(view); -} - -static void server_decoration_request_mode(struct wl_client *client, - struct wl_resource *resource, uint32_t mode) { - sway_log(L_DEBUG, "Client requested server decoration mode %d", mode); - if (mode == ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER) { - return; - } - struct wl_resource *surface = wl_resource_get_user_data(resource); - if (!surface) { - sway_log(L_DEBUG, "surface invalid"); - return; - } - wlc_handle handle = wlc_handle_from_wl_surface_resource(surface); - if (!handle) { - list_add(decoration_state.csd_resources, surface); - return; - } - server_decoration_enable_csd(handle); -} - -static struct org_kde_kwin_server_decoration_interface server_decoration_implementation = { - .release = server_decoration_release, - .request_mode = server_decoration_request_mode, -}; - -static void server_decoration_manager_create(struct wl_client *client, - struct wl_resource *resource, uint32_t id, struct wl_resource *surface) { - sway_log(L_DEBUG, "Client requested server decoration manager"); - struct wl_resource *manager = wl_resource_create(client, - &org_kde_kwin_server_decoration_interface, 1, id); - if (!manager) { - wl_client_post_no_memory(client); - } - wl_resource_set_implementation(manager, &server_decoration_implementation, surface, NULL); -} - -// Jesus christ KDE, these names are whack as hell -static struct org_kde_kwin_server_decoration_manager_interface server_decoration_manager_implementation = { - .create = server_decoration_manager_create, -}; - -static void server_decoration_manager_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id) { - if (version > 1) { - // Unsupported version - return; - } - struct wl_resource *resource = wl_resource_create(client, - &org_kde_kwin_server_decoration_manager_interface, version, id); - if (!resource) { - wl_client_post_no_memory(client); - } - wl_resource_set_implementation(resource, &server_decoration_manager_implementation, NULL, NULL); - org_kde_kwin_server_decoration_manager_send_default_mode(resource, - ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER); -} - -void register_extensions(void) { - wl_global_create(wlc_get_wl_display(), &desktop_shell_interface, 3, NULL, desktop_shell_bind); - desktop_shell.backgrounds = create_list(); - desktop_shell.panels = create_list(); - desktop_shell.lock_surfaces = create_list(); - desktop_shell.is_locked = false; - decoration_state.csd_resources = create_list(); - wl_global_create(wlc_get_wl_display(), &lock_interface, 1, NULL, swaylock_bind); - wl_global_create(wlc_get_wl_display(), &gamma_control_manager_interface, 1, - NULL, gamma_control_manager_bind); - wl_global_create(wlc_get_wl_display(), &org_kde_kwin_server_decoration_manager_interface , - 1, NULL, server_decoration_manager_bind); -} diff --git a/sway/focus.c b/sway/focus.c index e9b032f8..66f7ee17 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -4,7 +4,6 @@ #include "sway/workspace.h" #include "sway/layout.h" #include "sway/config.h" -#include "sway/extensions.h" #include "sway/input_state.h" #include "sway/ipc-server.h" #include "sway/border.h" @@ -163,12 +162,14 @@ bool set_focused_container(swayc_t *c) { if (c->type == C_VIEW) { wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true); } + /* TODO WLR if (!desktop_shell.is_locked) { // If the system is locked, we do everything _but_ actually setting // focus. This includes making our internals think that this view is // focused. wlc_view_focus(c->handle); } + */ if (c->parent->layout != L_TABBED && c->parent->layout != L_STACKED) { update_container_border(c); } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index b560b930..9ba736d8 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -31,21 +30,22 @@ struct ucred { #include "sway/config.h" #include "sway/commands.h" #include "sway/input.h" +#include "sway/server.h" #include "stringop.h" #include "log.h" #include "list.h" #include "util.h" static int ipc_socket = -1; -static struct wlc_event_source *ipc_event_source = NULL; +static struct wl_event_source *ipc_event_source = NULL; static struct sockaddr_un *ipc_sockaddr = NULL; static list_t *ipc_client_list = NULL; static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; struct ipc_client { - struct wlc_event_source *event_source; - struct wlc_event_source *writable_event_source; + struct wl_event_source *event_source; + struct wl_event_source *writable_event_source; int fd; uint32_t payload_length; uint32_t security_policy; @@ -58,25 +58,6 @@ struct ipc_client { static list_t *ipc_get_pixel_requests = NULL; -struct get_pixels_request { - struct ipc_client *client; - wlc_handle output; - struct wlc_geometry geo; -}; - -struct get_clipboard_request { - struct ipc_client *client; - json_object *json; - int fd; - struct wlc_event_source *fd_event_source; - struct wlc_event_source *timer_event_source; - char *type; - unsigned int *pending; - char *buf; - size_t buf_size; - size_t buf_position; -}; - struct sockaddr_un *ipc_user_sockaddr(void); int ipc_handle_connection(int fd, uint32_t mask, void *data); int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); @@ -118,12 +99,13 @@ void ipc_init(void) { ipc_client_list = create_list(); ipc_get_pixel_requests = create_list(); - ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); + ipc_event_source = wl_event_loop_add_fd(server.wl_event_loop, ipc_socket, + WL_EVENT_READABLE, ipc_handle_connection, NULL); } void ipc_terminate(void) { if (ipc_event_source) { - wlc_event_source_remove(ipc_event_source); + wl_event_source_remove(ipc_event_source); } close(ipc_socket); unlink(ipc_sockaddr->sun_path); @@ -176,7 +158,7 @@ static pid_t get_client_pid(int client_fd) { int ipc_handle_connection(int fd, uint32_t mask, void *data) { (void) fd; (void) data; sway_log(L_DEBUG, "Event on IPC listening socket"); - assert(mask == WLC_EVENT_READABLE); + assert(mask == WL_EVENT_READABLE); int client_fd = accept(ipc_socket, NULL, NULL); if (client_fd == -1) { @@ -207,7 +189,8 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { client->payload_length = 0; client->fd = client_fd; client->subscribed_events = 0; - client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); + client->event_source = wl_event_loop_add_fd(server.wl_event_loop, client_fd, + WL_EVENT_READABLE, ipc_client_handle_readable, client); client->writable_event_source = NULL; client->write_buffer_size = 128; @@ -234,13 +217,13 @@ static const int ipc_header_size = sizeof(ipc_magic)+8; int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; - if (mask & WLC_EVENT_ERROR) { + if (mask & WL_EVENT_ERROR) { sway_log(L_ERROR, "IPC Client socket error, removing client"); ipc_client_disconnect(client); return 0; } - if (mask & WLC_EVENT_HANGUP) { + if (mask & WL_EVENT_HANGUP) { sway_log(L_DEBUG, "Client %d hung up", client->fd); ipc_client_disconnect(client); return 0; @@ -296,13 +279,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; - if (mask & WLC_EVENT_ERROR) { + if (mask & WL_EVENT_ERROR) { sway_log(L_ERROR, "IPC Client socket error, removing client"); ipc_client_disconnect(client); return 0; } - if (mask & WLC_EVENT_HANGUP) { + if (mask & WL_EVENT_HANGUP) { sway_log(L_DEBUG, "Client %d hung up", client->fd); ipc_client_disconnect(client); return 0; @@ -328,7 +311,7 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { client->write_buffer_len -= written; if (client->write_buffer_len == 0 && client->writable_event_source) { - wlc_event_source_remove(client->writable_event_source); + wl_event_source_remove(client->writable_event_source); client->writable_event_source = NULL; } @@ -345,9 +328,9 @@ void ipc_client_disconnect(struct ipc_client *client) { } sway_log(L_INFO, "IPC Client %d disconnected", client->fd); - wlc_event_source_remove(client->event_source); + wl_event_source_remove(client->event_source); if (client->writable_event_source) { - wlc_event_source_remove(client->writable_event_source); + wl_event_source_remove(client->writable_event_source); } int i = 0; while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; @@ -365,165 +348,6 @@ bool output_by_name_test(swayc_t *view, void *data) { return !strcmp(name, view->name); } -void ipc_get_pixels(wlc_handle output) { - if (ipc_get_pixel_requests->length == 0) { - return; - } - - list_t *unhandled = create_list(); - - struct get_pixels_request *req; - int i; - for (i = 0; i < ipc_get_pixel_requests->length; ++i) { - req = ipc_get_pixel_requests->items[i]; - if (req->output != output) { - list_add(unhandled, req); - continue; - } - - const struct wlc_size *size = &req->geo.size; - struct wlc_geometry g_out; - char response_header[9]; - memset(response_header, 0, sizeof(response_header)); - char *data = malloc(sizeof(response_header) + size->w * size->h * 4); - if (!data) { - sway_log(L_ERROR, "Unable to allocate pixels for get_pixels"); - ipc_client_disconnect(req->client); - free(req); - continue; - } - wlc_pixels_read(WLC_RGBA8888, &req->geo, &g_out, data + sizeof(response_header)); - - response_header[0] = 1; - uint32_t *_size = (uint32_t *)(response_header + 1); - _size[0] = g_out.size.w; - _size[1] = g_out.size.h; - size_t len = sizeof(response_header) + (g_out.size.w * g_out.size.h * 4); - memcpy(data, response_header, sizeof(response_header)); - ipc_send_reply(req->client, data, len); - free(data); - // free the request since it has been handled - free(req); - } - - // free old list of pixel requests and set new list to all unhandled - // requests (request for another output). - list_free(ipc_get_pixel_requests); - ipc_get_pixel_requests = unhandled; -} - -static bool is_text_target(const char *target) { - return (strncmp(target, "text/", 5) == 0 - || strcmp(target, "UTF8_STRING") == 0 - || strcmp(target, "STRING") == 0 - || strcmp(target, "TEXT") == 0 - || strcmp(target, "COMPOUND_TEXT") == 0); -} - -static void release_clipboard_request(struct get_clipboard_request *req) { - if (--(*req->pending) == 0) { - const char *str = json_object_to_json_string(req->json); - ipc_send_reply(req->client, str, (uint32_t)strlen(str)); - json_object_put(req->json); - } - - free(req->type); - free(req->buf); - wlc_event_source_remove(req->fd_event_source); - wlc_event_source_remove(req->timer_event_source); - close(req->fd); - free(req); -} - -static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) { - assert(data); - struct get_clipboard_request *req = (struct get_clipboard_request *)data; - - if (mask & WLC_EVENT_ERROR) { - sway_log(L_ERROR, "Selection data fd error"); - goto error; - } - - if (mask & WLC_EVENT_READABLE) { - static const unsigned int max_size = 8192 * 1024; - int amt = 0; - - do { - int size = req->buf_size - req->buf_position; - int amt = read(fd, req->buf + req->buf_position, size - 1); - if (amt < 0) { - if (errno == EAGAIN) { - return 0; - } - - sway_log_errno(L_INFO, "Failed to read from clipboard data fd"); - goto release; - } - - req->buf_position += amt; - if (req->buf_position >= req->buf_size - 1) { - if (req->buf_size >= max_size) { - sway_log(L_ERROR, "get_clipbard: selection data too large"); - goto error; - } - char *next = realloc(req->buf, req->buf_size *= 2); - if (!next) { - sway_log_errno(L_ERROR, "get_clipboard: realloc data buffer failed"); - goto error; - } - - req->buf = next; - } - } while(amt != 0); - - req->buf[req->buf_position] = '\0'; - - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "success", json_object_new_boolean(true)); - if (is_text_target(req->type)) { - json_object_object_add(obj, "content", json_object_new_string(req->buf)); - json_object_object_add(req->json, req->type, obj); - } else { - size_t outlen; - char *b64 = b64_encode(req->buf, req->buf_position, &outlen); - json_object_object_add(obj, "content", json_object_new_string(b64)); - free(b64); - - char *type = malloc(strlen(req->type) + 8); - strcat(type, ";base64"); - json_object_object_add(req->json, type, obj); - free(type); - } - } - - goto release; - -error:; - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "success", json_object_new_boolean(false)); - json_object_object_add(obj, "error", - json_object_new_string("Failed to retrieve data")); - json_object_object_add(req->json, req->type, obj); - -release: - release_clipboard_request(req); - return 0; -} - -static int ipc_selection_timer_cb(void *data) { - assert(data); - struct get_clipboard_request *req = (struct get_clipboard_request *)data; - - sway_log(L_INFO, "get_clipbard: timeout for type %s", req->type); - json_object *obj = json_object_new_object(); - json_object_object_add(obj, "success", json_object_new_boolean(false)); - json_object_object_add(obj, "error", json_object_new_string("Timeout")); - json_object_object_add(req->json, req->type, obj); - - release_clipboard_request(req); - return 0; -} - // greedy wildcard (only "*") matching bool mime_type_matches(const char *mime_type, const char *pattern) { const char *wildcard = NULL; @@ -553,125 +377,6 @@ bool mime_type_matches(const char *mime_type, const char *pattern) { return (*mime_type == *pattern); } -void ipc_get_clipboard(struct ipc_client *client, char *buf) { - size_t size; - const char **types = wlc_get_selection_types(&size); - if (client->payload_length == 0) { - json_object *obj = json_object_new_array(); - for (size_t i = 0; i < size; ++i) { - json_object_array_add(obj, json_object_new_string(types[i])); - } - - const char *str = json_object_to_json_string(obj); - ipc_send_reply(client, str, strlen(str)); - json_object_put(obj); - return; - } - - unescape_string(buf); - strip_quotes(buf); - list_t *requested = split_string(buf, " "); - json_object *json = json_object_new_object(); - unsigned int *pending = malloc(sizeof(unsigned int)); - *pending = 0; - - for (size_t l = 0; l < (size_t) requested->length; ++l) { - const char *pattern = requested->items[l]; - bool found = false; - for (size_t i = 0; i < size; ++i) { - if (!mime_type_matches(types[i], pattern)) { - continue; - } - - found = true; - - struct get_clipboard_request *req = malloc(sizeof(*req)); - if (!req) { - sway_log(L_ERROR, "get_clipboard: request malloc failed"); - goto data_error; - } - - int pipes[2]; - if (pipe(pipes) == -1) { - sway_log_errno(L_ERROR, "get_clipboard: pipe call failed"); - free(req); - goto data_error; - } - - fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK); - fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK); - - if (!wlc_get_selection_data(types[i], pipes[1])) { - close(pipes[0]); - close(pipes[1]); - free(req); - sway_log(L_ERROR, "get_clipboard: failed to retrieve " - "selection data"); - goto data_error; - } - - if (!(req->buf = malloc(512))) { - close(pipes[0]); - close(pipes[1]); - free(req); - sway_log_errno(L_ERROR, "get_clipboard: buf malloc failed"); - goto data_error; - } - - (*pending)++; - - req->client = client; - req->type = strdup(types[i]); - req->json = json; - req->pending = pending; - req->buf_position = 0; - req->buf_size = 512; - req->fd = pipes[0]; - req->timer_event_source = wlc_event_loop_add_timer(ipc_selection_timer_cb, req); - req->fd_event_source = wlc_event_loop_add_fd(pipes[0], - WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP, - &ipc_selection_data_cb, req); - - wlc_event_source_timer_update(req->timer_event_source, 30000); - - // NOTE: remove this goto to enable retrieving multiple - // targets at once. The whole implementation is already - // made for it. The only reason it was disabled - // at the time of writing is that neither wlc's xselection - // implementation nor (apparently) gtk on wayland supports - // multiple send requests at the same time which makes - // every request except the last one fail (and therefore - // return empty data) - goto cleanup; - } - - if (!found) { - sway_log(L_INFO, "Invalid clipboard type %s requested", pattern); - } - } - - if (*pending == 0) { - static const char *error_empty = "{ \"success\": false, \"error\": " - "\"No matching types found\" }"; - ipc_send_reply(client, error_empty, (uint32_t)strlen(error_empty)); - free(json); - free(pending); - } - - goto cleanup; - -data_error:; - static const char *error_json = "{ \"success\": false, \"error\": " - "\"Failed to create clipboard data request\" }"; - ipc_send_reply(client, error_json, (uint32_t)strlen(error_json)); - free(json); - free(pending); - -cleanup: - list_free(requested); - free(types); -} - void ipc_client_handle_command(struct ipc_client *client) { if (!sway_assert(client != NULL, "client != NULL")) { return; @@ -830,52 +535,6 @@ void ipc_client_handle_command(struct ipc_client *client) { goto exit_cleanup; } - case IPC_SWAY_GET_PIXELS: - { - char response_header[9]; - memset(response_header, 0, sizeof(response_header)); - - json_object *obj = json_tokener_parse(buf); - json_object *o, *x, *y, *w, *h; - - json_object_object_get_ex(obj, "output", &o); - json_object_object_get_ex(obj, "x", &x); - json_object_object_get_ex(obj, "y", &y); - json_object_object_get_ex(obj, "w", &w); - json_object_object_get_ex(obj, "h", &h); - - struct wlc_geometry g = { - .origin = { - .x = json_object_get_int(x), - .y = json_object_get_int(y) - }, - .size = { - .w = json_object_get_int(w), - .h = json_object_get_int(h) - } - }; - - swayc_t *output = swayc_by_test(&root_container, output_by_name_test, (void *)json_object_get_string(o)); - json_object_put(obj); - - if (!output) { - sway_log(L_ERROR, "IPC GET_PIXELS request with unknown output name"); - ipc_send_reply(client, response_header, sizeof(response_header)); - goto exit_cleanup; - } - struct get_pixels_request *req = malloc(sizeof(struct get_pixels_request)); - if (!req) { - sway_log(L_ERROR, "Unable to allocate get_pixels request"); - goto exit_cleanup; - } - req->client = client; - req->output = output->handle; - req->geo = g; - list_add(ipc_get_pixel_requests, req); - wlc_output_schedule_render(output->handle); - goto exit_cleanup; - } - case IPC_GET_BAR_CONFIG: { if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) { @@ -917,14 +576,8 @@ void ipc_client_handle_command(struct ipc_client *client) { } case IPC_GET_CLIPBOARD: - { - if (!(client->security_policy & IPC_FEATURE_GET_CLIPBOARD)) { - goto exit_denied; - } - - ipc_get_clipboard(client, buf); - goto exit_cleanup; - } + // TODO WLR + break; default: sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); @@ -977,7 +630,9 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay client->write_buffer_len += payload_length; if (!client->writable_event_source) { - client->writable_event_source = wlc_event_loop_add_fd(client->fd, WLC_EVENT_WRITABLE, ipc_client_handle_writable, client); + client->writable_event_source = wl_event_loop_add_fd( + server.wl_event_loop, client->fd, WL_EVENT_WRITABLE, + ipc_client_handle_writable, client); } sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); diff --git a/sway/layout.c b/sway/layout.c index 69291daf..22f81688 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -3,7 +3,6 @@ #include #include #include -#include "sway/extensions.h" #include "sway/config.h" #include "sway/container.h" #include "sway/workspace.h" @@ -1001,6 +1000,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { { swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); width = output->width, height = output->height; + /* TODO WLR for (i = 0; i < desktop_shell.panels->length; ++i) { struct panel_config *config = desktop_shell.panels->items[i]; if (config->output == output->handle) { @@ -1022,6 +1022,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { } } } + */ int gap = swayc_gap(container); x = container->x = x + gap; y = container->y = y + gap; @@ -1380,11 +1381,13 @@ void arrange_windows(swayc_t *container, double width, double height) { } void arrange_backgrounds(void) { + /* TODO WLR struct background_config *bg; for (int i = 0; i < desktop_shell.backgrounds->length; ++i) { bg = desktop_shell.backgrounds->items[i]; wlc_view_send_to_back(bg->handle); } + */ } /** diff --git a/sway/main.c b/sway/main.c index cc9147b8..efca96d5 100644 --- a/sway/main.c +++ b/sway/main.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -15,13 +14,13 @@ #include #include #endif -#include "sway/extensions.h" #include "sway/layout.h" #include "sway/config.h" #include "sway/security.h" #include "sway/handlers.h" #include "sway/input.h" #include "sway/ipc-server.h" +#include "sway/server.h" #include "ipc-client.h" #include "readline.h" #include "stringop.h" @@ -31,11 +30,12 @@ static bool terminate_request = false; static int exit_value = 0; +struct sway_server server; void sway_terminate(int exit_code) { terminate_request = true; exit_value = exit_code; - wlc_terminate(); + wl_display_terminate(server.wl_display); } void sig_handler(int signal) { @@ -43,16 +43,6 @@ void sig_handler(int signal) { sway_terminate(EXIT_SUCCESS); } -static void wlc_log_handler(enum wlc_log_type type, const char *str) { - if (type == WLC_LOG_ERROR) { - sway_log(L_ERROR, "[wlc] %s", str); - } else if (type == WLC_LOG_WARN) { - sway_log(L_INFO, "[wlc] %s", str); - } else { - sway_log(L_DEBUG, "[wlc] %s", str); - } -} - void detect_raspi() { bool raspi = false; FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); @@ -189,19 +179,7 @@ static void log_env() { "LD_LIBRARY_PATH", "SWAY_CURSOR_THEME", "SWAY_CURSOR_SIZE", - "SWAYSOCK", - "WLC_DRM_DEVICE", - "WLC_SHM", - "WLC_OUTPUTS", - "WLC_XWAYLAND", - "WLC_LIBINPUT", - "WLC_REPEAT_DELAY", - "WLC_REPEAT_RATE", - "XKB_DEFAULT_RULES", - "XKB_DEFAULT_MODEL", - "XKB_DEFAULT_LAYOUT", - "XKB_DEFAULT_VARIANT", - "XKB_DEFAULT_OPTIONS", + "SWAYSOCK" }; for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) { sway_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); @@ -295,6 +273,37 @@ static void executable_sanity_check() { #endif } +static void drop_permissions(bool keep_caps) { + if (getuid() != geteuid() || getgid() != getegid()) { + if (setgid(getgid()) != 0) { + sway_log(L_ERROR, "Unable to drop root"); + exit(EXIT_FAILURE); + } + if (setuid(getuid()) != 0) { + sway_log(L_ERROR, "Unable to drop root"); + exit(EXIT_FAILURE); + } + } + if (setuid(0) != -1) { + sway_log(L_ERROR, "Root privileges can be restored."); + exit(EXIT_FAILURE); + } +#ifdef __linux__ + if (keep_caps) { + // Drop every cap except CAP_SYS_PTRACE + cap_t caps = cap_init(); + cap_value_t keep = CAP_SYS_PTRACE; + sway_log(L_INFO, "Dropping extra capabilities"); + if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) || + cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) || + cap_set_proc(caps)) { + sway_log(L_ERROR, "Failed to drop extra capabilities"); + exit(EXIT_FAILURE); + } + } +#endif +} + int main(int argc, char **argv) { static int verbose = 0, debug = 0, validate = 0; @@ -374,7 +383,7 @@ int main(int argc, char **argv) { } } - // we need to setup logging before wlc_init in case it fails. + // TODO: switch logging over to wlroots? if (debug) { init_log(L_DEBUG); } else if (verbose || validate) { @@ -388,20 +397,7 @@ int main(int argc, char **argv) { sway_log(L_ERROR, "Don't use options with the IPC client"); exit(EXIT_FAILURE); } - if (getuid() != geteuid() || getgid() != getegid()) { - if (setgid(getgid()) != 0) { - sway_log(L_ERROR, "Unable to drop root"); - exit(EXIT_FAILURE); - } - if (setuid(getuid()) != 0) { - sway_log(L_ERROR, "Unable to drop root"); - exit(EXIT_FAILURE); - } - } - if (setuid(0) != -1) { - sway_log(L_ERROR, "Root privileges can be restored."); - exit(EXIT_FAILURE); - } + drop_permissions(false); char *socket_path = getenv("SWAYSOCK"); if (!socket_path) { sway_log(L_ERROR, "Unable to retrieve socket path"); @@ -413,8 +409,8 @@ int main(int argc, char **argv) { } executable_sanity_check(); -#ifdef __linux__ bool suid = false; +#ifdef __linux__ if (getuid() != geteuid() || getgid() != getegid()) { // Retain capabilities after setuid() if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { @@ -425,37 +421,14 @@ int main(int argc, char **argv) { } #endif - wlc_log_set_handler(wlc_log_handler); log_kernel(); log_distro(); log_env(); detect_proprietary(); detect_raspi(); - input_devices = create_list(); - - /* Changing code earlier than this point requires detailed review */ - /* (That code runs as root on systems without logind, and wlc_init drops to - * another user.) */ - register_wlc_handlers(); - if (!wlc_init()) { - return 1; - } - register_extensions(); - #ifdef __linux__ - if (suid) { - // Drop every cap except CAP_SYS_PTRACE - cap_t caps = cap_init(); - cap_value_t keep = CAP_SYS_PTRACE; - sway_log(L_INFO, "Dropping extra capabilities"); - if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) || - cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) || - cap_set_proc(caps)) { - sway_log(L_ERROR, "Failed to drop extra capabilities"); - exit(EXIT_FAILURE); - } - } + drop_permissions(suid); #endif // handle SIGTERM signals signal(SIGTERM, sig_handler); @@ -465,8 +438,10 @@ int main(int argc, char **argv) { sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n"); + if (!server_init(&server)) { + return 1; + } init_layout(); - ipc_init(); if (validate) { @@ -485,10 +460,10 @@ int main(int argc, char **argv) { security_sanity_check(); if (!terminate_request) { - wlc_run(); + wl_display_run(server.wl_display); } - list_free(input_devices); + server_fini(&server); ipc_terminate(); diff --git a/sway/server.c b/sway/server.c new file mode 100644 index 00000000..39fa5d28 --- /dev/null +++ b/sway/server.c @@ -0,0 +1,54 @@ +#define _POSIX_C_SOURCE 200112L +#include +#include +#include +#include +#include +#include +#include +#include +// TODO WLR: make Xwayland optional +#include +#include "sway/server.h" +#include "log.h" + +bool server_init(struct sway_server *server) { + sway_log(L_DEBUG, "Initializing Wayland server"); + + server->wl_display = wl_display_create(); + server->wl_event_loop = wl_display_get_event_loop(server->wl_display); + server->backend = wlr_backend_autocreate(server->wl_display); + + server->renderer = wlr_gles2_renderer_create(server->backend); + wl_display_init_shm(server->wl_display); + + // TODO WLR + //server->desktop = desktop_create(server, server.config); + //server->input = input_create(&server, server.config); + server->data_device_manager = + wlr_data_device_manager_create(server->wl_display); + + const char *socket = wl_display_add_socket_auto(server->wl_display); + if (!socket) { + sway_log_errno(L_ERROR, "Unable to open wayland socket"); + wlr_backend_destroy(server->backend); + return false; + } + + sway_log(L_INFO, "Running compositor on wayland display '%s'", socket); + setenv("_WAYLAND_DISPLAY", socket, true); + + if (!wlr_backend_start(server->backend)) { + sway_log(L_ERROR, "Failed to start backend"); + wlr_backend_destroy(server->backend); + return false; + } + + setenv("WAYLAND_DISPLAY", socket, true); + return true; +} + +void server_fini(struct sway_server *server) { + // TODO WLR: tear down more stuff + wlr_backend_destroy(server->backend); +} diff --git a/sway/workspace.c b/sway/workspace.c index e0367190..14cde146 100644 --- a/sway/workspace.c +++ b/sway/workspace.c @@ -8,7 +8,6 @@ #include #include #include "sway/ipc-server.h" -#include "sway/extensions.h" #include "sway/workspace.h" #include "sway/layout.h" #include "sway/container.h"