|  |  |  | @ -10,6 +10,7 @@ | 
			
		
	
		
			
				
					|  |  |  |  | #include "sway/layout.h" | 
			
		
	
		
			
				
					|  |  |  |  | #include "sway/output.h" | 
			
		
	
		
			
				
					|  |  |  |  | #include "sway/view.h" | 
			
		
	
		
			
				
					|  |  |  |  | #include "sway/input/seat.h" | 
			
		
	
		
			
				
					|  |  |  |  | #include "list.h" | 
			
		
	
		
			
				
					|  |  |  |  | #include "log.h" | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -346,3 +347,176 @@ void apply_vert_layout(swayc_t *container, | 
			
		
	
		
			
				
					|  |  |  |  | 		*/ | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | /**
 | 
			
		
	
		
			
				
					|  |  |  |  |  * Get swayc in the direction of newly entered output. | 
			
		
	
		
			
				
					|  |  |  |  |  */ | 
			
		
	
		
			
				
					|  |  |  |  | static swayc_t *get_swayc_in_output_direction(swayc_t *output, | 
			
		
	
		
			
				
					|  |  |  |  | 		enum movement_direction dir, struct sway_seat *seat) { | 
			
		
	
		
			
				
					|  |  |  |  | 	// XXX is this really a seat function or can we do it with the default
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// seat?
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (!output) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	swayc_t *ws = sway_seat_get_focus_inactive(seat, output); | 
			
		
	
		
			
				
					|  |  |  |  | 	if (ws->type != C_WORKSPACE) { | 
			
		
	
		
			
				
					|  |  |  |  | 		ws = swayc_parent_by_type(ws, C_WORKSPACE); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (ws && ws->children->length > 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 		switch (dir) { | 
			
		
	
		
			
				
					|  |  |  |  | 		case MOVE_LEFT: | 
			
		
	
		
			
				
					|  |  |  |  | 			// get most right child of new output
 | 
			
		
	
		
			
				
					|  |  |  |  | 			return ws->children->items[ws->children->length-1]; | 
			
		
	
		
			
				
					|  |  |  |  | 		case MOVE_RIGHT: | 
			
		
	
		
			
				
					|  |  |  |  | 			// get most left child of new output
 | 
			
		
	
		
			
				
					|  |  |  |  | 			return ws->children->items[0]; | 
			
		
	
		
			
				
					|  |  |  |  | 		case MOVE_UP: | 
			
		
	
		
			
				
					|  |  |  |  | 		case MOVE_DOWN: | 
			
		
	
		
			
				
					|  |  |  |  | 			{ | 
			
		
	
		
			
				
					|  |  |  |  | 				swayc_t *focused = sway_seat_get_focus_inactive(seat, ws); | 
			
		
	
		
			
				
					|  |  |  |  | 				if (focused && focused->parent) { | 
			
		
	
		
			
				
					|  |  |  |  | 					swayc_t *parent = focused->parent; | 
			
		
	
		
			
				
					|  |  |  |  | 					if (parent->layout == L_VERT) { | 
			
		
	
		
			
				
					|  |  |  |  | 						if (dir == MOVE_UP) { | 
			
		
	
		
			
				
					|  |  |  |  | 							// get child furthest down on new output
 | 
			
		
	
		
			
				
					|  |  |  |  | 							return parent->children->items[parent->children->length-1]; | 
			
		
	
		
			
				
					|  |  |  |  | 						} else if (dir == MOVE_DOWN) { | 
			
		
	
		
			
				
					|  |  |  |  | 							// get child furthest up on new output
 | 
			
		
	
		
			
				
					|  |  |  |  | 							return parent->children->items[0]; | 
			
		
	
		
			
				
					|  |  |  |  | 						} | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 					return focused; | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		default: | 
			
		
	
		
			
				
					|  |  |  |  | 			break; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	return output; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static void get_absolute_center_position(swayc_t *container, int *x, int *y) { | 
			
		
	
		
			
				
					|  |  |  |  | 	*x = container->x + container->width/2; | 
			
		
	
		
			
				
					|  |  |  |  | 	*y = container->y + container->height/2; | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | static swayc_t *get_swayc_in_direction_under(swayc_t *container, | 
			
		
	
		
			
				
					|  |  |  |  | 		enum movement_direction dir, struct sway_seat *seat, swayc_t *limit) { | 
			
		
	
		
			
				
					|  |  |  |  | 	if (dir == MOVE_CHILD) { | 
			
		
	
		
			
				
					|  |  |  |  | 		return sway_seat_get_focus_inactive(seat, container); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	swayc_t *parent = container->parent; | 
			
		
	
		
			
				
					|  |  |  |  | 	if (dir == MOVE_PARENT) { | 
			
		
	
		
			
				
					|  |  |  |  | 		if (parent->type == C_OUTPUT) { | 
			
		
	
		
			
				
					|  |  |  |  | 			return NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			return parent; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (dir == MOVE_PREV || dir == MOVE_NEXT) { | 
			
		
	
		
			
				
					|  |  |  |  | 		int focused_idx = index_child(container); | 
			
		
	
		
			
				
					|  |  |  |  | 		if (focused_idx == -1) { | 
			
		
	
		
			
				
					|  |  |  |  | 			return NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % | 
			
		
	
		
			
				
					|  |  |  |  | 				parent->children->length; | 
			
		
	
		
			
				
					|  |  |  |  | 			if (desired < 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 				desired += parent->children->length; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			return parent->children->items[desired]; | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// If moving to an adjacent output we need a starting position (since this
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// output might border to multiple outputs).
 | 
			
		
	
		
			
				
					|  |  |  |  | 	//struct wlc_point abs_pos;
 | 
			
		
	
		
			
				
					|  |  |  |  | 	//get_absolute_center_position(container, &abs_pos);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	// TODO WLR fullscreen
 | 
			
		
	
		
			
				
					|  |  |  |  | 	/*
 | 
			
		
	
		
			
				
					|  |  |  |  | 	if (container->type == C_VIEW && swayc_is_fullscreen(container)) { | 
			
		
	
		
			
				
					|  |  |  |  | 		wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output"); | 
			
		
	
		
			
				
					|  |  |  |  | 		container = swayc_parent_by_type(container, C_OUTPUT); | 
			
		
	
		
			
				
					|  |  |  |  | 		get_absolute_center_position(container, &abs_pos); | 
			
		
	
		
			
				
					|  |  |  |  | 		swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true); | 
			
		
	
		
			
				
					|  |  |  |  | 		return get_swayc_in_output_direction(output, dir); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	if (container->type == C_WORKSPACE && container->fullscreen) { | 
			
		
	
		
			
				
					|  |  |  |  | 		sway_log(L_DEBUG, "Moving to fullscreen view"); | 
			
		
	
		
			
				
					|  |  |  |  | 		return container->fullscreen; | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | 	*/ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 	swayc_t *wrap_candidate = NULL; | 
			
		
	
		
			
				
					|  |  |  |  | 	while (true) { | 
			
		
	
		
			
				
					|  |  |  |  | 		// Test if we can even make a difference here
 | 
			
		
	
		
			
				
					|  |  |  |  | 		bool can_move = false; | 
			
		
	
		
			
				
					|  |  |  |  | 		int desired; | 
			
		
	
		
			
				
					|  |  |  |  | 		int idx = index_child(container); | 
			
		
	
		
			
				
					|  |  |  |  | 		if (parent->type == C_ROOT) { | 
			
		
	
		
			
				
					|  |  |  |  | 			struct wlr_output_layout *layout = root_container.sway_root->output_layout; | 
			
		
	
		
			
				
					|  |  |  |  | 			wlr_output_layout_adjacent_output(layout, container->sway_output->wlr_output); | 
			
		
	
		
			
				
					|  |  |  |  | 			//swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true);
 | 
			
		
	
		
			
				
					|  |  |  |  | 			if (!output || output == container) { | 
			
		
	
		
			
				
					|  |  |  |  | 				return wrap_candidate; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 			wlr_log(L_DEBUG, "Moving between outputs"); | 
			
		
	
		
			
				
					|  |  |  |  | 			return get_swayc_in_output_direction(output, dir, seat); | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { | 
			
		
	
		
			
				
					|  |  |  |  | 			if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { | 
			
		
	
		
			
				
					|  |  |  |  | 				if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { | 
			
		
	
		
			
				
					|  |  |  |  | 					can_move = true; | 
			
		
	
		
			
				
					|  |  |  |  | 					desired = idx + (dir == MOVE_LEFT ? -1 : 1); | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  |  | 				if (parent->layout == L_VERT || parent->layout == L_STACKED) { | 
			
		
	
		
			
				
					|  |  |  |  | 					can_move = true; | 
			
		
	
		
			
				
					|  |  |  |  | 					desired = idx + (dir == MOVE_UP ? -1 : 1); | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (can_move) { | 
			
		
	
		
			
				
					|  |  |  |  | 			// TODO handle floating
 | 
			
		
	
		
			
				
					|  |  |  |  | 			if (desired < 0 || desired >= parent->children->length) { | 
			
		
	
		
			
				
					|  |  |  |  | 				can_move = false; | 
			
		
	
		
			
				
					|  |  |  |  | 				int len = parent->children->length; | 
			
		
	
		
			
				
					|  |  |  |  | 				if (!wrap_candidate && len > 1) { | 
			
		
	
		
			
				
					|  |  |  |  | 					if (desired < 0) { | 
			
		
	
		
			
				
					|  |  |  |  | 						wrap_candidate = parent->children->items[len-1]; | 
			
		
	
		
			
				
					|  |  |  |  | 					} else { | 
			
		
	
		
			
				
					|  |  |  |  | 						wrap_candidate = parent->children->items[0]; | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 					if (config->force_focus_wrapping) { | 
			
		
	
		
			
				
					|  |  |  |  | 						return wrap_candidate; | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  |  | 				wlr_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__, | 
			
		
	
		
			
				
					|  |  |  |  | 						idx, container, dir, desired, parent->children->items[desired]); | 
			
		
	
		
			
				
					|  |  |  |  | 				return parent->children->items[desired]; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if (!can_move) { | 
			
		
	
		
			
				
					|  |  |  |  | 			container = parent; | 
			
		
	
		
			
				
					|  |  |  |  | 			parent = parent->parent; | 
			
		
	
		
			
				
					|  |  |  |  | 			if (!parent || container == limit) { | 
			
		
	
		
			
				
					|  |  |  |  | 				// wrapping is the last chance
 | 
			
		
	
		
			
				
					|  |  |  |  | 				return wrap_candidate; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | swayc_t *get_swayc_in_direction(swayc_t *container, struct sway_seat *seat, | 
			
		
	
		
			
				
					|  |  |  |  | 		enum movement_direction dir) { | 
			
		
	
		
			
				
					|  |  |  |  | 	return get_swayc_in_direction_under(container, dir, seat, NULL); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |