diff --git a/include/sway/container.h b/include/sway/container.h index 09e292915..d46ffa63b 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -11,6 +11,8 @@ typedef struct sway_container swayc_t; extern swayc_t root_container; extern swayc_t *current_focus; +struct sway_view; + /** * Different kinds of containers. * @@ -27,14 +29,6 @@ enum swayc_types { C_TYPES, }; -enum swayc_view_types { - V_WL_SHELL, - V_XDG_SHELL_V6, - V_XWAYLAND, - // Keep last - V_TYPES, -}; - /** * Different ways to arrange a container. */ @@ -76,6 +70,7 @@ struct sway_container { union { struct sway_output *output; + struct sway_view *view; } _handle; /** @@ -207,7 +202,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout); * * Pass in a sibling view, or a workspace to become this container's parent. */ -swayc_t *new_view(swayc_t *sibling, wlc_handle handle); +swayc_t *new_view(swayc_t *sibling, struct sway_view *view); /** * Allocates a new floating view in the active workspace. */ diff --git a/include/sway/server.h b/include/sway/server.h index 043c1a331..5a8a8d318 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -5,6 +5,7 @@ #include #include #include +#include #include // TODO WLR: make Xwayland optional #include @@ -24,6 +25,9 @@ struct sway_server { struct wl_listener output_add; struct wl_listener output_remove; struct wl_listener output_frame; + + struct wlr_xdg_shell_v6 *xdg_shell_v6; + struct wl_listener xdg_shell_v6_surface; }; struct sway_server server; @@ -35,4 +39,6 @@ void server_run(struct sway_server *server); void output_add_notify(struct wl_listener *listener, void *data); void output_remove_notify(struct wl_listener *listener, void *data); +void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); + #endif diff --git a/include/sway/view.h b/include/sway/view.h new file mode 100644 index 000000000..979b20a8e --- /dev/null +++ b/include/sway/view.h @@ -0,0 +1,56 @@ +#ifndef _SWAY_VIEW_H +#define _SWAY_VIEW_H +#include +#include + +struct sway_container; +struct sway_view; + +struct sway_xdg_surface_v6 { + struct sway_view *view; + + struct wl_listener commit; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; +}; + +enum sway_view_type { + SWAY_WL_SHELL_VIEW, + SWAY_XDG_SHELL_V6_VIEW, + SWAY_XWAYLAND_VIEW, + // Keep last + SWAY_VIEW_TYPES, +}; + +enum sway_view_prop { + VIEW_PROP_TITLE, + VIEW_PROP_CLASS, + VIEW_PROP_INSTANCE, + VIEW_PROP_APP_ID, +}; + +/** + * sway_view is a state container for surfaces that are arranged in the sway + * tree (shell surfaces). + */ +struct sway_view { + struct wl_listener destroy; + enum sway_view_type type; + struct sway_container *swayc; + + union { + struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; + }; + + union { + struct sway_xdg_surface_v6 *sway_xdg_surface_v6; + }; + + struct { + const char *(*get_prop)(struct sway_view *view, + enum sway_view_prop prop); + } iface; +}; + +#endif diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index 617a71f00..f9209189e 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt @@ -19,6 +19,7 @@ file(GLOB cmds add_executable(sway desktop/output.c + desktop/xdg_shell_v6.c tree/container.c tree/criteria.c diff --git a/sway/config.c b/sway/config.c index 78ab8f3b9..aa40c49a5 100644 --- a/sway/config.c +++ b/sway/config.c @@ -932,6 +932,7 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { static void invoke_swaybar(struct bar_config *bar) { return; // TODO WLR + sway_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); // Pipe to communicate errors int filedes[2]; if (pipe(filedes) == -1) { @@ -1059,7 +1060,6 @@ void load_swaybars() { if (bar->pid != 0) { terminate_swaybar(bar->pid); } - sway_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); invoke_swaybar(bar); } diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c new file mode 100644 index 000000000..e29b46d7d --- /dev/null +++ b/sway/desktop/xdg_shell_v6.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/focus.h" +#include "sway/ipc-server.h" +#include "sway/server.h" +#include "sway/view.h" +#include "log.h" + +// TODO: move elsewhere +static void temp_ws_cleanup() { + swayc_t *op, *ws; + int i = 0, j; + if (!root_container.children) + return; + while (i < root_container.children->length) { + op = root_container.children->items[i++]; + if (!op->children) + continue; + j = 0; + while (j < op->children->length) { + ws = op->children->items[j++]; + if (ws->children->length == 0 && ws->floating->length == 0 && ws != op->focused) { + if (destroy_workspace(ws)) { + j--; + } + } + } + } +} + +// TODO: move elsewhere +static swayc_t *move_focus_to_tiling(swayc_t *focused) { + if (focused->is_floating) { + if (focused->parent->children->length == 0) { + return focused->parent; + } + // TODO find a better way of doing this + // Or to focused container + return get_focused_container(focused->parent->children->items[0]); + } + return focused; +} + +static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { + if (!sway_assert(view->type == SWAY_XDG_SHELL_V6_VIEW, + "xdg get_prop for non-xdg view!")) { + return NULL; + } + switch (prop) { + case VIEW_PROP_TITLE: + return view->wlr_xdg_surface_v6->title; + case VIEW_PROP_APP_ID: + return view->wlr_xdg_surface_v6->app_id; + default: + return NULL; + } +} + +void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { + struct sway_server *server = wl_container_of( + listener, server, xdg_shell_v6_surface); + struct wlr_xdg_surface_v6 *xdg_surface = data; + + if (xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { + // TODO: popups + return; + } + + sway_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'", + xdg_surface->title, xdg_surface->app_id); + wlr_xdg_surface_v6_ping(xdg_surface); + + struct sway_xdg_surface_v6 *sway_surface = + calloc(1, sizeof(struct sway_xdg_surface_v6)); + if (!sway_assert(sway_surface, "Failed to allocate surface!")) { + return; + } + + struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); + if (!sway_assert(sway_view, "Failed to allocate view!")) { + return; + } + sway_view->type = SWAY_XDG_SHELL_V6_VIEW; + sway_view->iface.get_prop = get_prop; + sway_surface->view = sway_view; + + // TODO: + // - Consolodate common logic between shells + // - Wire up listeners + // - Handle popups + // - Look up pid and open on appropriate workspace + // - Set new view to maximized so it behaves nicely + // - Criteria + + suspend_workspace_cleanup = true; + //swayc_t *current_ws = swayc_active_workspace(); + swayc_t *prev_focus = get_focused_container(&root_container); + swayc_t *focused = move_focus_to_tiling(prev_focus); + + // TODO: fix new_view + swayc_t *view = new_view(focused, sway_view); + ipc_event_window(view, "new"); + set_focused_container(view); + + swayc_t *output = swayc_parent_by_type(view, C_OUTPUT); + arrange_windows(output, -1, -1); + + swayc_t *workspace = swayc_parent_by_type(focused, C_WORKSPACE); + if (workspace && workspace->fullscreen) { + set_focused_container(workspace->fullscreen); + } + suspend_workspace_cleanup = false; + temp_ws_cleanup(); +} diff --git a/sway/server.c b/sway/server.c index a7f47af37..940f28b31 100644 --- a/sway/server.c +++ b/sway/server.c @@ -34,6 +34,11 @@ bool server_init(struct sway_server *server) { wl_signal_add(&server->backend->events.output_remove, &server->output_remove); + server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display); + wl_signal_add(&server->xdg_shell_v6->events.new_surface, + &server->xdg_shell_v6_surface); + server->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface; + server->socket = wl_display_add_socket_auto(server->wl_display); if (!sway_assert(server->socket, "Unable to open wayland socket")) { wlr_backend_destroy(server->backend); diff --git a/sway/tree/container.c b/sway/tree/container.c index 25bb858e0..82c0d8770 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -15,6 +15,7 @@ #include "sway/input_state.h" #include "sway/ipc-server.h" #include "sway/output.h" +#include "sway/view.h" #include "log.h" #include "stringop.h" @@ -291,44 +292,49 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout) { return cont; } -swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { +swayc_t *new_view(swayc_t *sibling, struct sway_view *view) { if (!ASSERT_NONNULL(sibling)) { return NULL; } - const char *title = wlc_view_get_title(handle); - swayc_t *view = new_swayc(C_VIEW); - sway_log(L_DEBUG, "Adding new view %" PRIuPTR ":%s to container %p %d", - handle, title, sibling, sibling ? sibling->type : 0); + const char *title = view->iface.get_prop(view, VIEW_PROP_TITLE); + swayc_t *swayc = new_swayc(C_VIEW); + sway_log(L_DEBUG, "Adding new view %p:%s to container %p %d", + swayc, title, sibling, sibling ? sibling->type : 0); // Setup values - view->handle = handle; - view->name = title ? strdup(title) : NULL; - const char *class = wlc_view_get_class(handle); - view->class = class ? strdup(class) : NULL; - const char *instance = wlc_view_get_instance(handle); - view->instance = instance ? strdup(instance) : NULL; - const char *app_id = wlc_view_get_app_id(handle); - view->app_id = app_id ? strdup(app_id) : NULL; - view->visible = true; - view->is_focused = true; - view->sticky = false; - view->width = 0; - view->height = 0; - view->desired_width = -1; - view->desired_height = -1; - // setup border - view->border_type = config->border; - view->border_thickness = config->border_thickness; + swayc->_handle.view = view; - view->is_floating = false; + swayc->name = title ? strdup(title) : NULL; + + const char *class = view->iface.get_prop(view, VIEW_PROP_CLASS); + swayc->class = class ? strdup(class) : NULL; + + const char *instance = view->iface.get_prop(view, VIEW_PROP_INSTANCE); + swayc->instance = instance ? strdup(instance) : NULL; + + const char *app_id = view->iface.get_prop(view, VIEW_PROP_APP_ID); + swayc->app_id = app_id ? strdup(app_id) : NULL; + + swayc->visible = true; + swayc->is_focused = true; + swayc->sticky = false; + swayc->width = 0; + swayc->height = 0; + swayc->desired_width = -1; + swayc->desired_height = -1; + // setup border + swayc->border_type = config->border; + swayc->border_thickness = config->border_thickness; + + swayc->is_floating = false; if (sibling->type == C_WORKSPACE) { // Case of focused workspace, just create as child of it - add_child(sibling, view); + add_child(sibling, swayc); } else { // Regular case, create as sibling of current container - add_sibling(sibling, view); + add_sibling(sibling, swayc); } - return view; + return swayc; } swayc_t *new_floating_view(wlc_handle handle) {