13 #define MAX(x, y) ((x) > (y) ? (x) : (y)) 26 Rect outputs_dimensions = {0, 0, 0, 0};
31 return outputs_dimensions;
53 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
window->
id,
54 A_I3_FLOATING_WINDOW, XCB_ATOM_CARDINAL, 32, 1, &val);
56 xcb_delete_property(
conn, con->
window->
id, A_I3_FLOATING_WINDOW);
70 const int floating_sane_min_height = 50;
71 const int floating_sane_min_width = 75;
72 Rect floating_sane_max_dimensions;
86 if (focused_con->
window != NULL) {
174 bool set_focus = (con ==
focused);
177 LOG(
"Container is a dock window, not enabling floating mode.\n");
182 LOG(
"Container is already in floating mode, not doing anything.\n");
186 if (con->
type == CT_WORKSPACE) {
187 LOG(
"Container is a workspace, not enabling floating mode.\n");
191 Con *focus_head_placeholder = NULL;
192 bool focus_before_parent =
true;
197 while (ancestor->
parent->
type != CT_WORKSPACE) {
199 ancestor = ancestor->
parent;
211 if (focus_before_parent) {
231 nc->
type = CT_FLOATING_CON;
239 if (focus_before_parent) {
240 if (focus_head_placeholder) {
246 if (focus_head_placeholder) {
257 DLOG(
"Old container empty after setting this child to floating, closing\n");
265 sasprintf(&name,
"[i3 con] floatingcon around %p", con);
274 Rect zero = {0, 0, 0, 0};
278 if (memcmp(&(nc->
rect), &zero,
sizeof(
Rect)) == 0) {
279 DLOG(
"Geometry not set, combining children\n");
325 DLOG(
"Centering above leader\n");
337 if (!current_output || current_output->
con != correct_output) {
338 DLOG(
"This floating window is on the wrong output, fixing coordinates (currently (%d, %d))\n",
343 if (current_output) {
348 if (!current_output || current_output->
con != correct_output) {
359 nc->
rect.
y -= deco_height;
361 DLOG(
"Corrected y = %d (deco_height = %d)\n", nc->
rect.
y, deco_height);
376 LOG(
"Container isn't floating, not doing anything.\n");
382 LOG(
"Can't disable floating for container in internal workspace.\n");
387 if (tiling_focused->
type == CT_WORKSPACE) {
413 if (con->
type == CT_FLOATING_CON) {
414 ELOG(
"Cannot toggle floating mode on con = %p because it is of type CT_FLOATING_CON.\n", con);
420 LOG(
"already floating, re-setting to tiling\n");
434 DLOG(
"Raising floating con %p / %s\n", con, con->
name);
448 ELOG(
"No output found at destination coordinates?\n");
453 DLOG(
"still the same ws\n");
457 DLOG(
"Need to re-assign!\n");
461 DLOG(
"Moving con %p / %s to workspace %p / %s\n", con, con->
name, ws, ws->
name);
482 assert(con->
type == CT_FLOATING_CON);
484 xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(
conn, xcb_query_pointer(
conn,
root), NULL);
486 ELOG(
"could not query pointer position, not moving this container\n");
491 if (output == NULL) {
492 ELOG(
"The pointer is not on any output, cannot move the container here.\n");
497 int32_t
x = reply->root_x - con->
rect.
width / 2;
502 x =
MAX(x, (int32_t)output->
rect.
x);
503 y =
MAX(y, (int32_t)output->
rect.
y);
514 const struct xcb_button_press_event_t *
event = extra;
517 con->rect.x = old_rect->x + (new_x -
event->root_x);
518 con->rect.y = old_rect->y + (new_y -
event->root_y);
538 DLOG(
"floating_drag_window\n");
551 DLOG(
"The container has been closed in the meantime.\n");
578 const xcb_button_press_event_t *
event;
583 const xcb_button_press_event_t *
event = params->
event;
586 int32_t dest_x = con->rect.x;
587 int32_t dest_y = con->rect.y;
589 uint32_t dest_height;
591 double ratio = (double)old_rect->width / old_rect->height;
596 dest_width = old_rect->width - (new_x -
event->root_x);
598 dest_width = old_rect->width + (new_x -
event->root_x);
601 dest_height = old_rect->height - (new_y -
event->root_y);
603 dest_height = old_rect->height + (new_y -
event->root_y);
607 dest_width =
max(dest_width, (
int)(dest_height * ratio));
608 dest_height =
max(dest_height, (
int)(dest_width / ratio));
611 con->rect = (
Rect){dest_x, dest_y, dest_width, dest_height};
618 if (corner & BORDER_LEFT)
619 dest_x = old_rect->x + (old_rect->width - con->rect.width);
621 if (corner & BORDER_TOP)
622 dest_y = old_rect->y + (old_rect->height - con->rect.height);
624 con->rect.x = dest_x;
625 con->rect.y = dest_y;
640 const xcb_button_press_event_t *
event) {
641 DLOG(
"floating_resize_window\n");
647 if (event->event_x <= (int16_t)(con->
rect.
width / 2))
653 if (event->event_y <= (int16_t)(con->
rect.
height / 2)) {
669 DLOG(
"The container has been closed in the meantime.\n");
704 xcb_motion_notify_event_t *last_motion_notify = NULL;
705 xcb_generic_event_t *
event;
707 while ((event = xcb_poll_for_event(
conn)) != NULL) {
708 if (event->response_type == 0) {
709 xcb_generic_error_t *error = (xcb_generic_error_t *)event;
710 DLOG(
"X11 Error received (probably harmless)! sequence 0x%x, error_code = %d\n",
711 error->sequence, error->error_code);
717 int type = (
event->response_type & 0x7F);
720 case XCB_BUTTON_RELEASE:
725 DLOG(
"A key was pressed during drag, reverting changes.\n");
730 case XCB_UNMAP_NOTIFY: {
731 xcb_unmap_notify_event_t *unmap_event = (xcb_unmap_notify_event_t *)event;
735 DLOG(
"UnmapNotify for window 0x%08x (container %p)\n", unmap_event->window, con);
738 DLOG(
"UnmapNotify for a managed window on the current workspace, aborting\n");
747 case XCB_MOTION_NOTIFY:
749 FREE(last_motion_notify);
750 last_motion_notify = (xcb_motion_notify_event_t *)event;
754 DLOG(
"Passing to original handler\n");
759 if (last_motion_notify != (xcb_motion_notify_event_t *)event)
763 ev_break(EV_A_ EVBREAK_ONE);
768 free(last_motion_notify);
774 if (last_motion_notify == NULL) {
785 last_motion_notify->root_x,
786 last_motion_notify->root_y,
789 FREE(last_motion_notify);
815 xcb_grab_pointer_cookie_t cookie;
816 xcb_grab_pointer_reply_t *reply;
817 xcb_generic_error_t *error;
819 cookie = xcb_grab_pointer(
conn,
822 XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION,
829 if ((reply = xcb_grab_pointer_reply(
conn, cookie, &error)) == NULL) {
830 ELOG(
"Could not grab pointer (error_code = %d)\n", error->error_code);
838 xcb_grab_keyboard_cookie_t keyb_cookie;
839 xcb_grab_keyboard_reply_t *keyb_reply;
841 keyb_cookie = xcb_grab_keyboard(
conn,
849 if ((keyb_reply = xcb_grab_keyboard_reply(
conn, keyb_cookie, &error)) == NULL) {
850 ELOG(
"Could not grab keyboard (error_code = %d)\n", error->error_code);
852 xcb_ungrab_pointer(
conn, XCB_CURRENT_TIME);
869 prepare->data = &loop;
878 xcb_ungrab_keyboard(
conn, XCB_CURRENT_TIME);
879 xcb_ungrab_pointer(
conn, XCB_CURRENT_TIME);
896 ELOG(
"No output found at destination coordinates. Not repositioning.\n");
924 DLOG(
"floating resize to %dx%d px\n", x, y);
927 if (focused_con->
window == NULL) {
928 DLOG(
"No window is focused. Not resizing.\n");
953 DLOG(
"Fixing coordinates of floating window %p (rect (%d, %d), %d x %d)\n",
955 DLOG(
"old_rect = (%d, %d), %d x %d\n",
956 old_rect->
x, old_rect->
y, old_rect->
width, old_rect->
height);
957 DLOG(
"new_rect = (%d, %d), %d x %d\n",
958 new_rect->
x, new_rect->
y, new_rect->
width, new_rect->
height);
961 int32_t rel_x = con->
rect.
x - old_rect->
x + (int32_t)(con->
rect.
width / 2);
962 int32_t rel_y = con->
rect.
y - old_rect->
y + (int32_t)(con->
rect.
height / 2);
965 DLOG(
"rel_x = %d, rel_y = %d, fraction_x = %f, fraction_y = %f, output->w = %d, output->h = %d\n",
966 rel_x, rel_y, (
double)rel_x / old_rect->
width, (
double)rel_y / old_rect->
height,
969 con->
rect.
x = (int32_t)new_rect->
x + (
double)(rel_x * (int32_t)new_rect->
width) / (int32_t)old_rect->
width - (int32_t)(con->
rect.
width / 2);
970 con->
rect.
y = (int32_t)new_rect->
y + (
double)(rel_y * (int32_t)new_rect->
height) / (int32_t)old_rect->
height - (int32_t)(con->
rect.
height / 2);
971 DLOG(
"Resulting coordinates: x = %d, y = %d\n", con->
rect.
x, con->
rect.
y);
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 main_set_x11_cb(bool enable)
Enable or disable the main X11 event handling function.
void floating_raise_con(Con *con)
Raises the given container in the list of floating containers.
void con_fix_percent(Con *con)
Updates the percent attribute of the children of the given container.
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...
void con_detach(Con *con)
Detaches the given container from its current parent.
int32_t floating_maximum_height
struct outputs_head outputs
void toggle_floating_mode(Con *con, bool automatic)
Calls floating_enable() for tiling containers and floating_disable() for floating containers...
bool con_exists(Con *con)
Returns true if the given container (still) exists.
void floating_enable(Con *con, bool automatic)
Enables floating mode for the given container by detaching it from its parent, creating a new contain...
void workspace_show(Con *workspace)
Switches to the given workspace.
static bool drain_drag_events(EV_P, struct drag_x11_cb *dragloop)
Output * output_containing_rect(Rect rect)
In output_containing_rect, we check if any active output contains part of the container.
const xcb_button_press_event_t * event
#define TAILQ_EMPTY(head)
int32_t floating_maximum_width
Maximum and minimum dimensions of a floating window.
void x_push_changes(Con *con)
Pushes all changes (state of each node, see x_push_node() and the window stack) to X11...
void x_set_warp_to(Rect *rect)
Set warp_to coordinates.
void floating_drag_window(Con *con, const xcb_button_press_event_t *event)
Called when the user clicked on the titlebar of a floating window.
xcb_cursor_t xcursor_get_cursor(enum xcursor_cursor_t c)
xcb_connection_t * conn
XCB connection and root screen.
An Output is a physical output on your graphics driver.
bool con_is_leaf(Con *con)
Returns true when this node is a leaf node (has no children)
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".
xcb_screen_t * root_screen
Rect rect
x, y, width, height
Con * con_by_window_id(xcb_window_t window)
Returns the container with the given client window ID or NULL if no such container exists...
#define TAILQ_INSERT_HEAD(head, elm, field)
void floating_center(Con *con, Rect rect)
Centers a floating con above the specified rect.
bool floating_reposition(Con *con, Rect newrect)
Repositions the CT_FLOATING_CON to have the coordinates specified by newrect, but only if the coordin...
int32_t floating_minimum_height
#define TAILQ_REMOVE(head, elm, field)
bool floating_maybe_reassign_ws(Con *con)
Checks if con’s coordinates are within its workspace and re-assigns it to the actual workspace if no...
#define TAILQ_FIRST(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...
void floating_fix_coordinates(Con *con, Rect *old_rect, Rect *new_rect)
Fixes the coordinates of the floating window whenever the window gets reassigned to a different outpu...
Con * con
Pointer to the Con which represents this output.
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
Con * con_get_output(Con *con)
Gets the output container (first container with CT_OUTPUT in hierarchy) this node is on...
int con_num_children(Con *con)
Returns the number of children of this container.
Stores a rectangle, for example the size of a window, the child window etc.
bool con_is_floating(Con *con)
Returns true if the node is floating.
#define TAILQ_NEXT(elm, field)
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
bool con_is_docked(Con *con)
Returns true if the container is a docked container.
drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_window_t confine_to, border_t border, int cursor, callback_t callback, const void *extra)
This function grabs your pointer and keyboard and lets you drag stuff around (borders).
void floating_disable(Con *con, bool automatic)
Disables floating mode for the given container by re-attaching the container to its old parent...
void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool dont_warp, bool ignore_focus)
Moves the given container to the currently focused container on the given workspace.
void insert_con_into(Con *con, Con *target, position_t position)
This function detaches 'con' from its parent and inserts it either before or after 'target'...
struct Rect geometry
the geometry this window requested when getting mapped
static void xcb_drag_prepare_cb(EV_P_ ev_prepare *w, int revents)
void render_con(Con *con, bool render_fullscreen)
"Renders" the given container (and its children), meaning that all rects are updated correctly...
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
static void floating_set_hint_atom(Con *con, bool floating)
Con * output_get_content(Con *output)
Returns the output container below the given output container.
void(* callback_t)(Con *, Rect *, uint32_t, uint32_t, const void *)
Callback for dragging.
void floating_check_size(Con *floating_con)
Called when a floating window is created or resized.
void floating_resize_window(Con *con, const bool proportional, const xcb_button_press_event_t *event)
Called when the user clicked on a floating window while holding the floating_modifier and the right m...
#define TAILQ_INSERT_AFTER(head, listelm, elm, field)
Output * get_output_from_rect(Rect rect)
Returns the active output which contains the midpoint of the given rect.
enum Con::@21 floating
floating? (= not in tiling layout) This cannot be simply a bool because we want to keep track of whet...
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
border_t
On which border was the dragging initiated?
enum Con::@22 scratchpad_state
bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent)
Closes the given container including all children.
A 'Con' represents everything from the X11 root window down to a single X11 window.
int con_border_style(Con *con)
Use this function to get a container’s border style.
Con * con_new(Con *parent, i3Window *window)
A wrapper for con_new_skeleton, to retain the old con_new behaviour.
xcb_window_t leader
Holds the xcb_window_t (just an ID) for the leader window (logical parent for toolwindows and similar...
int32_t floating_minimum_width
#define TAILQ_PREV(elm, headname, field)
struct ev_loop * main_loop
static Rect total_outputs_dimensions(void)
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
Con * con_descend_tiling_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
void con_activate(Con *con)
Sets input focus to the given container and raises it to the top.
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...
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...
int render_deco_height(void)
Returns the height for the decorations.
void floating_resize(Con *floating_con, int x, int y)
Sets size of the CT_FLOATING_CON to specified dimensions.
DRAGGING_CB(drag_window_callback)
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
void floating_move_to_pointer(Con *con)
Moves the given floating con to the current pointer position.
drag_result_t
This is the return value of a drag operation like drag_pointer.
#define TAILQ_INSERT_TAIL(head, elm, field)
#define TAILQ_FOREACH(var, head, field)
border_style_t default_floating_border
The default border style for new floating windows.
border_style_t border_style
void handle_event(int type, xcb_generic_event_t *event)
Takes an xcb_generic_event_t and calls the appropriate handler, based on the event type...