diff options
Diffstat (limited to 'sway/tree')
| -rw-r--r-- | sway/tree/container.c | 45 | ||||
| -rw-r--r-- | sway/tree/layout.c | 11 | ||||
| -rw-r--r-- | sway/tree/view.c | 96 | ||||
| -rw-r--r-- | sway/tree/workspace.c | 11 | 
4 files changed, 137 insertions, 26 deletions
| diff --git a/sway/tree/container.c b/sway/tree/container.c index 35f67cce..3f9d701a 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -674,16 +674,23 @@ struct sway_container *floating_container_at(double lx, double ly,  void container_for_each_descendant_dfs(struct sway_container *container,  		void (*f)(struct sway_container *container, void *data),  		void *data) { -	if (container) { -		if (container->children)  { -			for (int i = 0; i < container->children->length; ++i) { -				struct sway_container *child = -					container->children->items[i]; -				container_for_each_descendant_dfs(child, f, data); -			} +	if (!container) { +		return; +	} +	if (container->children)  { +		for (int i = 0; i < container->children->length; ++i) { +			struct sway_container *child = container->children->items[i]; +			container_for_each_descendant_dfs(child, f, data);  		} -		f(container, data);  	} +	if (container->type == C_WORKSPACE)  { +		struct sway_container *floating = container->sway_workspace->floating; +		for (int i = 0; i < floating->children->length; ++i) { +			struct sway_container *child = floating->children->items[i]; +			container_for_each_descendant_dfs(child, f, data); +		} +	} +	f(container, data);  }  void container_for_each_descendant_bfs(struct sway_container *con, @@ -960,9 +967,14 @@ void container_set_geometry_from_floating_view(struct sway_container *con) {  		return;  	}  	struct sway_view *view = con->sway_view; -	size_t border_width = view->border_thickness * (view->border != B_NONE); -	size_t top = -		view->border == B_NORMAL ? container_titlebar_height() : border_width; +	size_t border_width = 0; +	size_t top = 0; + +	if (!view->using_csd) { +		border_width = view->border_thickness * (view->border != B_NONE); +		top = view->border == B_NORMAL ? +			container_titlebar_height() : border_width; +	}  	con->x = view->x - border_width;  	con->y = view->y - top; @@ -1063,6 +1075,8 @@ void container_floating_move_to(struct sway_container *con,  		container_add_child(new_workspace->sway_workspace->floating, con);  		arrange_windows(old_workspace);  		arrange_windows(new_workspace); +		workspace_detect_urgent(old_workspace); +		workspace_detect_urgent(new_workspace);  	}  } @@ -1073,3 +1087,12 @@ void container_set_dirty(struct sway_container *container) {  	container->dirty = true;  	list_add(server.dirty_containers, container);  } + +static bool find_urgent_iterator(struct sway_container *con, +		void *data) { +	return con->type == C_VIEW && view_is_urgent(con->sway_view); +} + +bool container_has_urgent_child(struct sway_container *container) { +	return container_find(container, find_urgent_iterator, NULL); +} diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 54ddb3f9..197a2fc8 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -225,6 +225,15 @@ void container_move_to(struct sway_container *container,  			}  		}  	} +	// Update workspace urgent state +	struct sway_container *old_workspace = old_parent; +	if (old_workspace->type != C_WORKSPACE) { +		old_workspace = container_parent(old_workspace, C_WORKSPACE); +	} +	if (new_workspace != old_workspace) { +		workspace_detect_urgent(new_workspace); +		workspace_detect_urgent(old_workspace); +	}  }  static bool sway_dir_to_wlr(enum movement_direction dir, @@ -548,6 +557,8 @@ void container_move(struct sway_container *container,  	}  	if (last_ws && next_ws && last_ws != next_ws) {  		ipc_event_workspace(last_ws, container, "focus"); +		workspace_detect_urgent(last_ws); +		workspace_detect_urgent(next_ws);  	}  } diff --git a/sway/tree/view.c b/sway/tree/view.c index bf380d98..fc31699c 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -25,6 +25,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,  	view->impl = impl;  	view->executed_criteria = create_list();  	view->marks = create_list(); +	view->allow_request_urgent = true;  	wl_signal_init(&view->events.unmap);  } @@ -315,11 +316,15 @@ void view_set_activated(struct sway_view *view, bool activated) {  }  void view_set_tiled(struct sway_view *view, bool tiled) { -	bool csd = true; -	if (view->impl->has_client_side_decorations) { -		csd = view->impl->has_client_side_decorations(view); +	if (!tiled) { +		view->using_csd = true; +		if (view->impl->has_client_side_decorations) { +			view->using_csd = view->impl->has_client_side_decorations(view); +		} +	} else { +		view->using_csd = false;  	} -	view->border = tiled || !csd ? config->border : B_NONE; +  	if (view->impl->set_tiled) {  		view->impl->set_tiled(view, tiled);  	} @@ -504,20 +509,38 @@ 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); +		seat_set_focus(seat, view->swayc);  		list_add(view->executed_criteria, criteria);  		struct cmd_results *res = execute_command(criteria->cmdlist, NULL);  		if (res->status != CMD_SUCCESS) {  			wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error);  		}  		free_cmd_results(res); -		// view must be focused for commands to affect it, -		// so always refocus in-between command lists -		seat_set_focus(seat, view->swayc);  	}  	list_free(criterias);  	seat_set_focus(seat, prior_focus);  } +static bool should_focus(struct sway_view *view) { +	// If the view is the only one in the focused workspace, it'll get focus +	// regardless of any no_focus criteria. +	struct sway_container *parent = view->swayc->parent; +	struct sway_seat *seat = input_manager_current_seat(input_manager); +	if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) { +		size_t num_children = parent->children->length + +			parent->sway_workspace->floating->children->length; +		if (num_children == 1) { +			return true; +		} +	} + +	// Check no_focus criteria +	list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); +	size_t len = criterias->length; +	list_free(criterias); +	return len == 0; +} +  void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  	if (!sway_assert(view->surface == NULL, "cannot map mapped view")) {  		return; @@ -554,8 +577,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  	view->surface = wlr_surface;  	view->swayc = cont; -	view->border = config->border; -	view->border_thickness = config->border_thickness;  	view_init_subsurfaces(view, wlr_surface);  	wl_signal_add(&wlr_surface->events.new_subsurface, @@ -566,14 +587,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  	view->container_reparent.notify = view_handle_container_reparent;  	if (view->impl->wants_floating && view->impl->wants_floating(view)) { +		view->border = config->floating_border; +		view->border_thickness = config->floating_border_thickness;  		container_set_floating(view->swayc, true);  	} else { +		view->border = config->border; +		view->border_thickness = config->border_thickness;  		view_set_tiled(view, true);  	} -	input_manager_set_focus(input_manager, cont); -	if (workspace) { -		workspace_switch(workspace); +	if (should_focus(view)) { +		input_manager_set_focus(input_manager, cont); +		if (workspace) { +			workspace_switch(workspace); +		}  	}  	view_update_title(view, false); @@ -589,16 +616,26 @@ void view_unmap(struct sway_view *view) {  	wl_list_remove(&view->surface_new_subsurface.link);  	wl_list_remove(&view->container_reparent.link); +	if (view->urgent_timer) { +		wl_event_source_remove(view->urgent_timer); +		view->urgent_timer = NULL; +	} + +	struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + +	struct sway_container *parent;  	if (view->is_fullscreen) { -		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);  		ws->sway_workspace->fullscreen = NULL; -		container_destroy(view->swayc); +		parent = container_destroy(view->swayc);  		arrange_windows(ws->parent);  	} else { -		struct sway_container *parent = container_destroy(view->swayc); +		parent = container_destroy(view->swayc);  		arrange_windows(parent);  	} +	if (parent->type >= C_WORKSPACE) { // if the workspace still exists +		workspace_detect_urgent(ws); +	}  	transaction_commit_dirty();  	view->surface = NULL;  } @@ -1047,3 +1084,32 @@ bool view_is_visible(struct sway_view *view) {  	}  	return true;  } + +void view_set_urgent(struct sway_view *view, bool enable) { +	if (view_is_urgent(view) == enable) { +		return; +	} +	if (enable) { +		struct sway_seat *seat = input_manager_current_seat(input_manager); +		if (seat_get_focus(seat) == view->swayc) { +			return; +		} +		clock_gettime(CLOCK_MONOTONIC, &view->urgent); +	} else { +		view->urgent = (struct timespec){ 0 }; +		if (view->urgent_timer) { +			wl_event_source_remove(view->urgent_timer); +			view->urgent_timer = NULL; +		} +	} +	container_damage_whole(view->swayc); + +	ipc_event_window(view->swayc, "urgent"); + +	struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); +	workspace_detect_urgent(ws); +} + +bool view_is_urgent(struct sway_view *view) { +	return view->urgent.tv_sec || view->urgent.tv_nsec; +} diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 2a2d834a..622f01ec 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -11,6 +11,7 @@  #include "sway/ipc-server.h"  #include "sway/tree/arrange.h"  #include "sway/tree/container.h" +#include "sway/tree/view.h"  #include "sway/tree/workspace.h"  #include "list.h"  #include "log.h" @@ -518,3 +519,13 @@ struct sway_container *workspace_output_get_highest_available(  	return NULL;  } + +void workspace_detect_urgent(struct sway_container *workspace) { +	bool new_urgent = container_has_urgent_child(workspace); + +	if (workspace->sway_workspace->urgent != new_urgent) { +		workspace->sway_workspace->urgent = new_urgent; +		ipc_event_workspace(NULL, workspace, "urgent"); +		container_damage_whole(workspace); +	} +} | 
