diff options
Diffstat (limited to 'sway/tree')
-rw-r--r-- | sway/tree/container.c | 52 | ||||
-rw-r--r-- | sway/tree/output.c | 18 | ||||
-rw-r--r-- | sway/tree/root.c | 46 | ||||
-rw-r--r-- | sway/tree/view.c | 109 | ||||
-rw-r--r-- | sway/tree/workspace.c | 44 |
5 files changed, 185 insertions, 84 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c index cf6f5b54..d9c721f5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -21,6 +21,7 @@ #include "sway/tree/arrange.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" +#include "list.h" #include "log.h" #include "stringop.h" @@ -67,8 +68,7 @@ void container_destroy(struct sway_container *con) { list_free(con->current.children); list_free(con->outputs); - list_foreach(con->marks, free); - list_free(con->marks); + list_free_items_and_destroy(con->marks); wlr_texture_destroy(con->marks_focused); wlr_texture_destroy(con->marks_focused_inactive); wlr_texture_destroy(con->marks_unfocused); @@ -453,19 +453,26 @@ static void update_title_texture(struct sway_container *con, int width = 0; int height = con->title_height * scale; - cairo_t *c = cairo_create(NULL); + // We must use a non-nil cairo_t for cairo_set_font_options to work. + // Therefore, we cannot use cairo_create(NULL). + cairo_surface_t *dummy_surface = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, 0, 0); + cairo_t *c = cairo_create(dummy_surface); + cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST); + cairo_font_options_t *fo = cairo_font_options_create(); + cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); + cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->wlr_output->subpixel)); + cairo_set_font_options(c, fo); get_text_size(c, config->font, &width, NULL, NULL, scale, config->pango_markup, "%s", con->formatted_title); + cairo_surface_destroy(dummy_surface); cairo_destroy(c); cairo_surface_t *surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height); cairo_t *cairo = cairo_create(surface); cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); - cairo_font_options_t *fo = cairo_font_options_create(); - cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); - cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); - cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->wlr_output->subpixel)); cairo_set_font_options(cairo, fo); cairo_font_options_destroy(fo); cairo_set_source_rgba(cairo, class->background[0], class->background[1], @@ -594,7 +601,7 @@ void container_update_representation(struct sway_container *con) { } size_t container_titlebar_height(void) { - return config->font_height + TITLEBAR_V_PADDING * 2; + return config->font_height + config->titlebar_v_padding * 2; } void container_init_floating(struct sway_container *con) { @@ -857,15 +864,7 @@ bool container_has_urgent_child(struct sway_container *container) { void container_end_mouse_operation(struct sway_container *container) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { - if (seat->op_container == container) { - seat->op_target_node = NULL; // ensure tiling move doesn't apply - seat_end_mouse_operation(seat); - } - // If the user is doing a tiling drag over this container, - // keep the operation active but unset the target container. - if (seat->op_target_node == &container->node) { - seat->op_target_node = NULL; - } + seatop_unref(seat, container); } } @@ -979,7 +978,7 @@ void container_discover_outputs(struct sway_container *con) { output_get_box(output, &output_box); struct wlr_box intersection; bool intersects = - wlr_box_intersection(&con_box, &output_box, &intersection); + wlr_box_intersection(&intersection, &con_box, &output_box); int index = list_find(con->outputs, output); if (intersects && index == -1) { @@ -1267,7 +1266,9 @@ bool container_find_and_unmark(char *mark) { } void container_clear_marks(struct sway_container *con) { - list_foreach(con->marks, free); + for (int i = 0; i < con->marks->length; ++i) { + free(con->marks->items[i]); + } con->marks->length = 0; ipc_event_window(con, "mark"); } @@ -1375,3 +1376,16 @@ void container_update_marks_textures(struct sway_container *con) { &config->border_colors.urgent); container_damage_whole(con); } + +void container_raise_floating(struct sway_container *con) { + // Bring container to front by putting it at the end of the floating list. + struct sway_container *floater = con; + while (floater->parent) { + floater = floater->parent; + } + if (container_is_floating(floater)) { + list_move_to_end(floater->workspace->floating, floater); + node_set_dirty(&floater->workspace->node); + } +} + diff --git a/sway/tree/output.c b/sway/tree/output.c index 3c4614a8..f24be010 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -58,6 +58,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) { wlr_output->data = output; wl_signal_add(&wlr_output->events.destroy, &output->destroy); + wl_signal_init(&output->events.destroy); wl_list_insert(&root->all_outputs, &output->link); @@ -76,7 +77,6 @@ void output_enable(struct sway_output *output, struct output_config *oc) { for (size_t i = 0; i < len; ++i) { wl_list_init(&output->layers[i]); } - wl_signal_init(&output->events.destroy); output->enabled = true; list_add(root->outputs, output); @@ -88,11 +88,12 @@ void output_enable(struct sway_output *output, struct output_config *oc) { restore_workspaces(output); + struct sway_workspace *ws = NULL; if (!output->workspaces->length) { // Create workspace char *ws_name = workspace_next_name(wlr_output->name); wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); - struct sway_workspace *ws = workspace_create(output, ws_name); + ws = workspace_create(output, ws_name); // Set each seat's focus if not already set struct sway_seat *seat = NULL; wl_list_for_each(seat, &server.input->seats, link) { @@ -104,9 +105,15 @@ void output_enable(struct sway_output *output, struct output_config *oc) { ipc_event_workspace(NULL, ws, "init"); } - apply_output_config(oc, output); + if (ws && config->default_orientation == L_NONE) { + // Since the output transformation and resolution could have changed + // due to applying the output config, the previously set layout for the + // created workspace may not be correct for `default_orientation auto` + ws->layout = output_get_default_layout(output); + } + input_manager_configure_xcursor(); wl_signal_add(&wlr_output->events.mode, &output->mode); @@ -218,6 +225,11 @@ void output_disable(struct sway_output *output) { root_for_each_container(untrack_output, output); + if (output->bg_pid) { + terminate_swaybg(output->bg_pid); + output->bg_pid = 0; + } + int index = list_find(root->outputs, output); list_del(root->outputs, index); diff --git a/sway/tree/root.c b/sway/tree/root.c index 544d666a..e1624863 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -5,6 +5,7 @@ #include <wlr/types/wlr_output_layout.h> #include "sway/desktop/transaction.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" @@ -68,13 +69,18 @@ void root_scratchpad_add_container(struct sway_container *con) { list_add(root->scratchpad, con); struct sway_seat *seat = input_manager_current_seat(); + struct sway_node *new_focus = NULL; if (parent) { arrange_container(parent); - seat_set_focus(seat, seat_get_focus_inactive(seat, &parent->node)); - } else { + new_focus = seat_get_focus_inactive(seat, &parent->node); + } + if (!new_focus) { arrange_workspace(workspace); - seat_set_focus(seat, seat_get_focus_inactive(seat, &workspace->node)); + new_focus = seat_get_focus_inactive(seat, &workspace->node); } + seat_set_focus(seat, new_focus); + + ipc_event_window(con, "move"); } void root_scratchpad_remove_container(struct sway_container *con) { @@ -85,45 +91,51 @@ void root_scratchpad_remove_container(struct sway_container *con) { int index = list_find(root->scratchpad, con); if (index != -1) { list_del(root->scratchpad, index); + ipc_event_window(con, "move"); } } void root_scratchpad_show(struct sway_container *con) { struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *ws = seat_get_focused_workspace(seat); + struct sway_workspace *new_ws = seat_get_focused_workspace(seat); + struct sway_workspace *old_ws = con->workspace; - // If the current con or any of its parents are in fullscreen mode, we - // first need to disable it before showing the scratchpad con. - if (ws->fullscreen) { - container_set_fullscreen(ws->fullscreen, false); + // If the current con or any of its parents are in fullscreen mode, we + // first need to disable it before showing the scratchpad con. + if (new_ws->fullscreen) { + container_set_fullscreen(new_ws->fullscreen, false); } // Show the container - if (con->workspace) { + if (old_ws) { container_detach(con); } - workspace_add_floating(ws, con); + workspace_add_floating(new_ws, con); // Make sure the container's center point overlaps this workspace double center_lx = con->x + con->width / 2; double center_ly = con->y + con->height / 2; struct wlr_box workspace_box; - workspace_get_box(ws, &workspace_box); + workspace_get_box(new_ws, &workspace_box); if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { // Maybe resize it - if (con->width > ws->width || con->height > ws->height) { + if (con->width > new_ws->width || con->height > new_ws->height) { container_init_floating(con); } // Center it - double new_lx = ws->x + (ws->width - con->width) / 2; - double new_ly = ws->y + (ws->height - con->height) / 2; + double new_lx = new_ws->x + (new_ws->width - con->width) / 2; + double new_ly = new_ws->y + (new_ws->height - con->height) / 2; container_floating_move_to(con, new_lx, new_ly); } - arrange_workspace(ws); + arrange_workspace(new_ws); seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node)); + + if (new_ws != old_ws) { + ipc_event_window(con, "move"); + } } void root_scratchpad_hide(struct sway_container *con) { @@ -133,10 +145,12 @@ void root_scratchpad_hide(struct sway_container *con) { container_detach(con); arrange_workspace(ws); - if (&con->node == focus) { + if (&con->node == focus || node_has_ancestor(focus, &con->node)) { seat_set_focus(seat, seat_get_focus_inactive(seat, &ws->node)); } list_move_to_end(root->scratchpad, con); + + ipc_event_window(con, "move"); } struct pid_workspace { diff --git a/sway/tree/view.c b/sway/tree/view.c index d7110619..5371ee20 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -437,9 +437,14 @@ void view_execute_criteria(struct sway_view *view) { wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", criteria->raw, view, criteria->cmdlist); list_add(view->executed_criteria, criteria); - struct cmd_results *res = execute_command( + list_t *res_list = execute_command( criteria->cmdlist, NULL, view->container); - free_cmd_results(res); + while (res_list->length) { + struct cmd_results *res = res_list->items[0]; + free_cmd_results(res); + list_del(res_list, 0); + } + list_free(res_list); } list_free(criterias); } @@ -454,7 +459,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) { for (int i = 0; i < criterias->length; ++i) { struct criteria *criteria = criterias->items[i]; if (criteria->type == CT_ASSIGN_OUTPUT) { - struct sway_output *output = output_by_name(criteria->target); + struct sway_output *output = output_by_name_or_id(criteria->target); if (output) { ws = output_get_active_workspace(output); break; @@ -600,7 +605,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, view_update_title(view, false); container_update_representation(view->container); - view_execute_criteria(view); if (decoration) { view_update_csd_from_client(view, decoration); @@ -617,6 +621,8 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, } } + view_execute_criteria(view); + if (should_focus(view)) { input_manager_set_focus(&view->container->node); } @@ -648,14 +654,8 @@ void view_unmap(struct sway_view *view) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { - if (config->mouse_warping == WARP_CONTAINER) { - struct sway_node *node = seat_get_focus(seat); - if (node && node->type == N_CONTAINER) { - cursor_warp_to_container(seat->cursor, node->sway_container); - } else if (node && node->type == N_WORKSPACE) { - cursor_warp_to_workspace(seat->cursor, node->sway_workspace); - } - } + seat->cursor->image_surface = NULL; + seat_consider_warp_to_focus(seat); } transaction_commit_dirty(); @@ -674,6 +674,8 @@ void view_update_size(struct sway_view *view, int width, int height) { container_set_geometry_from_content(view->container); } +static const struct sway_view_child_impl subsurface_impl; + static void subsurface_get_root_coords(struct sway_view_child *child, int *root_sx, int *root_sy) { struct wlr_surface *surface = child->surface; @@ -689,18 +691,47 @@ static void subsurface_get_root_coords(struct sway_view_child *child, } } +static void subsurface_destroy(struct sway_view_child *child) { + if (!sway_assert(child->impl == &subsurface_impl, + "Expected a subsurface")) { + return; + } + struct sway_subsurface *subsurface = (struct sway_subsurface *)child; + wl_list_remove(&subsurface->destroy.link); + free(subsurface); +} + static const struct sway_view_child_impl subsurface_impl = { .get_root_coords = subsurface_get_root_coords, + .destroy = subsurface_destroy, }; +static void subsurface_handle_destroy(struct wl_listener *listener, + void *data) { + struct sway_subsurface *subsurface = + wl_container_of(listener, subsurface, destroy); + struct sway_view_child *child = &subsurface->child; + view_child_destroy(child); +} + +static void view_child_damage(struct sway_view_child *child, bool whole); + static void view_subsurface_create(struct sway_view *view, - struct wlr_subsurface *subsurface) { - struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); - if (child == NULL) { + struct wlr_subsurface *wlr_subsurface) { + struct sway_subsurface *subsurface = + calloc(1, sizeof(struct sway_subsurface)); + if (subsurface == NULL) { wlr_log(WLR_ERROR, "Allocation failed"); return; } - view_child_init(child, &subsurface_impl, view, subsurface->surface); + view_child_init(&subsurface->child, &subsurface_impl, view, + wlr_subsurface->surface); + + wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); + subsurface->destroy.notify = subsurface_handle_destroy; + + subsurface->child.mapped = true; + view_child_damage(&subsurface->child, true); } static void view_child_damage(struct sway_view_child *child, bool whole) { @@ -745,6 +776,7 @@ static void view_child_handle_surface_map(struct wl_listener *listener, void *data) { struct sway_view_child *child = wl_container_of(listener, child, surface_map); + child->mapped = true; view_child_damage(child, true); } @@ -753,6 +785,7 @@ static void view_child_handle_surface_unmap(struct wl_listener *listener, struct sway_view_child *child = wl_container_of(listener, child, surface_unmap); view_child_damage(child, true); + child->mapped = false; } void view_child_init(struct sway_view_child *child, @@ -771,6 +804,7 @@ void view_child_init(struct sway_view_child *child, wl_signal_add(&surface->events.destroy, &child->surface_destroy); child->surface_destroy.notify = view_child_handle_surface_destroy; + // Not all child views have a map/unmap event child->surface_map.notify = view_child_handle_surface_map; child->surface_unmap.notify = view_child_handle_surface_unmap; @@ -781,6 +815,10 @@ void view_child_init(struct sway_view_child *child, } void view_child_destroy(struct sway_view_child *child) { + if (child->mapped && child->view->container != NULL) { + view_child_damage(child, true); + } + wl_list_remove(&child->surface_commit.link); wl_list_remove(&child->surface_destroy.link); @@ -824,12 +862,29 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { return NULL; } +static char *escape_pango_markup(const char *buffer) { + size_t length = escape_markup_text(buffer, NULL); + char *escaped_title = calloc(length + 1, sizeof(char)); + escape_markup_text(buffer, escaped_title); + return escaped_title; +} + static size_t append_prop(char *buffer, const char *value) { if (!value) { return 0; } - lenient_strcat(buffer, value); - return strlen(value); + // If using pango_markup in font, we need to escape all markup chars + // from values to make sure tags are not inserted by clients + if (config->pango_markup) { + char *escaped_value = escape_pango_markup(value); + lenient_strcat(buffer, escaped_value); + size_t len = strlen(escaped_value); + free(escaped_value); + return len; + } else { + lenient_strcat(buffer, value); + return strlen(value); + } } /** @@ -838,11 +893,7 @@ static size_t append_prop(char *buffer, const char *value) { */ static size_t parse_title_format(struct sway_view *view, char *buffer) { if (!view->title_format || strcmp(view->title_format, "%title") == 0) { - const char *title = view_get_title(view); - if (buffer && title) { - strcpy(buffer, title); - } - return title ? strlen(title) : 0; + return append_prop(buffer, view_get_title(view)); } size_t len = 0; @@ -882,14 +933,6 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) { return len; } -static char *escape_title(char *buffer) { - size_t length = escape_markup_text(buffer, NULL); - char *escaped_title = calloc(length + 1, sizeof(char)); - escape_markup_text(buffer, escaped_title); - free(buffer); - return escaped_title; -} - void view_update_title(struct sway_view *view, bool force) { const char *title = view_get_title(view); @@ -912,10 +955,6 @@ void view_update_title(struct sway_view *view, bool force) { return; } parse_title_format(view, buffer); - // now we have the title, but needs to be escaped when using pango markup - if (config->pango_markup) { - buffer = escape_title(buffer); - } view->container->title = strdup(title); view->container->formatted_title = buffer; diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 4be63311..7f18046d 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -35,10 +35,8 @@ struct sway_output *workspace_get_initial_output(const char *name) { struct workspace_config *wsc = workspace_find_config(name); if (wsc) { for (int i = 0; i < wsc->outputs->length; i++) { - struct sway_output *output = output_by_name(wsc->outputs->items[i]); - if (!output) { - output = output_by_identifier(wsc->outputs->items[i]); - } + struct sway_output *output = + output_by_name_or_id(wsc->outputs->items[i]); if (output) { return output; } @@ -113,7 +111,10 @@ struct sway_workspace *workspace_create(struct sway_output *output, // Add output priorities for (int i = 0; i < wsc->outputs->length; ++i) { - list_add(ws->output_priority, strdup(wsc->outputs->items[i])); + char *name = wsc->outputs->items[i]; + if (strcmp(name, "*") != 0) { + list_add(ws->output_priority, strdup(name)); + } } } } @@ -142,7 +143,7 @@ void workspace_destroy(struct sway_workspace *workspace) { free(workspace->name); free(workspace->representation); - free_flat_list(workspace->output_priority); + list_free_items_and_destroy(workspace->output_priority); list_free(workspace->floating); list_free(workspace->tiling); list_free(workspace->current.floating); @@ -182,7 +183,11 @@ static bool workspace_valid_on_output(const char *output_name, const char *ws_name) { struct workspace_config *wsc = workspace_find_config(ws_name); char identifier[128]; - struct sway_output *output = output_by_name(output_name); + struct sway_output *output = output_by_name_or_id(output_name); + if (!output) { + return false; + } + output_name = output->wlr_output->name; output_get_identifier(identifier, sizeof(identifier), output); if (!wsc) { @@ -190,7 +195,8 @@ static bool workspace_valid_on_output(const char *output_name, } for (int i = 0; i < wsc->outputs->length; i++) { - if (strcmp(wsc->outputs->items[i], output_name) == 0 || + if (strcmp(wsc->outputs->items[i], "*") == 0 || + strcmp(wsc->outputs->items[i], output_name) == 0 || strcmp(wsc->outputs->items[i], identifier) == 0) { return true; } @@ -286,6 +292,14 @@ char *workspace_next_name(const char *output_name) { // assignments primarily, falling back to bindings and numbers. struct sway_mode *mode = config->current_mode; + char identifier[128]; + struct sway_output *output = output_by_name_or_id(output_name); + if (!output) { + return NULL; + } + output_name = output->wlr_output->name; + output_get_identifier(identifier, sizeof(identifier), output); + int order = INT_MAX; char *target = NULL; for (int i = 0; i < mode->keysym_bindings->length; ++i) { @@ -304,7 +318,9 @@ char *workspace_next_name(const char *output_name) { } bool found = false; for (int j = 0; j < wsc->outputs->length; ++j) { - if (strcmp(wsc->outputs->items[j], output_name) == 0) { + if (strcmp(wsc->outputs->items[j], "*") == 0 || + strcmp(wsc->outputs->items[j], output_name) == 0 || + strcmp(wsc->outputs->items[j], identifier) == 0) { found = true; free(target); target = strdup(wsc->workspace); @@ -525,13 +541,19 @@ void workspace_output_add_priority(struct sway_workspace *workspace, struct sway_output *workspace_output_get_highest_available( struct sway_workspace *ws, struct sway_output *exclude) { + char exclude_id[128] = {'\0'}; + if (exclude) { + output_get_identifier(exclude_id, sizeof(exclude_id), exclude); + } + for (int i = 0; i < ws->output_priority->length; i++) { char *name = ws->output_priority->items[i]; - if (exclude && strcasecmp(name, exclude->wlr_output->name) == 0) { + if (exclude && (strcmp(name, exclude->wlr_output->name) == 0 + || strcmp(name, exclude_id) == 0)) { continue; } - struct sway_output *output = output_by_name(name); + struct sway_output *output = output_by_name_or_id(name); if (output) { return output; } |