diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 61ab7ca15..daad86845 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -34,7 +34,6 @@ enum sway_container_layout { L_VERT, L_STACKED, L_TABBED, - L_FLOATING, }; enum sway_container_border { @@ -70,6 +69,9 @@ struct sway_container { enum sway_container_layout layout; enum sway_container_layout prev_layout; + // Saves us from searching the list of children/floating in the parent + bool is_floating; + // For C_ROOT, this has no meaning // For C_OUTPUT, this is the output position in layout coordinates // For other types, this is the position in output-local coordinates diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index cc9998719..5606c2cb2 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -46,6 +46,9 @@ struct sway_container *container_add_sibling(struct sway_container *parent, struct sway_container *container_remove_child(struct sway_container *child); +void container_add_floating(struct sway_container *workspace, + struct sway_container *child); + struct sway_container *container_replace_child(struct sway_container *child, struct sway_container *new_child); diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 35e1df3b3..ece0ab5c3 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -8,6 +8,7 @@ struct sway_view; struct sway_workspace { struct sway_container *swayc; struct sway_view *fullscreen; + list_t *floating; }; extern char *prev_workspace_name; diff --git a/sway/commands.c b/sway/commands.c index 2e1cdc2ce..33ab25e12 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -107,7 +107,6 @@ static struct cmd_handler handlers[] = { { "focus_follows_mouse", cmd_focus_follows_mouse }, { "font", cmd_font }, { "for_window", cmd_for_window }, - { "fullscreen", cmd_fullscreen }, { "include", cmd_include }, { "input", cmd_input }, { "mode", cmd_mode }, @@ -170,7 +169,9 @@ static struct cmd_handler config_handlers[] = { static struct cmd_handler command_handlers[] = { { "border", cmd_border }, { "exit", cmd_exit }, + { "floating", cmd_floating }, { "focus", cmd_focus }, + { "fullscreen", cmd_fullscreen }, { "kill", cmd_kill }, { "layout", cmd_layout }, { "move", cmd_move }, diff --git a/sway/commands/floating.c b/sway/commands/floating.c new file mode 100644 index 000000000..9e0be9d0c --- /dev/null +++ b/sway/commands/floating.c @@ -0,0 +1,61 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/seat.h" +#include "sway/ipc-server.h" +#include "sway/output.h" +#include "sway/tree/arrange.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/tree/view.h" +#include "list.h" + +struct cmd_results *cmd_floating(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { + return error; + } + struct sway_container *container = + config->handler_context.current_container; + if (container->type != C_VIEW) { + // TODO: This doesn't strictly speaking have to be true + return cmd_results_new(CMD_INVALID, "float", "Only views can float"); + } + + bool wants_floating; + if (strcasecmp(argv[0], "enable") == 0) { + wants_floating = true; + } else if (strcasecmp(argv[0], "disable") == 0) { + wants_floating = false; + } else if (strcasecmp(argv[0], "toggle") == 0) { + wants_floating = !container->is_floating; + } else { + return cmd_results_new(CMD_FAILURE, "floating", + "Expected 'floating "); + } + + // Change from tiled to floating + if (!container->is_floating && wants_floating) { + struct sway_container *workspace = container_parent( + container, C_WORKSPACE); + container_remove_child(container); + container_add_floating(workspace, container); + + struct sway_output *output = workspace->parent->sway_output; + output_damage_whole_container(output, container); + // Reset to sane size and position + container->width = 640; + container->height = 480; + container->x = workspace->width / 2 - container->width / 2; + container->y = workspace->height / 2 - container->height / 2; + view_autoconfigure(container->sway_view); + output_damage_whole_container(output, container); + + seat_set_focus(config->handler_context.seat, container); + arrange_workspace(workspace); + } else if (container->is_floating && !wants_floating) { + // TODO + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/debug-tree.c b/sway/debug-tree.c index ae0a1869b..5af5b5652 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c @@ -22,8 +22,6 @@ static const char *layout_to_str(enum sway_container_layout layout) { return "L_STACKED"; case L_TABBED: return "L_TABBED"; - case L_FLOATING: - return "L_FLOATING"; case L_NONE: default: return "L_NONE"; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 9b0f1ae34..e7f2dc59d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -383,6 +383,34 @@ static void render_container_simple_border_pixel(struct sway_output *output, static void render_container(struct sway_output *output, struct sway_container *con); +static void render_view_with_border(struct sway_output *output, + struct sway_container *view) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + if (view->sway_view->border != B_NONE) { + struct border_colors *colors; + struct wlr_texture *title_texture; + if (focus == view) { + colors = &config->border_colors.focused; + title_texture = view->title_focused; + } else if (seat_get_focus_inactive(seat, view->parent) == view) { + colors = &config->border_colors.focused_inactive; + title_texture = view->title_focused_inactive; + } else { + colors = &config->border_colors.unfocused; + title_texture = view->title_unfocused; + } + + if (view->sway_view->border == B_NORMAL) { + render_container_simple_border_normal(output, view, + colors, title_texture); + } else { + render_container_simple_border_pixel(output, view, colors); + } + } + render_view(view->sway_view, output); +} + /** * Render a container's children using a L_HORIZ or L_VERT layout. * @@ -391,35 +419,10 @@ static void render_container(struct sway_output *output, */ static void render_container_simple(struct sway_output *output, struct sway_container *con) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - for (int i = 0; i < con->children->length; ++i) { struct sway_container *child = con->children->items[i]; - if (child->type == C_VIEW) { - if (child->sway_view->border != B_NONE) { - struct border_colors *colors; - struct wlr_texture *title_texture; - if (focus == child) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - } else if (seat_get_focus_inactive(seat, con) == child) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - } - - if (child->sway_view->border == B_NORMAL) { - render_container_simple_border_normal(output, child, - colors, title_texture); - } else { - render_container_simple_border_pixel(output, child, colors); - } - } - render_view(child->sway_view, output); + render_view_with_border(output, child); } else { render_container(output, child); } @@ -456,9 +459,6 @@ static void render_container(struct sway_output *output, case L_TABBED: render_container_tabbed(output, con); break; - case L_FLOATING: - // TODO - break; } } @@ -523,6 +523,14 @@ static void render_output(struct sway_output *output, struct timespec *when, render_container(output, workspace); + // TODO: iterate over all floating views of all active workspaces and + // render them in layout space + for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) { + struct sway_container *c = + workspace->sway_workspace->floating->items[0]; + render_view_with_border(output, c); + } + render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); } @@ -600,6 +608,12 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { struct sway_container *workspace = output_get_active_workspace(output); send_frame_done_container(&data, workspace); + for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) { + struct sway_container *c = + workspace->sway_workspace->floating->items[0]; + send_frame_done_container_iterator(c, &data); + } + send_frame_done_unmanaged(&data, &root_container.sway_root->xwayland_unmanaged); diff --git a/sway/ipc-json.c b/sway/ipc-json.c index ea7fd9ad9..3d4618b39 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -21,8 +21,6 @@ static const char *ipc_json_layout_description(enum sway_container_layout l) { return "tabbed"; case L_STACKED: return "stacked"; - case L_FLOATING: - return "floating"; case L_NONE: break; } diff --git a/sway/meson.build b/sway/meson.build index f70a8e445..2135cb4e1 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -40,6 +40,7 @@ sway_sources = files( 'commands/focus_follows_mouse.c', 'commands/font.c', 'commands/for_window.c', + 'commands/floating.c', 'commands/fullscreen.c', 'commands/kill.c', 'commands/opacity.c', diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ec1c6fe5b..92301dcf6 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -142,16 +142,51 @@ struct sway_container *container_remove_child(struct sway_container *child) { } struct sway_container *parent = child->parent; - for (int i = 0; i < parent->children->length; ++i) { - if (parent->children->items[i] == child) { - list_del(parent->children, i); - break; + if (!child->is_floating) { + for (int i = 0; i < parent->children->length; ++i) { + if (parent->children->items[i] == child) { + list_del(parent->children, i); + break; + } } + } else { + if (!sway_assert(parent->type == C_WORKSPACE && child->type == C_VIEW, + "Found floating non-view and/or in non-workspace")) { + return parent; + } + struct sway_workspace *ws = parent->sway_workspace; + for (int i = 0; i < ws->floating->length; ++i) { + if (ws->floating->items[i] == child) { + list_del(ws->floating, i); + break; + } + } + child->is_floating = false; } child->parent = NULL; return parent; } +void container_add_floating(struct sway_container *workspace, + struct sway_container *child) { + if (!sway_assert(workspace->type == C_WORKSPACE && child->type == C_VIEW, + "Attempted to float non-view and/or in non-workspace")) { + return; + } + if (!sway_assert(!child->parent, + "child already has a parent (invalid call)")) { + return; + } + if (!sway_assert(!child->is_floating, + "child is already floating (invalid state)")) { + return; + } + struct sway_workspace *ws = workspace->sway_workspace; + list_add(ws->floating, child); + child->parent = workspace; + child->is_floating = true; +} + void container_move_to(struct sway_container *container, struct sway_container *destination) { if (container == destination diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index f34baa9ee..c4f8ac5ee 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -12,6 +12,7 @@ #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/workspace.h" +#include "list.h" #include "log.h" #include "util.h" @@ -64,6 +65,7 @@ struct sway_container *workspace_create(struct sway_container *output, return NULL; } swayws->swayc = workspace; + swayws->floating = create_list(); workspace->sway_workspace = swayws; container_add_child(output, workspace);