tiling drag: only start when there are drop targets (#5213)
This prevents potentially confusing drag & drop on fullscreen containers and only-containers on workspaces. fixes https://github.com/i3/i3/issues/5184
This commit is contained in:
parent
941229ee62
commit
5e759ed424
@ -9,6 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "all.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tiling drag initiation modes.
|
* Tiling drag initiation modes.
|
||||||
*/
|
*/
|
||||||
@ -19,6 +21,13 @@ typedef enum {
|
|||||||
TILING_DRAG_MODIFIER_OR_TITLEBAR = 3
|
TILING_DRAG_MODIFIER_OR_TITLEBAR = 3
|
||||||
} tiling_drag_t;
|
} tiling_drag_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether there currently are any drop targets.
|
||||||
|
* Used to only initiate a drag when there is something to drop onto.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool has_drop_targets(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a mouse drag operation on a tiled window.
|
* Initiates a mouse drag operation on a tiled window.
|
||||||
*
|
*
|
||||||
|
1
release-notes/changes/2-tiling-drag-targets
Normal file
1
release-notes/changes/2-tiling-drag-targets
Normal file
@ -0,0 +1 @@
|
|||||||
|
tiling drag: only initiate when there are drop targets
|
@ -230,7 +230,8 @@ static void route_click(Con *con, xcb_button_press_event_t *event, const bool mo
|
|||||||
/* 2: floating modifier pressed, initiate a drag */
|
/* 2: floating modifier pressed, initiate a drag */
|
||||||
if (mod_pressed && is_left_click && !floatingcon &&
|
if (mod_pressed && is_left_click && !floatingcon &&
|
||||||
(config.tiling_drag == TILING_DRAG_MODIFIER ||
|
(config.tiling_drag == TILING_DRAG_MODIFIER ||
|
||||||
config.tiling_drag == TILING_DRAG_MODIFIER_OR_TITLEBAR)) {
|
config.tiling_drag == TILING_DRAG_MODIFIER_OR_TITLEBAR) &&
|
||||||
|
has_drop_targets()) {
|
||||||
const bool use_threshold = !mod_pressed;
|
const bool use_threshold = !mod_pressed;
|
||||||
tiling_drag(con, event, use_threshold);
|
tiling_drag(con, event, use_threshold);
|
||||||
allow_replay_pointer(event->time);
|
allow_replay_pointer(event->time);
|
||||||
@ -311,7 +312,8 @@ static void route_click(Con *con, xcb_button_press_event_t *event, const bool mo
|
|||||||
if (is_left_click &&
|
if (is_left_click &&
|
||||||
((config.tiling_drag == TILING_DRAG_TITLEBAR && dest == CLICK_DECORATION) ||
|
((config.tiling_drag == TILING_DRAG_TITLEBAR && dest == CLICK_DECORATION) ||
|
||||||
(config.tiling_drag == TILING_DRAG_MODIFIER_OR_TITLEBAR &&
|
(config.tiling_drag == TILING_DRAG_MODIFIER_OR_TITLEBAR &&
|
||||||
(mod_pressed || dest == CLICK_DECORATION)))) {
|
(mod_pressed || dest == CLICK_DECORATION))) &&
|
||||||
|
has_drop_targets()) {
|
||||||
allow_replay_pointer(event->time);
|
allow_replay_pointer(event->time);
|
||||||
const bool use_threshold = !mod_pressed;
|
const bool use_threshold = !mod_pressed;
|
||||||
tiling_drag(con, event, use_threshold);
|
tiling_drag(con, event, use_threshold);
|
||||||
|
@ -27,6 +27,62 @@ static Rect con_rect_plus_deco_height(Con *con) {
|
|||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_tiling_drop_target(Con *con) {
|
||||||
|
if (!con_has_managed_window(con) ||
|
||||||
|
con_is_floating(con) ||
|
||||||
|
con_is_hidden(con)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Con *ws = con_get_workspace(con);
|
||||||
|
if (con_is_internal(ws)) {
|
||||||
|
/* Skip containers on i3-internal containers like the scratchpad, which are
|
||||||
|
technically visible on their pseudo-output. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!workspace_is_visible(ws)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Con *fs = con_get_fullscreen_covering_ws(ws);
|
||||||
|
if (fs != NULL && fs != con) {
|
||||||
|
/* Workspace is visible, but con is not visible because some other
|
||||||
|
container is in fullscreen. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns whether there currently are any drop targets.
|
||||||
|
* Used to only initiate a drag when there is something to drop onto.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool has_drop_targets(void) {
|
||||||
|
int drop_targets = 0;
|
||||||
|
Con *con;
|
||||||
|
TAILQ_FOREACH (con, &all_cons, all_cons) {
|
||||||
|
if (!is_tiling_drop_target(con)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
drop_targets++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In addition to tiling containers themselves, an visible but empty
|
||||||
|
* workspace (in a multi-monitor scenario) also is a drop target. */
|
||||||
|
Con *output;
|
||||||
|
TAILQ_FOREACH (output, &(croot->focus_head), focused) {
|
||||||
|
if (con_is_internal(output)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Con *visible_ws = NULL;
|
||||||
|
GREP_FIRST(visible_ws, output_get_content(output), workspace_is_visible(child));
|
||||||
|
if (visible_ws != NULL && con_num_children(visible_ws) == 0) {
|
||||||
|
drop_targets++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return drop_targets > 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return an appropriate target at given coordinates.
|
* Return an appropriate target at given coordinates.
|
||||||
*
|
*
|
||||||
@ -35,23 +91,13 @@ static Con *find_drop_target(uint32_t x, uint32_t y) {
|
|||||||
Con *con;
|
Con *con;
|
||||||
TAILQ_FOREACH (con, &all_cons, all_cons) {
|
TAILQ_FOREACH (con, &all_cons, all_cons) {
|
||||||
Rect rect = con_rect_plus_deco_height(con);
|
Rect rect = con_rect_plus_deco_height(con);
|
||||||
|
if (!rect_contains(rect, x, y) ||
|
||||||
if (rect_contains(rect, x, y) &&
|
!is_tiling_drop_target(con)) {
|
||||||
con_has_managed_window(con) &&
|
continue;
|
||||||
!con_is_floating(con) &&
|
|
||||||
!con_is_hidden(con)) {
|
|
||||||
Con *ws = con_get_workspace(con);
|
|
||||||
if (strcmp(ws->name, "__i3_scratch") == 0) {
|
|
||||||
/* Skip containers on the scratchpad, which are technically
|
|
||||||
visible on their pseudo-output. */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!workspace_is_visible(ws)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Con *fs = con_get_fullscreen_covering_ws(ws);
|
|
||||||
return fs ? fs : con;
|
|
||||||
}
|
}
|
||||||
|
Con *ws = con_get_workspace(con);
|
||||||
|
Con *fs = con_get_fullscreen_covering_ws(ws);
|
||||||
|
return fs ? fs : con;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Couldn't find leaf container, get a workspace. */
|
/* Couldn't find leaf container, get a workspace. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user