mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	interactive: allow moving horizontally/vertically maximized window
Applies drag resistance unidirectionally for horizontally/vertically maximized windows, allowing them to be dragged without being untiled immediately. When the distance of cursor movement orthogonal to the maximized direction exceeds <resistance><unMaximizeThreshold>. While dragging a horizontally/vertically maximized window, edge/region snapping is disabled to prevent unintentional snapping and overlays. This commit also includes some refactoring to simplify the logic.
This commit is contained in:
		
							parent
							
								
									2e19bd4d5b
								
							
						
					
					
						commit
						1f1bdad087
					
				
					 11 changed files with 137 additions and 120 deletions
				
			
		| 
						 | 
				
			
			@ -9,58 +9,47 @@
 | 
			
		|||
#include "view.h"
 | 
			
		||||
#include "window-rules.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *   pos_old  pos_cursor
 | 
			
		||||
 *      v         v
 | 
			
		||||
 *      +---------+-------------------+
 | 
			
		||||
 *      <-----------size_old---------->
 | 
			
		||||
 *
 | 
			
		||||
 *      return value
 | 
			
		||||
 *           v
 | 
			
		||||
 *           +----+---------+
 | 
			
		||||
 *           <---size_new--->
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
max_move_scale(double pos_cursor, double pos_current,
 | 
			
		||||
	double size_current, double size_orig)
 | 
			
		||||
