19xcb_randr_get_output_primary_reply_t *
primary;
37 if (output->
id ==
id) {
51 const bool get_primary = (strcasecmp(
"primary", name) == 0);
52 const bool get_non_primary = (strcasecmp(
"nonprimary", name) == 0);
56 if (require_active && !output->
active) {
59 if (output->
primary && get_primary) {
62 if (!output->
primary && get_non_primary) {
81 Output *output, *result = NULL;
98 die(
"No usable outputs available.\n");
128 DLOG(
"comparing x=%d y=%d with x=%d and y=%d width %d height %d\n",
146 unsigned int mid_x = rect.
x + rect.
width / 2;
147 unsigned int mid_y = rect.
y + rect.
height / 2;
164 DLOG(
"comparing x=%d y=%d %dx%d with x=%d and y=%d %dx%d\n",
185 int lx = rect.
x, uy = rect.
y;
193 int lx_o = (int)output->
rect.
x, uy_o = (
int)output->
rect.
y;
195 DLOG(
"comparing x=%d y=%d with x=%d and y=%d width %d height %d\n",
197 int left =
max(lx, lx_o);
198 int right =
min(rx, rx_o);
199 int bottom =
min(by, by_o);
200 int top =
max(uy, uy_o);
201 if (left < right && bottom > top) {
202 long area = (right - left) * (bottom - top);
203 if (area > max_area) {
228 }
else if (direction ==
D_LEFT) {
230 }
else if (direction ==
D_DOWN) {
265 other = &(output->
rect);
267 if ((direction ==
D_RIGHT && other->x > cur->
x) ||
268 (direction ==
D_LEFT && other->x < cur->
x)) {
271 if ((other->y + other->height) <= cur->
y ||
272 (cur->
y + cur->
height) <= other->y) {
275 }
else if ((direction ==
D_DOWN && other->y > cur->
y) ||
276 (direction ==
D_UP && other->y < cur->
y)) {
279 if ((other->x + other->width) <= cur->
x ||
280 (cur->
x + cur->
width) <= other->x) {
296 if ((direction ==
D_RIGHT && other->x < best->
rect.
x) ||
297 (direction ==
D_LEFT && other->x > best->
rect.
x) ||
298 (direction ==
D_DOWN && other->y < best->
rect.
y) ||
299 (direction ==
D_UP && other->y > best->
rect.
y)) {
306 if ((direction ==
D_RIGHT && other->x > best->
rect.
x) ||
307 (direction ==
D_LEFT && other->x < best->
rect.
x) ||
308 (direction ==
D_DOWN && other->y > best->
rect.
y) ||
309 (direction ==
D_UP && other->y < best->
rect.
y)) {
347 Con *con = NULL, *current;
361 DLOG(
"Using existing con %p / %s\n", con, con->
name);
369 con->
type = CT_OUTPUT;
382 DLOG(
"Not adding workspace, this was a reused con\n");
386 DLOG(
"Changing layout, adding top/bottom dockarea\n");
388 topdock->
type = CT_DOCKAREA;
393 match->
dock = M_DOCK_TOP;
408 DLOG(
"adding main content container\n");
410 content->
type = CT_CON;
422 bottomdock->
type = CT_DOCKAREA;
427 match->
dock = M_DOCK_BOTTOM;
472 if (output->
con != workspace_out) {
476 DLOG(
"Moving workspace \"%s\" from output \"%s\" to \"%s\" due to assignment\n",
510 LOG(
"Initializing first assigned workspace \"%s\" for output \"%s\"\n",
517 DLOG(
"Now adding a workspace\n");
521 if (previous_focus) {
538 DLOG(
"Output mode changed, updating rect\n");
539 assert(
output->con != NULL);
542 Con *content, *workspace, *child;
550 TAILQ_FOREACH (child, &(workspace->floating_head), floating_windows) {
567 DLOG(
"Setting workspace [%d,%s]'s layout to %d.\n", workspace->
num, workspace->
name, workspace->
layout);
568 if ((child =
TAILQ_FIRST(&(workspace->nodes_head)))) {
572 DLOG(
"Setting child [%d,%s]'s layout to %d.\n", child->
num, child->
name, child->
layout);
583#if XCB_RANDR_MINOR_VERSION < 5
592 DLOG(
"Querying outputs using RandR 1.5\n");
593 xcb_generic_error_t *err;
594 xcb_randr_get_monitors_reply_t *monitors =
595 xcb_randr_get_monitors_reply(
598 ELOG(
"Could not get RandR monitors: X11 error code %d\n", err->error_code);
609 output->to_be_disabled =
true;
613 DLOG(
"%d RandR monitors found (timestamp %d)\n",
614 xcb_randr_get_monitors_monitors_length(monitors),
615 monitors->timestamp);
617 xcb_randr_monitor_info_iterator_t iter;
618 for (iter = xcb_randr_get_monitors_monitors_iterator(monitors);
620 xcb_randr_monitor_info_next(&iter)) {
621 const xcb_randr_monitor_info_t *monitor_info = iter.data;
622 xcb_get_atom_name_reply_t *atom_reply =
623 xcb_get_atom_name_reply(
624 conn, xcb_get_atom_name(
conn, monitor_info->name), &err);
626 ELOG(
"Could not get RandR monitor name: X11 error code %d\n", err->error_code);
632 xcb_get_atom_name_name_length(atom_reply),
633 xcb_get_atom_name_name(atom_reply));
643 xcb_randr_output_t *randr_outputs = xcb_randr_monitor_info_outputs(monitor_info);
644 int randr_output_len = xcb_randr_monitor_info_outputs_length(monitor_info);
645 for (
int i = 0; i < randr_output_len; i++) {
646 xcb_randr_output_t randr_output = randr_outputs[i];
648 xcb_randr_get_output_info_reply_t *info =
649 xcb_randr_get_output_info_reply(
conn,
650 xcb_randr_get_output_info(
conn, randr_output, monitors->timestamp),
653 if (info != NULL && info->crtc != XCB_NONE) {
656 xcb_randr_get_output_info_name_length(info),
657 xcb_randr_get_output_info_name(info));
659 if (strcmp(
name, oname) != 0) {
675 if (monitor_info->primary) {
684 new->to_be_disabled =
false;
686 new->primary = monitor_info->primary;
693 new->changed = update_x || update_y || update_w || update_h;
695 DLOG(
"name %s, x %d, y %d, width %d px, height %d px, width %d mm, height %d mm, primary %d, automatic %d\n",
697 monitor_info->x, monitor_info->y, monitor_info->width, monitor_info->height,
698 monitor_info->width_in_millimeters, monitor_info->height_in_millimeters,
699 monitor_info->primary, monitor_info->automatic);
716 xcb_randr_get_output_info_reply_t *output,
718 xcb_randr_get_screen_resources_current_reply_t *res) {
720 xcb_randr_get_crtc_info_reply_t *crtc;
723 bool existing = (
new != NULL);
738 xcb_randr_get_output_info_name_length(output),
739 xcb_randr_get_output_info_name(output));
747 if (output->crtc == XCB_NONE) {
754 }
else if (new->active) {
755 new->to_be_disabled =
true;
760 xcb_randr_get_crtc_info_cookie_t icookie;
761 icookie = xcb_randr_get_crtc_info(
conn, output->crtc, cts);
762 if ((crtc = xcb_randr_get_crtc_info_reply(
conn, icookie, NULL)) == NULL) {
763 DLOG(
"Skipping output %s: could not get CRTC (%p)\n",
773 const bool updated = update_x || update_y || update_w || update_h;
775 new->active = (
new->rect.width != 0 &&
new->rect.height != 0);
777 DLOG(
"width/height 0/0, disabling output\n");
781 DLOG(
"mode: %dx%d+%d+%d\n", new->rect.width, new->rect.height,
782 new->rect.x, new->rect.y);
787 if (!updated || !existing) {
806 DLOG(
"Querying outputs using RandR ≤ 1.4\n");
809 xcb_randr_get_screen_resources_current_cookie_t rcookie;
810 rcookie = xcb_randr_get_screen_resources_current(
conn,
root);
811 xcb_randr_get_output_primary_cookie_t pcookie;
812 pcookie = xcb_randr_get_output_primary(
conn,
root);
814 if ((
primary = xcb_randr_get_output_primary_reply(
conn, pcookie, NULL)) == NULL) {
815 ELOG(
"Could not get RandR primary output\n");
820 xcb_randr_get_screen_resources_current_reply_t *res =
821 xcb_randr_get_screen_resources_current_reply(
conn, rcookie, NULL);
823 ELOG(
"Could not query screen resources.\n");
829 const xcb_timestamp_t cts = res->config_timestamp;
831 const int len = xcb_randr_get_screen_resources_current_outputs_length(res);
834 xcb_randr_output_t *randr_outputs = xcb_randr_get_screen_resources_current_outputs(res);
837 xcb_randr_get_output_info_cookie_t ocookie[len];
838 for (
int i = 0; i < len; i++) {
839 ocookie[i] = xcb_randr_get_output_info(
conn, randr_outputs[i], cts);
843 for (
int i = 0; i < len; i++) {
844 xcb_randr_get_output_info_reply_t *output;
846 if ((output = xcb_randr_get_output_info_reply(
conn, ocookie[i], NULL)) == NULL) {
878 if (current != next &&
TAILQ_EMPTY(&(current->focus_head))) {
880 DLOG(
"Getting rid of current = %p / %s (empty, unfocused)\n", current, current->
name);
884 DLOG(
"Detaching current = %p / %s\n", current, current->
name);
886 DLOG(
"Re-attaching current = %p / %s\n", current, current->
name);
888 DLOG(
"Fixing the coordinates of floating containers\n");
890 TAILQ_FOREACH (floating_con, &(current->floating_head), floating_windows) {
897 DLOG(
"now focusing next = %p\n", next);
905 if (child->
type != CT_DOCKAREA) {
908 DLOG(
"Handling dock con %p\n", child);
915 DLOG(
"Moving dock client %p to nc %p\n", dock, nc);
917 DLOG(
"Re-attaching\n");
923 DLOG(
"Destroying disappearing con %p\n", con);
942 DLOG(
"Active RandR output found. Disabling root output.\n");
947 DLOG(
"No active RandR output found. Enabling root output.\n");
957 DLOG(
"output %p / %s, position (%d, %d), checking for clones\n",
972 DLOG(
"output %p has the same position, its mode = %d x %d\n",
979 if (update_w || update_h) {
989 DLOG(
"new output mode %d x %d, other mode %d x %d\n",
1000 if (output->
active && output->
con == NULL) {
1016 DLOG(
"No output %s found, moving its old content to first output\n", con->
name);
1077 if (output->
con != NULL) {
1100 const xcb_query_extension_reply_t *extreply;
1105 extreply = xcb_get_extension_data(
conn, &xcb_randr_id);
1106 if (!extreply->present) {
1107 DLOG(
"RandR is not present, activating root output.\n");
1112 xcb_generic_error_t *err;
1113 xcb_randr_query_version_reply_t *randr_version =
1114 xcb_randr_query_version_reply(
1115 conn, xcb_randr_query_version(
conn, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION), &err);
1117 ELOG(
"Could not query RandR version: X11 error code %d\n", err->error_code);
1124 (randr_version->minor_version >= 5) &&
1127 free(randr_version);
1131 if (event_base != NULL) {
1132 *event_base = extreply->first_event;
1136 XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
1137 XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
1138 XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
1139 XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY);
Con * con_for_window(Con *con, i3Window *window, Match **store_match)
Returns the first container below 'con' which wants to swallow this window TODO: priority.
Con * con_new(Con *parent, i3Window *window)
A wrapper for con_new_skeleton, to retain the old con_new behaviour.
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
bool con_is_internal(Con *con)
Returns true if the container is internal, such as __i3_scratch.
void con_detach(Con *con)
Detaches the given container from its current parent.
void con_fix_percent(Con *con)
Updates the percent attribute of the children of the given container.
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
int con_num_children(Con *con)
Returns the number of children of this container.
void con_focus(Con *con)
Sets input focus to the given container.
void ewmh_update_desktop_properties(void)
Updates all the EWMH desktop properties.
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...
void match_init(Match *match)
Initializes the Match data structure.
char * output_primary_name(Output *output)
Retrieves the primary name of an output.
Output * get_output_for_con(Con *con)
Retrieves the output for a given container.
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Output * get_output_by_name(const char *name, const bool require_active)
Returns the output with the given name or NULL.
Output * get_output_from_rect(Rect rect)
Returns the active output which contains the midpoint of the given rect.
static void randr_query_outputs_14(void)
Output * output_containing_rect(Rect rect)
In output_containing_rect, we check if any active output contains part of the container.
Output * get_output_with_dimensions(Rect rect)
Returns the active output which spans exactly the area specified by rect or NULL if there is no outpu...
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 init_ws_for_output(Output *output)
Initializes at least one workspace for this output, trying the following steps until there is at leas...
void randr_query_outputs(void)
(Re-)queries the outputs via RandR and stores them in the list of outputs.
static void output_change_mode(xcb_connection_t *conn, Output *output)
static Output * get_output_by_id(xcb_randr_output_t id)
Output * get_output_next_wrap(direction_t direction, Output *current)
Like get_output_next with close_far == CLOSEST_OUTPUT, but wraps.
static void move_content(Con *con)
void output_init_con(Output *output)
Initializes a CT_OUTPUT Con (searches existing ones from inplace restart before) to use for the given...
Output * get_output_next(direction_t direction, Output *current, output_close_far_t close_far)
Gets the output which is the next one in the given direction.
struct outputs_head outputs
static Output * root_output
void randr_init(int *event_base, const bool disable_randr15)
We have just established a connection to the X server and need the initial XRandR information to setu...
Output * create_root_output(xcb_connection_t *conn)
Creates an output covering the root window.
Output * get_first_output(void)
Returns the first output which is active.
xcb_randr_get_output_primary_reply_t * primary
static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, xcb_randr_get_output_info_reply_t *output, xcb_timestamp_t cts, xcb_randr_get_screen_resources_current_reply_t *res)
static void fallback_to_root_output(void)
static bool has_randr_1_5
static bool randr_query_outputs_15(void)
void randr_disable_output(Output *output)
Disables the output and moves its content.
static bool any_randr_output_active(void)
bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent)
Closes the given container including all children.
struct all_cons_head all_cons
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
bool update_if_necessary(uint32_t *destination, const uint32_t new_value)
Updates *destination with new_value and returns true if it was changed or false if it was the same.
bool output_triggers_assignment(Output *output, struct Workspace_Assignment *assignment)
Returns true if the first output assigned to a workspace with the given workspace assignment is the s...
Con * create_workspace_on_output(Output *output, Con *content)
Returns a pointer to a new workspace in the given output.
void workspace_show(Con *workspace)
Switches to the given workspace.
void workspace_move_to_output(Con *ws, Output *output)
Move the given workspace to the specified output.
void workspace_show_by_name(const char *num)
Looks up the workspace by name and switches to it.
Con * get_assigned_output(const char *name, long parsed_num)
Returns the first output that is assigned to a workspace specified by the given name or number.
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.
xcb_connection_t * conn
XCB connection and root screen.
xcb_screen_t * root_screen
struct ws_assignments_head ws_assignments
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
void * scalloc(size_t num, size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
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...
#define SLIST_FOREACH(var, head, field)
#define TAILQ_FOREACH(var, head, field)
#define SLIST_INSERT_HEAD(head, elm, field)
#define TAILQ_INSERT_TAIL(head, elm, field)
#define SLIST_EMPTY(head)
#define TAILQ_FIRST(head)
#define SLIST_FIRST(head)
#define TAILQ_REMOVE(head, elm, field)
#define TAILQ_NEXT(elm, field)
#define TAILQ_HEAD_INITIALIZER(head)
#define TAILQ_EMPTY(head)
#define SLIST_REMOVE_HEAD(head, field)
#define TAILQ_INSERT_HEAD(head, elm, field)
#define GREP_FIRST(dest, head, condition)
int default_orientation
Default orientation for new containers.
Stores a rectangle, for example the size of a window, the child window etc.
Stores which workspace (by name or number) goes to which output and its gaps config.
An Output is a physical output on your graphics driver.
Con * con
Pointer to the Con which represents this output.
bool changed
Internal flags, necessary for querying RandR screens (happens in two stages)
bool active
Whether the output is currently active (has a CRTC attached with a valid mode)
xcb_randr_output_t id
Output id, so that we can requery the output directly later.
Rect rect
x, y, width, height
A "match" is a data structure which acts like a mask or expression to match certain windows or not.
enum Match::@15 insert_where
A 'Con' represents everything from the X11 root window down to a single X11 window.
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
fullscreen_mode_t fullscreen_mode