mirror of
https://github.com/tmux/tmux.git
synced 2026-06-20 17:25:57 +00:00
hide-pane and show-pane now use the new layout mechanics.
This commit is contained in:
176
cmd-hide-pane.c
176
cmd-hide-pane.c
@@ -27,12 +27,8 @@
|
||||
* Hide or show panes.
|
||||
*/
|
||||
|
||||
static enum cmd_retval cmd_hide_pane_hide_exec(struct cmd *, struct cmdq_item *);
|
||||
static enum cmd_retval cmd_hide_pane_show_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static enum cmd_retval cmd_hide_pane_hide(struct window *, struct window_pane *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_hide_pane_show(struct window *, struct window_pane *);
|
||||
static enum cmd_retval cmd_hide_pane_exec(struct cmd *, struct cmdq_item *);
|
||||
static enum cmd_retval cmd_show_pane_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
const struct cmd_entry cmd_hide_pane_entry = {
|
||||
.name = "hide-pane",
|
||||
@@ -44,7 +40,7 @@ const struct cmd_entry cmd_hide_pane_entry = {
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_hide_pane_hide_exec
|
||||
.exec = cmd_hide_pane_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_show_pane_entry = {
|
||||
@@ -57,12 +53,61 @@ const struct cmd_entry cmd_show_pane_entry = {
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_hide_pane_show_exec
|
||||
.exec = cmd_show_pane_exec
|
||||
};
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_hide_pane_hide(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
struct window_pane *wpp = NULL;
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
|
||||
if (window_pane_is_hidden(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
if (wp == w->active) {
|
||||
/* Find previous active pane. */
|
||||
TAILQ_FOREACH(wpp, &w->last_panes, sentry) {
|
||||
if (wpp != wp && window_pane_visible(wpp))
|
||||
break;
|
||||
}
|
||||
if (wpp == NULL) {
|
||||
TAILQ_FOREACH(wpp, &w->z_index, zentry) {
|
||||
if (wpp != wp &&
|
||||
window_pane_visible(wpp))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lc->flags |= LAYOUT_CELL_HIDDEN;
|
||||
|
||||
layout_remove_tile(w, lc);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
|
||||
window_pane_stack_remove(&w->last_panes, wp);
|
||||
if (wpp != NULL) {
|
||||
window_set_active_pane(w, wpp, 1);
|
||||
} else if (wp == w->active) {
|
||||
/* No visible previous active pane; null active pane
|
||||
* to show dots background. */
|
||||
w->active = NULL;
|
||||
if (options_get_number(global_options, "focus-events"))
|
||||
window_pane_update_focus(wp);
|
||||
notify_window("window-pane-changed", w);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
} else {
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_hide_pane_hide_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmd_hide_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
@@ -73,11 +118,13 @@ cmd_hide_pane_hide_exec(struct cmd *self, struct cmdq_item *item)
|
||||
char *cause = NULL;
|
||||
enum cmd_retval rv;
|
||||
|
||||
window_unzoom(w, 1);
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
TAILQ_FOREACH(wp, &w->z_index, zentry) {
|
||||
if (!window_pane_visible(wp) || wp == active_pane)
|
||||
continue;
|
||||
rv = cmd_hide_pane_hide(w, wp, item);
|
||||
rv = cmd_hide_pane_hide(w, wp);
|
||||
if (rv != CMD_RETURN_NORMAL)
|
||||
return (rv);
|
||||
}
|
||||
@@ -97,12 +144,34 @@ cmd_hide_pane_hide_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_error(item, "No target pane to hide.");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
return (cmd_hide_pane_hide(w, wp, item));
|
||||
return (cmd_hide_pane_hide(w, wp));
|
||||
}
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_hide_pane_show_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmd_hide_pane_show(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
|
||||
if (!window_pane_is_hidden(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
lc->flags &= ~LAYOUT_CELL_HIDDEN;
|
||||
|
||||
layout_insert_tile(w, lc);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
|
||||
window_set_active_pane(w, wp, 1);
|
||||
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_show_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
@@ -113,6 +182,8 @@ cmd_hide_pane_show_exec(struct cmd *self, struct cmdq_item *item)
|
||||
char *cause = NULL;
|
||||
enum cmd_retval rv;
|
||||
|
||||
window_unzoom(w, 1);
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
TAILQ_FOREACH(wp, &w->z_index, zentry) {
|
||||
if (!window_pane_visible(wp))
|
||||
@@ -140,84 +211,3 @@ cmd_hide_pane_show_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (cmd_hide_pane_show(w, wp));
|
||||
}
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_hide_pane_hide(struct window *w, struct window_pane *wp,
|
||||
__unused struct cmdq_item *item)
|
||||
{
|
||||
struct window_pane *pwp = NULL;
|
||||
|
||||
if (wp->flags & PANE_HIDDEN)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
if (wp == w->active) {
|
||||
/*
|
||||
* Unzoom before searching: under zoom, window_pane_visible
|
||||
* returns false for every non-active pane.
|
||||
*/
|
||||
if (w->flags & WINDOW_ZOOMED)
|
||||
window_unzoom(w, 1);
|
||||
/* Find previous active pane. */
|
||||
TAILQ_FOREACH(pwp, &w->last_panes, sentry) {
|
||||
if (pwp != wp && window_pane_visible(pwp))
|
||||
break;
|
||||
}
|
||||
if (pwp == NULL) {
|
||||
TAILQ_FOREACH(pwp, &w->z_index, zentry) {
|
||||
if (pwp != wp &&
|
||||
window_pane_visible(pwp))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wp->flags |= PANE_HIDDEN;
|
||||
|
||||
if (w->layout_root != NULL) {
|
||||
wp->saved_layout_cell = wp->layout_cell;
|
||||
layout_hide_cell(w, wp->layout_cell);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
|
||||
window_pane_stack_remove(&w->last_panes, wp);
|
||||
if (pwp != NULL) {
|
||||
window_set_active_pane(w, pwp, 1);
|
||||
} else if (wp == w->active) {
|
||||
/* No visible previous active pane; null active pane
|
||||
* to show dots background. */
|
||||
w->active = NULL;
|
||||
if (options_get_number(global_options, "focus-events"))
|
||||
window_pane_update_focus(wp);
|
||||
notify_window("window-pane-changed", w);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
} else {
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_hide_pane_show(struct window *w, struct window_pane *wp)
|
||||
{
|
||||
wp->flags &= ~PANE_HIDDEN;
|
||||
|
||||
/* Fix pane offsets and sizes. */
|
||||
if (w->layout_root != NULL && wp->saved_layout_cell != NULL) {
|
||||
wp->layout_cell = wp->saved_layout_cell;
|
||||
wp->saved_layout_cell = NULL;
|
||||
layout_show_cell(w, wp->layout_cell);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
|
||||
window_set_active_pane(w, wp, 1);
|
||||
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
2
format.c
2
format.c
@@ -2155,7 +2155,7 @@ format_cb_pane_hidden_flag(struct format_tree *ft)
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL) {
|
||||
if (wp->flags & PANE_HIDDEN)
|
||||
if (window_pane_is_hidden(wp))
|
||||
return (xstrdup("1"));
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
|
||||
127
layout.c
127
layout.c
@@ -435,7 +435,8 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
||||
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if ((lc = wp->layout_cell) == NULL || wp == skip)
|
||||
if ((lc = wp->layout_cell) == NULL || wp == skip ||
|
||||
!window_pane_visible(wp))
|
||||
continue;
|
||||
|
||||
wp->xoff = lc->xoff;
|
||||
@@ -625,62 +626,6 @@ layout_resize_set_size(struct window *w, struct layout_cell *lc,
|
||||
layout_resize_adjust(w, lc, type, change);
|
||||
}
|
||||
|
||||
/*
|
||||
* Redistribute space equally among all visible (non-hidden WINDOWPANE)
|
||||
* children of lcparent in the given direction. Hidden WINDOWPANE leaves
|
||||
* are skipped; their stored sizes are left untouched. Container children
|
||||
* have their own children resized proportionally via layout_resize_child_cells.
|
||||
*
|
||||
* If all children happen to be hidden (n==0), nothing is done.
|
||||
*/
|
||||
void
|
||||
layout_redistribute_cells(struct window *w, struct layout_cell *lcparent,
|
||||
enum layout_type type)
|
||||
{
|
||||
struct layout_cell *lc;
|
||||
u_int n, total, each, rem, i, target;
|
||||
|
||||
/* Count visible cells at this level. */
|
||||
n = 0;
|
||||
TAILQ_FOREACH(lc, &lcparent->cells, entry) {
|
||||
if (lc->type == LAYOUT_WINDOWPANE &&
|
||||
lc->wp != NULL &&
|
||||
(lc->wp->flags & PANE_HIDDEN))
|
||||
continue;
|
||||
n++;
|
||||
}
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
total = (type == LAYOUT_LEFTRIGHT) ? lcparent->sx : lcparent->sy;
|
||||
if (total + 1 < n) /* can't fit even the minimum borders */
|
||||
return;
|
||||
|
||||
/*
|
||||
* each * n + (n-1) borders = total
|
||||
* → each = (total - (n-1)) / n, rem = (total - (n-1)) % n
|
||||
* The first `rem` visible cells get (each+1) to consume the remainder.
|
||||
*/
|
||||
each = (total - (n - 1)) / n;
|
||||
rem = (total - (n - 1)) % n;
|
||||
|
||||
i = 0;
|
||||
TAILQ_FOREACH(lc, &lcparent->cells, entry) {
|
||||
if (lc->type == LAYOUT_WINDOWPANE &&
|
||||
lc->wp != NULL &&
|
||||
(lc->wp->flags & PANE_HIDDEN))
|
||||
continue;
|
||||
target = each + (i < rem ? 1 : 0);
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
lc->sx = target;
|
||||
else
|
||||
lc->sy = target;
|
||||
if (lc->type != LAYOUT_WINDOWPANE)
|
||||
layout_resize_child_cells(w, lc);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find and return the nearest neighbour to a cell in a specific direction. */
|
||||
static struct layout_cell *
|
||||
layout_cell_get_neighbour_direction(struct layout_cell *lc, int direction)
|
||||
@@ -790,71 +735,6 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Hide a cell. Space is redistributed to the nearest neighbour if the cell was
|
||||
* tiled.
|
||||
*/
|
||||
void
|
||||
layout_hide_cell(struct window *w, struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcother, *lcparent, *lcchild;
|
||||
u_int shown_children = 0;
|
||||
int val;
|
||||
|
||||
if (lc == NULL)
|
||||
return;
|
||||
|
||||
lcparent = lc->parent;
|
||||
lc->flags |= LAYOUT_CELL_HIDDEN;
|
||||
|
||||
/* Merge the space into the nearest neighbour. */
|
||||
lcother = layout_cell_get_neighbour(lc);
|
||||
|
||||
if (lcother != NULL) {
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT)
|
||||
val = lc->sx + 1;
|
||||
else
|
||||
val = lc->sy + 1;
|
||||
layout_resize_adjust(w, lcother, lcparent->type, val);
|
||||
}
|
||||
|
||||
if (layout_cell_is_tiled(lc))
|
||||
layout_set_size(lc, 0, 0, 0, 0);
|
||||
|
||||
/* If no children are tiled, hide the parent. */
|
||||
if (lcparent != NULL) {
|
||||
TAILQ_FOREACH(lcchild, &lcparent->cells, entry) {
|
||||
if (layout_cell_is_tiled(lcchild)) {
|
||||
shown_children = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shown_children == 0)
|
||||
layout_hide_cell(w, lcparent);
|
||||
}
|
||||
}
|
||||
|
||||
/* Show a cell and redistribute the space in tiled cells. */
|
||||
void
|
||||
layout_show_cell(struct window *w, struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcparent;
|
||||
|
||||
if (lc == NULL)
|
||||
return;
|
||||
lcparent = lc->parent;
|
||||
if (lcparent == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Redistribute the parent's space equally among all visible (non-
|
||||
* hidden) children, including lc which has just been shown.
|
||||
* This ensures every pane at this level gets an equal share rather
|
||||
* than one pane losing most of its space to the restored pane.
|
||||
*/
|
||||
layout_redistribute_cells(w, lcparent, lcparent->type);
|
||||
}
|
||||
|
||||
/* Initialize layout for pane. */
|
||||
void
|
||||
layout_init(struct window *w, struct window_pane *wp)
|
||||
@@ -1866,6 +1746,9 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
if (lc == NULL)
|
||||
fatalx("layout cell cannot be null when tiling");
|
||||
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
return (1);
|
||||
|
||||
if (lcparent == NULL) {
|
||||
/* Only pane in the layout. */
|
||||
layout_set_size(lc, w->sx, w->sy, 0, 0);
|
||||
|
||||
@@ -146,7 +146,7 @@ screen_write_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
if (wp->layout_cell == NULL)
|
||||
return (0);
|
||||
|
||||
if (wp->flags & PANE_HIDDEN)
|
||||
if (window_pane_is_hidden(wp))
|
||||
return (0);
|
||||
|
||||
if (wp->flags & (PANE_REDRAW|PANE_DROP))
|
||||
|
||||
3
tmux.h
3
tmux.h
@@ -1289,7 +1289,6 @@ struct window_pane {
|
||||
#define PANE_THEMECHANGED 0x2000
|
||||
#define PANE_UNSEENCHANGES 0x4000
|
||||
#define PANE_REDRAWSCROLLBAR 0x8000
|
||||
#define PANE_HIDDEN 0x20000
|
||||
|
||||
/* Last floating position/size, saved when the pane is tiled. */
|
||||
int saved_float_xoff;
|
||||
@@ -3545,8 +3544,6 @@ void layout_destroy_cell(struct window *, struct layout_cell *,
|
||||
struct layout_cell **);
|
||||
void layout_hide_cell(struct window *, struct layout_cell *);
|
||||
void layout_show_cell(struct window *, struct layout_cell *);
|
||||
void layout_redistribute_cells(struct window *, struct layout_cell *,
|
||||
enum layout_type);
|
||||
void layout_resize_layout(struct window *, struct layout_cell *,
|
||||
enum layout_type, int, int);
|
||||
struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int);
|
||||
|
||||
51
window.c
51
window.c
@@ -543,7 +543,8 @@ window_pane_update_focus(struct window_pane *wp)
|
||||
int
|
||||
window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
|
||||
{
|
||||
struct window_pane *lastwp;
|
||||
struct window_pane *lastwp;
|
||||
struct layout_cell *lc;
|
||||
|
||||
log_debug("%s: pane %%%u", __func__, wp->id);
|
||||
|
||||
@@ -557,18 +558,15 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify)
|
||||
window_pane_stack_push(&w->last_panes, lastwp);
|
||||
|
||||
w->active = wp;
|
||||
w->active->active_point = next_active_point++;
|
||||
w->active->flags |= PANE_CHANGED;
|
||||
wp->active_point = next_active_point++;
|
||||
wp->flags |= PANE_CHANGED;
|
||||
lc = wp->layout_cell;
|
||||
|
||||
if (wp->flags & PANE_HIDDEN) {
|
||||
wp->flags &= ~PANE_HIDDEN;
|
||||
if (w->layout_root != NULL && wp->saved_layout_cell != NULL) {
|
||||
wp->layout_cell = wp->saved_layout_cell;
|
||||
wp->saved_layout_cell = NULL;
|
||||
layout_show_cell(w, wp->layout_cell);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
if (window_pane_is_hidden(wp)) {
|
||||
lc->flags &= ~LAYOUT_CELL_HIDDEN;
|
||||
layout_insert_tile(w, lc);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
@@ -864,19 +862,19 @@ window_lost_pane(struct window *w, struct window_pane *wp)
|
||||
|
||||
/* Try to find a good fit. */
|
||||
wpp = TAILQ_FIRST(&w->last_panes);
|
||||
if (wpp == NULL || wpp->flags & PANE_HIDDEN) {
|
||||
if (wpp == NULL || window_pane_is_hidden(wpp)) {
|
||||
wpp = TAILQ_PREV(wp, window_panes, entry);
|
||||
if (wpp == NULL || wpp->flags & PANE_HIDDEN)
|
||||
if (wpp == NULL || window_pane_is_hidden(wpp))
|
||||
wpp = TAILQ_NEXT(wp, entry);
|
||||
}
|
||||
/* Try to find any fit. */
|
||||
if (wpp == NULL || (wpp->flags & PANE_HIDDEN)) {
|
||||
if (wpp == NULL || window_pane_is_hidden(wpp)) {
|
||||
TAILQ_FOREACH_SAFE(wpp, &w->panes, entry, twpp) {
|
||||
if (wpp != wp && (~wpp->flags & PANE_HIDDEN))
|
||||
if (wpp != wp && !window_pane_is_hidden(wpp))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (wpp != NULL && (wpp->flags & PANE_HIDDEN))
|
||||
if (wpp != NULL && window_pane_is_hidden(wpp))
|
||||
wpp = NULL;
|
||||
|
||||
w->active = wpp;
|
||||
@@ -1046,7 +1044,7 @@ window_pane_printable_flags(struct window_pane *wp)
|
||||
flags[pos++] = 'Z';
|
||||
if (window_pane_is_floating(wp))
|
||||
flags[pos++] = 'F';
|
||||
if (wp->flags & PANE_HIDDEN)
|
||||
if (window_pane_is_hidden(wp))
|
||||
flags[pos++] = 'm';
|
||||
|
||||
flags[pos] = '\0';
|
||||
@@ -1463,8 +1461,9 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
|
||||
int
|
||||
window_pane_visible(struct window_pane *wp)
|
||||
{
|
||||
if (~wp->window->flags & WINDOW_ZOOMED &&
|
||||
~wp->flags & PANE_HIDDEN)
|
||||
if (window_pane_is_hidden(wp))
|
||||
return (0);
|
||||
if (~wp->window->flags & WINDOW_ZOOMED)
|
||||
return (1);
|
||||
|
||||
return (wp == wp->window->active);
|
||||
@@ -2202,19 +2201,11 @@ window_get_pane_status(struct window *w)
|
||||
int
|
||||
window_pane_is_floating(struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
|
||||
if (lc == NULL || (lc->flags & LAYOUT_CELL_FLOATING) == 0)
|
||||
return (0);
|
||||
return (1);
|
||||
return (wp->layout_cell->flags & LAYOUT_CELL_FLOATING);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_is_hidden(struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
|
||||
if ((lc->flags & LAYOUT_CELL_HIDDEN) == 0)
|
||||
return (0);
|
||||
return (1);
|
||||
return (wp->layout_cell->flags & LAYOUT_CELL_HIDDEN);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user