max_move_scale(double pos_cursor, double pos_old, double size_old,
 | 
			
		||||
		double size_new)
 | 
			
		||||
{
 | 
			
		||||
	double anchor_frac = (pos_cursor - pos_current) / size_current;
 | 
			
		||||
	int pos_new = pos_cursor - (size_orig * anchor_frac);
 | 
			
		||||
	if (pos_new < pos_current) {
 | 
			
		||||
	double anchor_frac = (pos_cursor - pos_old) / size_old;
 | 
			
		||||
	int pos_new = pos_cursor - (size_new * anchor_frac);
 | 
			
		||||
	if (pos_new < pos_old) {
 | 
			
		||||
		/* Clamp by using the old offsets of the maximized window */
 | 
			
		||||
		pos_new = pos_current;
 | 
			
		||||
		pos_new = pos_old;
 | 
			
		||||
	}
 | 
			
		||||
	return pos_new;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
interactive_anchor_to_cursor(struct view *view, struct wlr_box *geometry,
 | 
			
		||||
		int cursor_x, int cursor_y)
 | 
			
		||||
interactive_anchor_to_cursor(struct server *server, struct wlr_box *geo)
 | 
			
		||||
{
 | 
			
		||||
	geometry->x = max_move_scale(cursor_x, view->current.x,
 | 
			
		||||
		view->current.width, geometry->width);
 | 
			
		||||
	geometry->y = max_move_scale(cursor_y, view->current.y,
 | 
			
		||||
		view->current.height, geometry->height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
interactive_move_tiled_view_to(struct server *server, struct view *view,
 | 
			
		||||
		struct wlr_box *geometry)
 | 
			
		||||
{
 | 
			
		||||
	assert(!view_is_floating(view));
 | 
			
		||||
 | 
			
		||||
	int threshold = rc.unsnap_threshold;
 | 
			
		||||
 | 
			
		||||
	if (server->input_mode == LAB_INPUT_STATE_MOVE) {
 | 
			
		||||
		/* When called from cursor motion handler */
 | 
			
		||||
		assert(server->move_pending && server->grabbed_view == view);
 | 
			
		||||
 | 
			
		||||
		double dx = server->seat.cursor->x - server->grab_x;
 | 
			
		||||
		double dy = server->seat.cursor->y - server->grab_y;
 | 
			
		||||
		if (dx * dx + dy * dy < threshold * threshold) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		/* When called from interactive_begin() */
 | 
			
		||||
		if (threshold > 0) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	assert(server->input_mode == LAB_INPUT_STATE_MOVE);
 | 
			
		||||
	if (wlr_box_empty(geo)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	/* Resize grab_box while anchoring it to grab_box.{x,y} */
 | 
			
		||||
	server->grab_box.x = max_move_scale(server->grab_x, server->grab_box.x,
 | 
			
		||||
		server->grab_box.width, geo->width);
 | 
			
		||||
	server->grab_box.y = max_move_scale(server->grab_y, server->grab_box.y,
 | 
			
		||||
		server->grab_box.height, geo->height);
 | 
			
		||||
	server->grab_box.width = geo->width;
 | 
			
		||||
	server->grab_box.height = geo->height;
 | 
			
		||||
 | 
			
		||||
	view_set_untiled(view);
 | 
			
		||||
	view_restore_to(view, *geometry);
 | 
			
		||||
	server->move_pending = false;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
	geo->x = server->grab_box.x + (server->seat.cursor->x - server->grab_x);
 | 
			
		||||
	geo->y = server->grab_box.y + (server->seat.cursor->y - server->grab_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +62,6 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
 | 
			
		|||
	 */
 | 
			
		||||
	struct server *server = view->server;
 | 
			
		||||
	struct seat *seat = &server->seat;
 | 
			
		||||
	struct wlr_box geometry = view->current;
 | 
			
		||||
 | 
			
		||||
	if (server->input_mode != LAB_INPUT_STATE_PASSTHROUGH) {
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -97,31 +85,7 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
 | 
			
		|||
			 */
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (!view_is_floating(view)) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Un-maximize and restore natural width/height.
 | 
			
		||||
			 * If the natural geometry is unknown (possible
 | 
			
		||||
			 * with xdg-shell views), then we set a size of
 | 
			
		||||
			 * 0x0 here and determine the correct geometry
 | 
			
		||||
			 * later. See do_late_positioning() in xdg.c.
 | 
			
		||||
			 */
 | 
			
		||||
			geometry.width = view->natural_geometry.width;
 | 
			
		||||
			geometry.height = view->natural_geometry.height;
 | 
			
		||||
			if (!wlr_box_empty(&geometry)) {
 | 
			
		||||
				interactive_anchor_to_cursor(view, &geometry,
 | 
			
		||||
					seat->cursor->x, seat->cursor->y);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * If <resistance><unSnapThreshold> is non-zero, the
 | 
			
		||||
			 * tiled/maximized view is un-tiled later in cursor
 | 
			
		||||
			 * motion handler.
 | 
			
		||||
			 */
 | 
			
		||||
			if (!interactive_move_tiled_view_to(
 | 
			
		||||
					server, view, &geometry)) {
 | 
			
		||||
				server->move_pending = true;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
		if (view_is_floating(view)) {
 | 
			
		||||
			/* Store natural geometry at start of move */
 | 
			
		||||
			view_store_natural_geometry(view);
 | 
			
		||||
			view_invalidate_last_layout_geometry(view);
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +115,7 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
 | 
			
		|||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If tiled or maximized in only one direction, reset
 | 
			
		||||
		 * tiled/maximized state but keep the same geometry as
 | 
			
		||||
		 * maximized/tiled state but keep the same geometry as
 | 
			
		||||
		 * the starting point for the resize.
 | 
			
		||||
		 */
 | 
			
		||||
		view_set_untiled(view);
 | 
			
		||||
| 
						 | 
				
			
			@ -168,8 +132,24 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
 | 
			
		|||
	/* Remember view and cursor positions at start of move/resize */
 | 
			
		||||
	server->grab_x = seat->cursor->x;
 | 
			
		||||
	server->grab_y = seat->cursor->y;
 | 
			
		||||
	server->grab_box = geometry;
 | 
			
		||||
	server->grab_box = view->current;
 | 
			
		||||
	server->resize_edges = edges;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Un-tile maximized/tiled view immediately if <unSnapThreshold> is
 | 
			
		||||
	 * zero. Otherwise, un-tile it later in cursor motion handler.
 | 
			
		||||
	 * If the natural geometry is unknown (possible with xdg-shell views),
 | 
			
		||||
	 * then we set a size of 0x0 here and determine the correct geometry
 | 
			
		||||
	 * later. See do_late_positioning() in xdg.c.
 | 
			
		||||
	 */
 | 
			
		||||
	if (mode == LAB_INPUT_STATE_MOVE && !view_is_floating(view)
 | 
			
		||||
			&& rc.unsnap_threshold <= 0) {
 | 
			
		||||
		struct wlr_box natural_geo = view->natural_geometry;
 | 
			
		||||
		interactive_anchor_to_cursor(server, &natural_geo);
 | 
			
		||||
		view_set_untiled(view);
 | 
			
		||||
		view_restore_to(view, natural_geo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rc.resize_indicator) {
 | 
			
		||||
		resize_indicator_show(view);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +161,10 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
 | 
			
		|||
enum view_edge
 | 
			
		||||
edge_from_cursor(struct seat *seat, struct output **dest_output)
 | 
			
		||||
{
 | 
			
		||||
	if (!view_is_floating(seat->server->grabbed_view)) {
 | 
			
		||||
		return VIEW_EDGE_INVALID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int snap_range = rc.snap_edge_range;
 | 
			
		||||
	if (!snap_range) {
 | 
			
		||||
		return VIEW_EDGE_INVALID;
 | 
			
		||||
| 
						 | 
				
			
			@ -296,7 +280,6 @@ interactive_cancel(struct view *view)
 | 
			
		|||
 | 
			
		||||
	view->server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
 | 
			
		||||
	view->server->grabbed_view = NULL;
 | 
			
		||||
	view->server->move_pending = false;
 | 
			
		||||
 | 
			
		||||
	/* Update focus/cursor image */
 | 
			
		||||
	cursor_update_focus(view->server);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue