2 #define I3__FILE__ "x.c"
77 static
con_state *state_for_frame(xcb_window_t window) {
80 if (state->
id == window)
84 ELOG(
"No state found\n");
101 xcb_visualid_t visual = XCB_COPY_FROM_PARENT;
102 xcb_colormap_t win_colormap = XCB_NONE;
103 if (depth !=
root_depth && depth != XCB_COPY_FROM_PARENT) {
107 win_colormap = xcb_generate_id(
conn);
108 xcb_create_colormap_checked(
conn, XCB_COLORMAP_ALLOC_NONE, win_colormap,
root, visual);
114 mask |= XCB_CW_BACK_PIXEL;
117 mask |= XCB_CW_BORDER_PIXEL;
121 mask |= XCB_CW_OVERRIDE_REDIRECT;
125 mask |= XCB_CW_EVENT_MASK;
128 mask |= XCB_CW_COLORMAP;
129 values[4] = win_colormap;
132 mask = XCB_CW_OVERRIDE_REDIRECT;
136 mask |= XCB_CW_EVENT_MASK;
139 mask |= XCB_CW_COLORMAP;
143 Rect dims = {-15, -15, 10, 10};
146 if (win_colormap != XCB_NONE)
147 xcb_free_colormap(
conn, win_colormap);
153 DLOG(
"Adding window 0x%08x to lists\n", state->
id);
157 DLOG(
"adding new state for window id 0x%08x\n", state->
id);
169 if ((state = state_for_frame(con->
frame)) == NULL) {
170 ELOG(
"window state not found\n");
174 DLOG(
"resetting state %p to initial\n", state);
188 if ((state = state_for_frame(con->
frame)) == NULL) {
189 ELOG(
"window state for con not found\n");
202 struct con_state *state_src, *state_dest;
204 if ((state_src = state_for_frame(src->
frame)) == NULL) {
205 ELOG(
"window state for src not found\n");
209 if ((state_dest = state_for_frame(dest->
frame)) == NULL) {
210 ELOG(
"window state for dest not found\n");
214 state_dest->
con = state_src->
con;
215 state_src->
con = NULL;
217 Rect zero = {0, 0, 0, 0};
220 DLOG(
"COPYING RECT\n");
234 state = state_for_frame(con->
frame);
237 TAILQ_REMOVE(&initial_mapping_head, state, initial_mapping_order);
250 xcb_get_property_cookie_t cookie;
259 for (uint32_t i = 0; i < protocols.atoms_len; i++)
260 if (protocols.atoms[i] == atom)
276 LOG(
"Killing specific window 0x%08x\n", window);
277 xcb_destroy_window(
conn, window);
279 LOG(
"Killing the X11 client which owns window 0x%08x\n", window);
280 xcb_kill_client(
conn, window);
289 xcb_client_message_event_t *ev = event;
291 ev->response_type = XCB_CLIENT_MESSAGE;
293 ev->type = A_WM_PROTOCOLS;
295 ev->data.data32[0] = A_WM_DELETE_WINDOW;
296 ev->data.data32[1] = XCB_CURRENT_TIME;
298 LOG(
"Sending WM_DELETE to the client\n");
299 xcb_send_event(
conn,
false, window, XCB_EVENT_MASK_NO_EVENT, (
char *)ev);
323 parent->
type == CT_OUTPUT ||
324 parent->
type == CT_DOCKAREA ||
325 con->
type == CT_FLOATING_CON)
335 if (leaf && con->
pixmap == XCB_NONE)
346 else if (con ==
TAILQ_FIRST(&(parent->focus_head)))
386 if (con->
window != NULL) {
387 xcb_rectangle_t background[] = {
397 for (
int i = 0; i < 4; i++)
398 DLOG(
"rect is (%d, %d) with %d x %d\n",
407 xcb_poly_fill_rectangle(
conn, con->
pixmap, con->
pm_gc,
sizeof(background) /
sizeof(xcb_rectangle_t), background);
411 if (p->border_style !=
BS_NONE && p->con_is_leaf) {
419 DLOG(
"border_rect spans (%d, %d) with %d x %d\n", br.
x, br.
y, br.
width, br.
height);
427 xcb_change_gc(
conn,
con->
pm_gc, XCB_GC_FOREGROUND, (uint32_t[]) {p->color->background});
429 xcb_rectangle_t leftline = {0, 0, br.
x, r->height};
433 xcb_rectangle_t rightline = {r->width + br.
width + br.
x, 0, r->width, r->height};
437 xcb_rectangle_t bottomline = {0, r->height + br.
height + br.
y, r->width, r->height};
453 xcb_change_gc(
conn,
con->
pm_gc, XCB_GC_FOREGROUND, (uint32_t[]) {p->color->indicator});
456 {r->width + br.
width + br.
x, br.
y, r->width, r->height + br.
height}});
457 else if (p->parent_layout ==
L_SPLITV)
458 xcb_poly_fill_rectangle(
conn, con->pixmap, con->pm_gc, 1, (xcb_rectangle_t[]) {
459 {br.
x, r->height + br.
height + br.
y, r->width - (2 * br.
x), r->height}});
469 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]) {p->color->background});
470 xcb_rectangle_t drect = {con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height};
471 xcb_poly_fill_rectangle(
conn, parent->pixmap, parent->pm_gc, 1, &drect);
474 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]) {p->color->border});
475 Rect *dr = &(con->deco_rect);
479 if (
TAILQ_PREV(con, nodes_head, nodes) != NULL)
484 xcb_segment_t segments[] = {
486 dr->x + dr->width - 1, dr->y},
487 {dr->x + deco_diff_l, dr->y + dr->height - 1,
488 dr->x - deco_diff_r + dr->width - 1, dr->y + dr->height - 1}};
489 xcb_poly_segment(
conn, parent->pixmap, parent->pm_gc, 2, segments);
495 struct Window *win = con->window;
506 parent->pixmap, parent->pm_gc,
507 con->deco_rect.x + 2, con->deco_rect.y + text_offset_y,
508 con->deco_rect.width - 2);
514 if (win->
name == NULL)
517 int indent_level = 0,
519 Con *il_parent = parent;
525 if (il_parent->
type == CT_WORKSPACE || il_parent->
type == CT_DOCKAREA || il_parent->
type == CT_OUTPUT)
527 il_parent = il_parent->
parent;
532 int indent_px = (indent_level * 5) * indent_mult;
535 parent->pixmap, parent->pm_gc,
536 con->deco_rect.x + 2 + indent_px, con->deco_rect.y + text_offset_y,
537 con->deco_rect.width - 2 - indent_px);
548 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]) {p->color->border});
550 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]) {p->color->background});
552 xcb_poly_line(
conn, XCB_COORD_MODE_ORIGIN, parent->pixmap, parent->pm_gc, 6,
554 {dr->x + dr->width, dr->y},
555 {dr->x + dr->width, dr->y + dr->height},
556 {dr->x + dr->width - 1, dr->y},
557 {dr->x + dr->width - 1, dr->y + dr->height},
558 {dr->x, dr->y + dr->height},
562 xcb_change_gc(
conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]) {p->color->border});
563 xcb_poly_segment(
conn, parent->pixmap, parent->pm_gc, 2, segments);
566 xcb_copy_area(
conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
585 TAILQ_FOREACH (current, &(con->floating_head), floating_windows)
592 if ((con->
type != CT_ROOT && con->
type != CT_OUTPUT) &&
609 state = state_for_frame(con->
frame);
611 if (state->
name != NULL) {
612 DLOG(
"pushing name %s for con %p\n", state->
name, con);
614 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
frame,
619 if (con->
window == NULL) {
622 uint32_t max_y = 0, max_height = 0;
625 if (dr->
y >= max_y && dr->
height >= max_height) {
630 rect.
height = max_y + max_height;
638 DLOG(
"Reparenting child window\n");
643 uint32_t values[] = {XCB_NONE};
644 xcb_change_window_attributes(
conn, state->
old_frame, XCB_CW_EVENT_MASK, values);
645 xcb_change_window_attributes(
conn, con->
window->
id, XCB_CW_EVENT_MASK, values);
650 xcb_change_window_attributes(
conn, state->
old_frame, XCB_CW_EVENT_MASK, values);
652 xcb_change_window_attributes(
conn, con->
window->
id, XCB_CW_EVENT_MASK, values);
658 DLOG(
"ignore_unmap for reparenting of con %p (win 0x%08x) is now %d\n",
662 bool fake_notify =
false;
664 if (memcmp(&(state->
rect), &rect,
sizeof(
Rect)) != 0 &&
685 if (!is_pixmap_needed && con->
pixmap != XCB_NONE) {
690 if (has_rect_changed && is_pixmap_needed) {
710 uint32_t values[] = {0};
711 xcb_create_gc(
conn, con->
pm_gc, con->
pixmap, XCB_GC_GRAPHICS_EXPOSURES, values);
726 DLOG(
"setting rect (%d, %d, %d, %d)\n", rect.
x, rect.
y, rect.
width, rect.
height);
733 if (con->
pixmap != XCB_NONE)
737 memcpy(&(state->
rect), &rect,
sizeof(
Rect));
742 if (con->
window != NULL &&
744 DLOG(
"setting window rect (%d, %d, %d, %d)\n",
756 xcb_void_cookie_t cookie;
758 if (con->
window != NULL) {
762 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
window->
id,
763 A_WM_STATE, A_WM_STATE, 32, 2, data);
773 xcb_change_window_attributes(
conn, con->
window->
id, XCB_CW_EVENT_MASK, values);
774 DLOG(
"mapping child window (serial %d)\n", cookie.sequence);
778 cookie = xcb_map_window(
conn, con->
frame);
781 xcb_change_window_attributes(
conn, con->
frame, XCB_CW_EVENT_MASK, values);
784 if (con->
pixmap != XCB_NONE)
788 DLOG(
"mapping container %08x (serial %d)\n", con->
frame, cookie.sequence);
795 DLOG(
"Sending fake configure notify\n");
820 state = state_for_frame(con->
frame);
826 xcb_void_cookie_t cookie;
827 if (con->
window != NULL) {
830 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
window->
id,
831 A_WM_STATE, A_WM_STATE, 32, 2, data);
834 cookie = xcb_unmap_window(
conn, con->
frame);
835 DLOG(
"unmapping container %p / %s (serial %d)\n", con, con->
name, cookie.sequence);
839 if (con->
window != NULL) {
850 TAILQ_FOREACH (current, &(con->floating_head), floating_windows)
885 xcb_query_pointer_cookie_t pointercookie;
889 pointercookie = xcb_query_pointer(
conn,
root);
892 DLOG(
"-- PUSHING WINDOW STACK --\n");
894 uint32_t values[1] = {XCB_NONE};
897 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);
900 bool order_changed =
false;
901 bool stacking_changed =
false;
912 static xcb_window_t *client_list_windows = NULL;
913 static int client_list_count = 0;
915 if (cnt != client_list_count) {
916 client_list_windows =
srealloc(client_list_windows,
sizeof(xcb_window_t) * cnt);
917 client_list_count = cnt;
920 xcb_window_t *walk = client_list_windows;
925 memcpy(walk++, &(state->
con->
window->
id),
sizeof(xcb_window_t));
930 if (prev != old_prev)
931 order_changed =
true;
933 stacking_changed =
true;
936 mask |= XCB_CONFIG_WINDOW_SIBLING;
937 mask |= XCB_CONFIG_WINDOW_STACK_MODE;
938 uint32_t values[] = {state->
id, XCB_STACK_MODE_ABOVE};
940 xcb_configure_window(
conn, prev->
id, mask, values);
947 if (stacking_changed) {
948 DLOG(
"Client list changed (%i clients)\n", cnt);
951 walk = client_list_windows;
954 TAILQ_FOREACH (state, &initial_mapping_head, initial_mapping_order) {
962 DLOG(
"PUSHING CHANGES\n");
966 xcb_query_pointer_reply_t *pointerreply = xcb_query_pointer_reply(
conn, pointercookie, NULL);
968 ELOG(
"Could not query pointer position, not warping pointer\n");
970 int mid_x = warp_to->
x + (warp_to->
width / 2);
971 int mid_y = warp_to->
y + (warp_to->
height / 2);
975 if (current != target) {
977 xcb_change_window_attributes(
conn,
root, XCB_CW_EVENT_MASK, (uint32_t[]) {XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT});
978 xcb_warp_pointer(
conn, XCB_NONE,
root, 0, 0, 0, 0, mid_x, mid_y);
989 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);
1008 DLOG(
"Updating focus by sending WM_TAKE_FOCUS to window 0x%08x (focused: %p / %s)\n",
1042 DLOG(
"Still no window focused, better set focus to the root window\n");
1049 DLOG(
"ENDING CHANGES\n");
1062 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);
1087 state = state_for_frame(con->
frame);
1103 if ((state = state_for_frame(con->
frame)) == NULL) {
1104 ELOG(
"window state not found\n");
1117 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE,
root,
1118 A_I3_SHMLOG_PATH, A_UTF8_STRING, 8,
1127 pid_t pid = getpid();
1128 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE,
root, A_I3_SOCKET_PATH, A_UTF8_STRING, 8,
1132 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE,
root, A_I3_CONFIG_PATH, A_UTF8_STRING, 8,
1160 xcb_change_window_attributes(
conn, state->
id, XCB_CW_EVENT_MASK, values);
void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows)
Updates the _NET_CLIENT_LIST_STACKING hint.
void x_mask_event_mask(uint32_t mask)
Applies the given mask to the event mask of every i3 window decoration X11 window.
#define CIRCLEQ_INSERT_HEAD(head, elm, field)
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
Con * con
The con for which this state is.
#define CHILD_EVENT_MASK
The XCB_CW_EVENT_MASK for the child (= real window)
uint8_t ignore_unmap
This counter contains the number of UnmapNotify events for this container (or, more precisely...
#define TAILQ_REMOVE(head, elm, field)
bool disable_focus_follows_mouse
By default, focus follows mouse.
void x_reinit(Con *con)
Re-initializes the associated X window state for this container.
bool needs_take_focus
Whether the application needs to receive WM_TAKE_FOCUS.
Stores a rectangle, for example the size of a window, the child window etc.
static xcb_window_t last_focused
#define CIRCLEQ_PREV(elm, field)
bool window_supports_protocol(xcb_window_t window, xcb_atom_t atom)
Returns true if the client supports the given protocol atom (like WM_DELETE_WINDOW) ...
#define xcb_icccm_get_wm_protocols_reply
#define CIRCLEQ_FOREACH(var, head, field)
void x_push_node(Con *con)
This function pushes the properties of each node of the layout tree to X11 if they have changed (like...
xcb_screen_t * root_screen
struct width_height con_rect
uint16_t depth
Depth of the window.
#define TAILQ_FIRST(head)
#define xcb_icccm_get_wm_protocols_reply_wipe
void x_reparent_child(Con *con, Con *old)
Reparents the child window of the given container (necessary for sticky containers).
void x_deco_recurse(Con *con)
Recursively calls x_draw_decoration.
xcb_timestamp_t last_timestamp
The last timestamp we got from X11 (timestamps are included in some events and are used for some thin...
#define FRAME_EVENT_MASK
The XCB_CW_EVENT_MASK for its frame.
struct Config::config_client client
void x_window_kill(xcb_window_t window, kill_window_t kill_window)
Kills the given X11 window using WM_DELETE_WINDOW (if supported).
bool name_x_changed
Flag to force re-rendering the decoration upon changes.
struct Colortriple unfocused
static bool is_con_attached(Con *con)
An Output is a physical output on your graphics driver.
void send_take_focus(xcb_window_t window, xcb_timestamp_t timestamp)
Sends the WM_TAKE_FOCUS ClientMessage to the given window.
Stores the parameters for rendering a window decoration.
#define TAILQ_NEXT(elm, field)
border_style_t border_style
A 'Window' is a type which contains an xcb_window_t and all the related information (hints like _NET_...
void x_set_warp_to(Rect *rect)
Set warp_to coordinates.
void ewmh_update_client_list(xcb_window_t *list, int num_windows)
Updates the _NET_CLIENT_LIST hint.
char * con_get_tree_representation(Con *con)
Create a string representing the subtree under con.
#define xcb_icccm_get_wm_protocols_reply_t
#define CIRCLEQ_END(head)
int sasprintf(char **strp, const char *fmt,...)
Safe-wrapper around asprintf which exits if it returns -1 (meaning that there is no more memory avail...
CIRCLEQ_HEAD(state_head, con_state)
#define XCB_ICCCM_WM_STATE_WITHDRAWN
Rect con_border_style_rect(Con *con)
Returns a "relative" Rect which contains the amount of pixels that need to be added to the original R...
void x_move_win(Con *src, Con *dest)
Moves a child window from Container src to Container dest.
bool con_is_leaf(Con *con)
Returns true when this node is a leaf node (has no children)
bool con_has_managed_window(Con *con)
Returns true when this con is a leaf node with a managed X11 window (e.g., excluding dock containers)...
struct deco_render_params * deco_render_params
Cache for the decoration rendering.
#define CIRCLEQ_ENTRY(type)
void x_push_changes(Con *con)
Pushes all changes (state of each node, see x_push_node() and the window stack) to X11...
warping_t mouse_warping
By default, when switching focus to a window on a different output (e.g.
void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r)
Configures the given window to have the size/position specified by given rect.
int height
The height of the font, built from font_ascent + font_descent.
void draw_text(i3String *text, xcb_drawable_t drawable, xcb_gcontext_t gc, int x, int y, int max_width)
Draws text onto the specified X drawable (normally a pixmap) at the specified coordinates (from the t...
void x_set_name(Con *con, const char *name)
Sets the WM_NAME property (so, no UTF8, but used only for debugging anyways) of the given name...
#define TAILQ_EMPTY(head)
adjacent_t con_adjacent_borders(Con *con)
Returns adjacent borders of the window.
struct width_height con_window_rect
struct Colortriple focused
adjacent_t hide_edge_borders
Remove borders if they are adjacent to the screen edge.
#define TAILQ_PREV(elm, headname, field)
#define TAILQ_ENTRY(type)
char * current_configpath
void draw_text_ascii(const char *text, xcb_drawable_t drawable, xcb_gcontext_t gc, int x, int y, int max_width)
ASCII version of draw_text to print static strings.
xcb_visualid_t get_visualid_by_depth(uint16_t depth)
Get visualid with specified depth.
xcb_window_t create_window(xcb_connection_t *conn, Rect dims, uint16_t depth, xcb_visualid_t visual, uint16_t window_class, enum xcursor_cursor_t cursor, bool map, uint32_t mask, uint32_t *values)
Convenience wrapper around xcb_create_window which takes care of depth, generating an ID and checking...
void x_draw_decoration(Con *con)
Draws the decoration of the given container onto its parent.
Stores a width/height pair, used as part of deco_render_params to check whether the rects width/heigh...
struct Colortriple urgent
A 'Con' represents everything from the X11 root window down to a single X11 window.
void * scalloc(size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
#define CIRCLEQ_FOREACH_REVERSE(var, head, field)
char * current_socketpath
static void x_push_node_unmaps(Con *con)
#define CIRCLEQ_REMOVE(head, elm, field)
Output * get_output_containing(unsigned int x, unsigned int y)
Returns the active (!) output which contains the coordinates x, y or NULL if there is no output which...
bool con_inside_focused(Con *con)
Checks if the given container is inside a focused container.
void fake_absolute_configure_notify(Con *con)
Generates a configure_notify_event with absolute coordinates (relative to the X root window...
void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background)
Defines the colors to be used for the forthcoming draw_text calls.
#define TAILQ_INSERT_TAIL(head, elm, field)
int con_border_style(Con *con)
Use this function to get a container’s border style.
adjacent_t
describes if the window is adjacent to the output (physical screen) edges.
#define TAILQ_HEAD_INITIALIZER(head)
struct Colortriple focused_inactive
i3String * name
The name of the window.
#define xcb_icccm_get_wm_protocols
#define CIRCLEQ_HEAD_INITIALIZER(head)
void x_set_i3_atoms(void)
Sets up i3 specific atoms (I3_SOCKET_PATH and I3_CONFIG_PATH)
void update_shmlog_atom()
Set up the SHMLOG_PATH atom.
#define TAILQ_FOREACH(var, head, field)
bool doesnt_accept_focus
Whether this window accepts focus.
void * srealloc(void *ptr, size_t size)
Safe-wrapper around realloc which exits if realloc returns NULL (meaning that there is no more memory...
void ewmh_update_active_window(xcb_window_t window)
Updates _NET_ACTIVE_WINDOW with the currently focused window.
struct Colortriple * color
void ipc_send_window_event(const char *property, Con *con)
For the window events we send, along the usual "change" field, also the window container, in "container".
#define CIRCLEQ_INSERT_TAIL(head, elm, field)
#define TAILQ_HEAD(name, type)
#define XCB_ICCCM_WM_STATE_NORMAL
void x_con_kill(Con *con)
Kills the window decoration associated with the given container.
xcb_window_t focused_id
Stores the X11 window ID of the currently focused window.
#define XCB_ATOM_CARDINAL
kill_window_t
parameter to specify whether tree_close() and x_window_kill() should kill only this specific window o...
void x_raise_con(Con *con)
Raises the specified container in the internal stack of X windows.
void x_con_init(Con *con, uint16_t depth)
Initializes the X11 part for the given container.