Merge branch 'next' (3.β is stable now)
This commit is contained in:
78
include/client.h
Normal file
78
include/client.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* vim:ts=8:expandtab
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
*
|
||||
* (c) 2009 Michael Stapelberg and contributors
|
||||
*
|
||||
* See file LICENSE for license information.
|
||||
*
|
||||
*/
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include "data.h"
|
||||
|
||||
#ifndef _CLIENT_H
|
||||
#define _CLIENT_H
|
||||
|
||||
/**
|
||||
* Removes the given client from the container, either because it will be inserted into another
|
||||
* one or because it was unmapped
|
||||
*
|
||||
*/
|
||||
void client_remove_from_container(xcb_connection_t *conn, Client *client, Container *container, bool remove_from_focusstack);
|
||||
|
||||
/**
|
||||
* Warps the pointer into the given client (in the middle of it, to be specific), therefore
|
||||
* selecting it
|
||||
*
|
||||
*/
|
||||
void client_warp_pointer_into(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Kills the given window using WM_DELETE_WINDOW or xcb_kill_window
|
||||
*
|
||||
*/
|
||||
void client_kill(xcb_connection_t *conn, Client *window);
|
||||
|
||||
/**
|
||||
* Checks if the given window class and title match the given client
|
||||
* Window title is passed as "normal" string and as UCS-2 converted string for
|
||||
* matching _NET_WM_NAME capable clients as well as those using legacy hints.
|
||||
*
|
||||
*/
|
||||
bool client_matches_class_name(Client *client, char *to_class, char *to_title,
|
||||
char *to_title_ucs, int to_title_ucs_len);
|
||||
|
||||
/**
|
||||
* Enters fullscreen mode for the given client. This is called by toggle_fullscreen
|
||||
* and when moving a fullscreen client to another screen.
|
||||
*
|
||||
*/
|
||||
void client_enter_fullscreen(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Toggles fullscreen mode for the given client. It updates the data structures and
|
||||
* reconfigures (= resizes/moves) the client and its frame to the full size of the
|
||||
* screen. When leaving fullscreen, re-rendering the layout is forced.
|
||||
*
|
||||
*/
|
||||
void client_toggle_fullscreen(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Sets the position of the given client in the X stack to the highest (tiling layer is always
|
||||
* on the same position, so this doesn’t matter) below the first floating client, so that
|
||||
* floating windows are always on top.
|
||||
*
|
||||
*/
|
||||
void client_set_below_floating(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Returns true if the client is floating. Makes the code more beatiful, as floating
|
||||
* is not simply a boolean, but also saves whether the user selected the current state
|
||||
* or whether it was automatically set.
|
||||
*
|
||||
*/
|
||||
bool client_is_floating(Client *client);
|
||||
|
||||
#endif
|
@ -1,12 +1,56 @@
|
||||
/*
|
||||
* vim:ts=8:expandtab
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
*
|
||||
* © 2009 Michael Stapelberg and contributors
|
||||
*
|
||||
* See file LICENSE for license information.
|
||||
*
|
||||
* include/config.h: Contains all structs/variables for
|
||||
* the configurable part of i3
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
typedef struct Config Config;
|
||||
extern Config config;
|
||||
|
||||
struct Colortriple {
|
||||
uint32_t border;
|
||||
uint32_t background;
|
||||
uint32_t text;
|
||||
};
|
||||
|
||||
struct Variable {
|
||||
char *key;
|
||||
char *value;
|
||||
|
||||
SLIST_ENTRY(Variable) variables;
|
||||
};
|
||||
|
||||
struct Config {
|
||||
const char *terminal;
|
||||
const char *font;
|
||||
const char *terminal;
|
||||
const char *font;
|
||||
|
||||
/** The modifier which needs to be pressed in combination with your mouse
|
||||
* buttons to do things with floating windows (move, resize) */
|
||||
uint32_t floating_modifier;
|
||||
|
||||
/* Color codes are stored here */
|
||||
struct config_client {
|
||||
struct Colortriple focused;
|
||||
struct Colortriple focused_inactive;
|
||||
struct Colortriple unfocused;
|
||||
} client;
|
||||
struct config_bar {
|
||||
struct Colortriple focused;
|
||||
struct Colortriple unfocused;
|
||||
} bar;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -16,6 +60,6 @@ struct Config {
|
||||
* configuration file.
|
||||
*
|
||||
*/
|
||||
void load_configuration(const char *override_configfile);
|
||||
void load_configuration(xcb_connection_t *conn, const char *override_configfile);
|
||||
|
||||
#endif
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
*
|
||||
* (c) 2009 Michael Stapelberg and contributors
|
||||
* © 2009 Michael Stapelberg and contributors
|
||||
*
|
||||
* See file LICENSE for license information.
|
||||
*
|
||||
@ -161,12 +161,21 @@ struct Workspace {
|
||||
int current_row;
|
||||
int current_col;
|
||||
|
||||
/* Should clients on this workspace be automatically floating? */
|
||||
bool auto_float;
|
||||
/* Are the floating clients on this workspace currently hidden? */
|
||||
bool floating_hidden;
|
||||
|
||||
Client *fullscreen_client;
|
||||
|
||||
/* The focus stack contains the clients in the correct order of focus so that
|
||||
the focus can be reverted correctly when a client is closed */
|
||||
SLIST_HEAD(focus_stack_head, Client) focus_stack;
|
||||
|
||||
/* This tail queue contains the floating clients in order of when they were first
|
||||
* set to floating (new floating clients are just appended) */
|
||||
TAILQ_HEAD(floating_clients_head, Client) floating_clients;
|
||||
|
||||
/* Backpointer to the screen this workspace is on */
|
||||
i3Screen *screen;
|
||||
|
||||
@ -197,6 +206,30 @@ struct Binding {
|
||||
TAILQ_ENTRY(Binding) bindings;
|
||||
};
|
||||
|
||||
/*
|
||||
* Holds a command specified by an exec-line in the config (see src/config.c)
|
||||
*
|
||||
*/
|
||||
struct Autostart {
|
||||
/* Command, like in command mode */
|
||||
char *command;
|
||||
TAILQ_ENTRY(Autostart) autostarts;
|
||||
};
|
||||
|
||||
/*
|
||||
* Holds an assignment for a given window class/title to a specific workspace
|
||||
* (see src/config.c)
|
||||
*
|
||||
*/
|
||||
struct Assignment {
|
||||
char *windowclass_title;
|
||||
/* floating is true if this was an assignment to the special workspace "~".
|
||||
* Matching clients will be put into floating mode automatically. */
|
||||
bool floating;
|
||||
int workspace;
|
||||
TAILQ_ENTRY(Assignment) assignments;
|
||||
};
|
||||
|
||||
/*
|
||||
* Data structure for cached font information:
|
||||
* - font id in X11 (load it once)
|
||||
@ -221,6 +254,10 @@ struct Font {
|
||||
*
|
||||
*/
|
||||
struct Client {
|
||||
/* initialized will be set to true if the client was fully initialized by
|
||||
* manage_window() and all functions can be used normally */
|
||||
bool initialized;
|
||||
|
||||
/* if you set a client to floating and set it back to managed, it does remember its old
|
||||
position and *tries* to get back there */
|
||||
Cell old_position;
|
||||
@ -232,6 +269,8 @@ struct Client {
|
||||
|
||||
/* x, y, width, height of the frame */
|
||||
Rect rect;
|
||||
/* Position in floating mode and in tiling mode are saved separately */
|
||||
Rect floating_rect;
|
||||
/* x, y, width, height of the child (relative to its frame) */
|
||||
Rect child_rect;
|
||||
|
||||
@ -255,9 +294,18 @@ struct Client {
|
||||
legacy window names are ignored. */
|
||||
bool uses_net_wm_name;
|
||||
|
||||
/* Holds the WM_CLASS, useful for matching the client in commands */
|
||||
char *window_class;
|
||||
|
||||
/* fullscreen is pretty obvious */
|
||||
bool fullscreen;
|
||||
|
||||
/* floating? (= not in tiling layout) This cannot be simply a bool because we want to keep track
|
||||
* of whether the status was set by the application (by setting WM_CLASS to tools for example) or
|
||||
* by the user. The user’s choice overwrites automatic mode, of course. The order of the values
|
||||
* is important because we check with >= FLOATING_AUTO_ON if a client is floating. */
|
||||
enum { FLOATING_AUTO_OFF = 0, FLOATING_USER_OFF = 1, FLOATING_AUTO_ON = 2, FLOATING_USER_ON = 3 } floating;
|
||||
|
||||
/* Ensure TITLEBAR_TOP maps to 0 because we use calloc for initialization later */
|
||||
enum { TITLEBAR_TOP = 0, TITLEBAR_LEFT, TITLEBAR_RIGHT, TITLEBAR_BOTTOM, TITLEBAR_OFF } titlebar_position;
|
||||
|
||||
@ -283,6 +331,7 @@ struct Client {
|
||||
CIRCLEQ_ENTRY(Client) clients;
|
||||
SLIST_ENTRY(Client) dock_clients;
|
||||
SLIST_ENTRY(Client) focus_clients;
|
||||
TAILQ_ENTRY(Client) floating_clients;
|
||||
};
|
||||
|
||||
/*
|
||||
|
87
include/floating.h
Normal file
87
include/floating.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* vim:ts=8:expandtab
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
*
|
||||
* © 2009 Michael Stapelberg and contributors
|
||||
*
|
||||
* See file LICENSE for license information.
|
||||
*
|
||||
*/
|
||||
#ifndef _FLOATING_H
|
||||
#define _FLOATING_H
|
||||
|
||||
/** Callback for dragging */
|
||||
typedef void(*callback_t)(Rect*, uint32_t, uint32_t);
|
||||
|
||||
/** On which border was the dragging initiated? */
|
||||
typedef enum { BORDER_LEFT, BORDER_RIGHT, BORDER_TOP, BORDER_BOTTOM} border_t;
|
||||
|
||||
/**
|
||||
* Enters floating mode for the given client.
|
||||
* Correctly takes care of the position/size (separately stored for tiling/floating mode)
|
||||
* and repositions/resizes/redecorates the client.
|
||||
*
|
||||
* If the automatic flag is set to true, this was an automatic update by a change of the
|
||||
* window class from the application which can be overwritten by the user.
|
||||
*
|
||||
*/
|
||||
void toggle_floating_mode(xcb_connection_t *conn, Client *client, bool automatic);
|
||||
|
||||
/**
|
||||
* Removes the floating client from its workspace and attaches it to the new workspace.
|
||||
* This is centralized here because it may happen if you move it via keyboard and
|
||||
* if you move it using your mouse.
|
||||
*
|
||||
*/
|
||||
void floating_assign_to_workspace(Client *client, Workspace *new_workspace);
|
||||
|
||||
/**
|
||||
* Called whenever the user clicks on a border (not the titlebar!) of a floating window.
|
||||
* Determines on which border the user clicked and launches the drag_pointer function
|
||||
* with the resize_callback.
|
||||
*
|
||||
*/
|
||||
int floating_border_click(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event);
|
||||
|
||||
/**
|
||||
* Called when the user clicked on the titlebar of a floating window.
|
||||
* Calls the drag_pointer function with the drag_window callback
|
||||
*
|
||||
*/
|
||||
void floating_drag_window(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event);
|
||||
|
||||
/**
|
||||
* Changes focus in the given direction for floating clients.
|
||||
*
|
||||
* Changing to the left/right means going to the previous/next floating client,
|
||||
* changing to top/bottom means cycling through the Z-index.
|
||||
*
|
||||
*/
|
||||
void floating_focus_direction(xcb_connection_t *conn, Client *currently_focused, direction_t direction);
|
||||
|
||||
/**
|
||||
* Moves the client 10px to the specified direction.
|
||||
*
|
||||
*/
|
||||
void floating_move(xcb_connection_t *conn, Client *currently_focused, direction_t direction);
|
||||
|
||||
/**
|
||||
* Hides all floating clients (or show them if they are currently hidden) on
|
||||
* the specified workspace.
|
||||
*
|
||||
*/
|
||||
void floating_toggle_hide(xcb_connection_t *conn, Workspace *workspace);
|
||||
|
||||
/**
|
||||
* This function grabs your pointer and lets you drag stuff around (borders).
|
||||
* Every time you move your mouse, an XCB_MOTION_NOTIFY event will be received
|
||||
* and the given callback will be called with the parameters specified (client,
|
||||
* border on which the click originally was), the original rect of the client,
|
||||
* the event and the new coordinates (x, y).
|
||||
*
|
||||
*/
|
||||
void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event,
|
||||
xcb_window_t confine_to, border_t border, callback_t callback);
|
||||
|
||||
#endif
|
@ -85,7 +85,15 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||
*
|
||||
*/
|
||||
int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t state,
|
||||
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop);
|
||||
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop);
|
||||
|
||||
/**
|
||||
* Store the window classes for jumping to them later.
|
||||
*
|
||||
*/
|
||||
int handle_windowclass_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||
xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop);
|
||||
|
||||
|
||||
/**
|
||||
* Expose event means we should redraw our windows (= title bar)
|
||||
@ -116,4 +124,14 @@ int handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_wi
|
||||
int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||
xcb_atom_t name, xcb_get_property_reply_t *reply);
|
||||
|
||||
/**
|
||||
* Handles the transient for hints set by a window, signalizing that this window is a popup window
|
||||
* for some other window.
|
||||
*
|
||||
* See ICCCM 4.1.2.6 for more details
|
||||
*
|
||||
*/
|
||||
int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
|
||||
xcb_atom_t name, xcb_get_property_reply_t *reply);
|
||||
|
||||
#endif
|
||||
|
11
include/i3.h
11
include/i3.h
@ -3,7 +3,7 @@
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
*
|
||||
* (c) 2009 Michael Stapelberg and contributors
|
||||
* © 2009 Michael Stapelberg and contributors
|
||||
*
|
||||
* See file LICENSE for license information.
|
||||
*
|
||||
@ -20,19 +20,16 @@
|
||||
#ifndef _I3_H
|
||||
#define _I3_H
|
||||
|
||||
#define NUM_ATOMS 13
|
||||
#define NUM_ATOMS 17
|
||||
|
||||
extern char **start_argv;
|
||||
extern Display *xkbdpy;
|
||||
extern TAILQ_HEAD(bindings_head, Binding) bindings;
|
||||
extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
|
||||
extern TAILQ_HEAD(assignments_head, Assignment) assignments;
|
||||
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
||||
extern xcb_event_handlers_t evenths;
|
||||
extern int num_screens;
|
||||
extern xcb_atom_t atoms[NUM_ATOMS];
|
||||
|
||||
void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn, xcb_window_t window, window_attributes_t wa);
|
||||
void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||
xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
|
||||
int16_t x, int16_t y, uint16_t width, uint16_t height);
|
||||
|
||||
#endif
|
||||
|
@ -36,6 +36,18 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw
|
||||
*/
|
||||
void redecorate_window(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Pushes the client’s x and y coordinates to X11
|
||||
*
|
||||
*/
|
||||
void reposition_client(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Pushes the client’s width/height to X11 and resizes the child window
|
||||
*
|
||||
*/
|
||||
void resize_client(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Renders the given container. Is called by render_layout() or individually (for example
|
||||
* when focus changes in a stacking container)
|
||||
|
42
include/manage.h
Normal file
42
include/manage.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* vim:ts=8:expandtab
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
*
|
||||
* (c) 2009 Michael Stapelberg and contributors
|
||||
*
|
||||
* See file LICENSE for license information.
|
||||
*
|
||||
*/
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include "data.h"
|
||||
|
||||
#ifndef _MANAGE_H
|
||||
#define _MANAGE_H
|
||||
|
||||
/**
|
||||
* Go through all existing windows (if the window manager is restarted) and manage them
|
||||
*
|
||||
*/
|
||||
void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *prophs, xcb_window_t root);
|
||||
|
||||
/**
|
||||
* Do some sanity checks and then reparent the window.
|
||||
*
|
||||
*/
|
||||
void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
||||
xcb_window_t window, window_attributes_t wa);
|
||||
|
||||
/**
|
||||
* reparent_window() gets called when a new window was opened and becomes a child of the root
|
||||
* window, or it gets called by us when we manage the already existing windows at startup.
|
||||
*
|
||||
* Essentially, this is the point where we take over control.
|
||||
*
|
||||
*/
|
||||
void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||
xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
|
||||
int16_t x, int16_t y, uint16_t width, uint16_t height);
|
||||
|
||||
#endif
|
@ -25,7 +25,7 @@
|
||||
for (int cols = 0; cols < (workspace)->cols; cols++) \
|
||||
for (int rows = 0; rows < (workspace)->rows; rows++)
|
||||
#define FREE(pointer) do { \
|
||||
if (pointer == NULL) { \
|
||||
if (pointer != NULL) { \
|
||||
free(pointer); \
|
||||
pointer = NULL; \
|
||||
} \
|
||||
@ -54,7 +54,7 @@ void slog(char *fmt, ...);
|
||||
* Prints the message (see printf()) to stderr, then exits the program.
|
||||
*
|
||||
*/
|
||||
void die(char *fmt, ...);
|
||||
void die(char *fmt, ...) __attribute__((__noreturn__));
|
||||
|
||||
/**
|
||||
* Safe-wrapper around malloc which exits if malloc returns NULL (meaning that there
|
||||
@ -123,13 +123,6 @@ void check_error(xcb_connection_t *conn, xcb_void_cookie_t cookie, char *err_mes
|
||||
*/
|
||||
char *convert_utf8_to_ucs2(char *input, int *real_strlen);
|
||||
|
||||
/**
|
||||
* Removes the given client from the container, either because it will be inserted into another
|
||||
* one or because it was unmapped
|
||||
*
|
||||
*/
|
||||
void remove_client_from_container(xcb_connection_t *conn, Client *client, Container *container);
|
||||
|
||||
/**
|
||||
* Returns the client which comes next in focus stack (= was selected before) for
|
||||
* the given container, optionally excluding the given client.
|
||||
@ -148,6 +141,17 @@ Client *get_last_focused_client(xcb_connection_t *conn, Container *container, Cl
|
||||
*/
|
||||
void unmap_workspace(xcb_connection_t *conn, Workspace *u_ws);
|
||||
|
||||
/**
|
||||
* Unmaps all clients (and stack windows) of the given workspace.
|
||||
*
|
||||
* This needs to be called separately when temporarily rendering
|
||||
* a workspace which is not the active workspace to force
|
||||
* reconfiguration of all clients, like in src/xinerama.c when
|
||||
* re-assigning a workspace to another screen.
|
||||
*
|
||||
*/
|
||||
void unmap_workspace(xcb_connection_t *conn, Workspace *u_ws);
|
||||
|
||||
/**
|
||||
* Sets the given client as focused by updating the data structures correctly,
|
||||
* updating the X input focus and finally re-decorating both windows (to signalize
|
||||
@ -170,24 +174,12 @@ void leave_stack_mode(xcb_connection_t *conn, Container *container);
|
||||
void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode);
|
||||
|
||||
/**
|
||||
* Warps the pointer into the given client (in the middle of it, to be specific), therefore
|
||||
* selecting it
|
||||
* Gets the first matching client for the given window class/window title.
|
||||
* If the paramater specific is set to a specific client, only this one
|
||||
* will be checked.
|
||||
*
|
||||
*/
|
||||
void warp_pointer_into(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Toggles fullscreen mode for the given client. It updates the data structures and
|
||||
* reconfigures (= resizes/moves) the client and its frame to the full size of the
|
||||
* screen. When leaving fullscreen, re-rendering the layout is forced.
|
||||
*
|
||||
*/
|
||||
void toggle_fullscreen(xcb_connection_t *conn, Client *client);
|
||||
|
||||
/**
|
||||
* Kills the given window using WM_DELETE_WINDOW or xcb_kill_window
|
||||
*
|
||||
*/
|
||||
void kill_window(xcb_connection_t *conn, Client *window);
|
||||
Client *get_matching_client(xcb_connection_t *conn, const char *window_classtitle,
|
||||
Client *specific);
|
||||
|
||||
#endif
|
||||
|
@ -49,6 +49,10 @@ enum { _NET_SUPPORTED = 0,
|
||||
_NET_WM_STATE,
|
||||
_NET_WM_WINDOW_TYPE,
|
||||
_NET_WM_WINDOW_TYPE_DOCK,
|
||||
_NET_WM_WINDOW_TYPE_DIALOG,
|
||||
_NET_WM_WINDOW_TYPE_UTILITY,
|
||||
_NET_WM_WINDOW_TYPE_TOOLBAR,
|
||||
_NET_WM_WINDOW_TYPE_SPLASH,
|
||||
_NET_WM_DESKTOP,
|
||||
_NET_WM_STRUT_PARTIAL,
|
||||
WM_PROTOCOLS,
|
||||
@ -126,4 +130,10 @@ void fake_absolute_configure_notify(xcb_connection_t *conn, Client *client);
|
||||
*/
|
||||
void xcb_get_numlock_mask(xcb_connection_t *conn);
|
||||
|
||||
/**
|
||||
* Raises the given window (typically client->frame) above all other windows
|
||||
*
|
||||
*/
|
||||
void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user