diff options
Diffstat (limited to 'sway/input_state.c')
-rw-r--r-- | sway/input_state.c | 281 |
1 files changed, 265 insertions, 16 deletions
diff --git a/sway/input_state.c b/sway/input_state.c index 9e065e60..e911d9cf 100644 --- a/sway/input_state.c +++ b/sway/input_state.c @@ -74,27 +74,276 @@ void release_key(uint32_t key_sym, uint32_t key_code) { } } +// Pointer state and mode + struct pointer_state pointer_state; -static struct wlc_geometry saved_floating; +static struct mode_state { + // initial view state + double x, y, w, h; + swayc_t *ptr; + // Containers used for resizing horizontally + struct { + double w; + swayc_t *ptr; + struct { + double w; + swayc_t *ptr; + } parent; + } horiz; + // Containers used for resizing vertically + struct { + double h; + swayc_t *ptr; + struct { + double h; + swayc_t *ptr; + } parent; + } vert; +} initial; + +static struct { + bool left; + bool top; +} lock; + +// initial set/unset + +static void set_initial_view(swayc_t *view) { + initial.ptr = view; + initial.x = view->x; + initial.y = view->y; + initial.w = view->width; + initial.h = view->height; +} + +static void set_initial_sibling(void) { + bool reset = true; + if ((initial.horiz.ptr = get_swayc_in_direction(initial.ptr, lock.left ? MOVE_RIGHT: MOVE_LEFT))) { + initial.horiz.w = initial.horiz.ptr->width; + initial.horiz.parent.ptr = get_swayc_in_direction(initial.horiz.ptr, lock.left ? MOVE_LEFT : MOVE_RIGHT); + initial.horiz.parent.w = initial.horiz.parent.ptr->width; + reset = false; + } + if ((initial.vert.ptr = get_swayc_in_direction(initial.ptr, lock.top ? MOVE_DOWN: MOVE_UP))) { + initial.vert.h = initial.vert.ptr->height; + initial.vert.parent.ptr = get_swayc_in_direction(initial.vert.ptr, lock.top ? MOVE_UP : MOVE_DOWN); + initial.vert.parent.h = initial.vert.parent.ptr->height; + reset = false; + } + // If nothing will change just undo the mode + if (reset) { + pointer_state.mode = 0; + } +} + +static void reset_initial_view(void) { + initial.ptr->x = initial.x; + initial.ptr->y = initial.y; + initial.ptr->width = initial.w; + initial.ptr->height = initial.h; + arrange_windows(initial.ptr, -1, -1); + pointer_state.mode = 0; +} + +static void reset_initial_sibling(void) { + initial.horiz.ptr->width = initial.horiz.w; + initial.horiz.parent.ptr->width = initial.horiz.parent.w; + initial.vert.ptr->height = initial.vert.h; + initial.vert.parent.ptr->height = initial.vert.parent.h; + arrange_windows(initial.horiz.ptr->parent, -1, -1); + arrange_windows(initial.vert.ptr->parent, -1, -1); + pointer_state.mode = 0; +} + +// Mode set left/right click + +static void pointer_mode_set_left(void) { + set_initial_view(pointer_state.left.view); + if (initial.ptr->is_floating) { + pointer_state.mode = M_DRAGGING | M_FLOATING; + } else { + pointer_state.mode = M_DRAGGING | M_TILING; + } +} + +static void pointer_mode_set_right(void) { + set_initial_view(pointer_state.right.view); + // Setup locking information + int midway_x = initial.ptr->x + initial.ptr->width/2; + int midway_y = initial.ptr->y + initial.ptr->height/2; + + lock.left = pointer_state.origin.x > midway_x; + lock.top = pointer_state.origin.y > midway_y; + + if (initial.ptr->is_floating) { + pointer_state.mode = M_RESIZING | M_FLOATING; + } else { + pointer_state.mode = M_RESIZING | M_TILING; + set_initial_sibling(); + } +} + +// Mode set/update/reset + +void pointer_mode_set(uint32_t button, bool condition) { + // switch on drag/resize mode + switch (pointer_state.mode & (M_DRAGGING | M_RESIZING)) { + case M_DRAGGING: + // end drag mode when left click is unpressed + if (!pointer_state.left.held) { + pointer_state.mode = 0; + } + break; + + case M_RESIZING: + // end resize mode when right click is unpressed + if (!pointer_state.right.held) { + pointer_state.mode = 0; + } + break; + + // No mode case + default: + // return if failed condition, or no view + if (!condition || !pointer_state.view) { + break; + } -void start_floating(swayc_t *view) { - if (view->is_floating) { - saved_floating.origin.x = view->x; - saved_floating.origin.y = view->y; - saved_floating.size.w = view->width; - saved_floating.size.h = view->height; + // Set mode depending on current button press + switch (button) { + // Start dragging mode + case M_LEFT_CLICK: + // if button release dont do anything + if (pointer_state.left.held) { + pointer_mode_set_left(); + } + break; + + // Start resize mode + case M_RIGHT_CLICK: + // if button release dont do anyhting + if (pointer_state.right.held) { + pointer_mode_set_right(); + } + break; + } } } -void reset_floating(swayc_t *view) { - if (view->is_floating) { - view->x = saved_floating.origin.x; - view->y = saved_floating.origin.y; - view->width = saved_floating.size.w; - view->height = saved_floating.size.h; - arrange_windows(view->parent, -1, -1); +void pointer_mode_update(void) { + if (initial.ptr->type != C_VIEW) { + pointer_state.mode = 0; + return; + } + int dx = pointer_state.origin.x; + int dy = pointer_state.origin.y; + + switch (pointer_state.mode) { + case M_FLOATING | M_DRAGGING: + // Update position + dx -= pointer_state.left.x; + dy -= pointer_state.left.y; + if (initial.x + dx != initial.ptr->x) { + initial.ptr->x = initial.x + dx; + } + if (initial.y + dy != initial.ptr->y) { + initial.ptr->y = initial.y + dy; + } + update_geometry(initial.ptr); + break; + + case M_FLOATING | M_RESIZING: + dx -= pointer_state.right.x; + dy -= pointer_state.right.y; + initial.ptr = pointer_state.right.view; + if (lock.left) { + if (initial.w + dx > min_sane_w) { + initial.ptr->width = initial.w + dx; + } + } else { // lock.right + if (initial.w - dx > min_sane_w) { + initial.ptr->width = initial.w - dx; + initial.ptr->x = initial.x + dx; + } + } + if (lock.top) { + if (initial.h + dy > min_sane_h) { + initial.ptr->height = initial.h + dy; + } + } else { // lock.bottom + if (initial.h - dy > min_sane_h) { + initial.ptr->height = initial.h - dy; + initial.ptr->y = initial.y + dy; + } + } + update_geometry(initial.ptr); + break; + + case M_TILING | M_DRAGGING: + // swap current view under pointer with dragged view + if (pointer_state.view && pointer_state.view->type == C_VIEW + && pointer_state.view != initial.ptr) { + // Swap them around + swap_container(pointer_state.view, initial.ptr); + update_geometry(pointer_state.view); + update_geometry(initial.ptr); + // Set focus back to initial view + set_focused_container(initial.ptr); + } + break; + + case M_TILING | M_RESIZING: + dx -= pointer_state.right.x; + dy -= pointer_state.right.y; + // resize if we can + if (initial.horiz.ptr) { + if (lock.left) { + // Check whether its fine to resize + if (initial.w + dx > min_sane_w && initial.horiz.w - dx > min_sane_w) { + initial.horiz.ptr->width = initial.horiz.w - dx; + initial.horiz.parent.ptr->width = initial.horiz.parent.w + dx; + } + } else { // lock.right + if (initial.w - dx > min_sane_w && initial.horiz.w + dx > min_sane_w) { + initial.horiz.ptr->width = initial.horiz.w + dx; + initial.horiz.parent.ptr->width = initial.horiz.parent.w - dx; + } + } + arrange_windows(initial.horiz.ptr->parent, -1, -1); + } + if (initial.vert.ptr) { + if (lock.top) { + if (initial.h + dy > min_sane_h && initial.vert.h - dy > min_sane_h) { + initial.vert.ptr->height = initial.vert.h - dy; + initial.vert.parent.ptr->height = initial.vert.parent.h + dy; + } + } else { // lock.bottom + if (initial.h - dy > min_sane_h && initial.vert.h + dy > min_sane_h) { + initial.vert.ptr->height = initial.vert.h + dy; + initial.vert.parent.ptr->height = initial.vert.parent.h - dy; + } + } + arrange_windows(initial.vert.ptr->parent, -1, -1); + } + default: + return; + } +} + +void pointer_mode_reset(void) { + switch (pointer_state.mode) { + case M_FLOATING | M_RESIZING: + case M_FLOATING | M_DRAGGING: + reset_initial_view(); + break; + + case M_TILING | M_RESIZING: + (void) reset_initial_sibling; + break; + + case M_TILING | M_DRAGGING: + default: + break; } - pointer_state.floating = (struct pointer_floating){0, 0}; - pointer_state.lock = (struct pointer_lock){0, 0, 0, 0, 0, 0, 0, 0}; } |