2 #define I3__FILE__ "con.c"
38 while (parent && parent->
type != CT_WORKSPACE && parent->
type != CT_DOCKAREA) {
58 new->current_border_width = -1;
60 DLOG(
"opening window %d\n", cnt);
64 new->name = strdup(
colors[cnt]);
67 if ((cnt % (
sizeof(
colors) /
sizeof(
char*))) == 0)
99 struct nodes_head *nodes_head = &(parent->nodes_head);
100 struct focus_head *focus_head = &(parent->focus_head);
104 if (con->
type == CT_WORKSPACE) {
105 DLOG(
"it's a workspace. num = %d\n", con->
num);
110 if (con->
num < current->
num) {
114 while (current->
num != -1 && con->
num > current->
num) {
127 goto add_to_focus_head;
130 if (con->
type == CT_FLOATING_CON) {
131 DLOG(
"Inserting into floating containers\n");
137 if (loop->
type == CT_FLOATING_CON)
151 if (con->
window != NULL &&
152 parent->
type == CT_WORKSPACE &&
154 DLOG(
"Parent is a workspace. Applying default layout...\n");
158 nodes_head = &(target->nodes_head);
159 focus_head = &(target->focus_head);
168 if (current && parent->
type != CT_OUTPUT) {
169 DLOG(
"Inserting con = %p after last focused tiling con %p\n",
189 if (con->
type == CT_FLOATING_CON) {
205 DLOG(
"con_focus = %p\n", con);
268 if (con->
type == CT_WORKSPACE)
272 DLOG(
"container %p does not accept windows, it is a split container.\n", con);
277 return (con->
window == NULL);
287 while (result != NULL && result->
type != CT_OUTPUT)
291 assert(result != NULL);
301 while (result != NULL && result->
type != CT_WORKSPACE)
312 DLOG(
"Searching for parent of Con %p with orientation %d\n", con, orientation);
314 if (parent->
type == CT_FLOATING_CON)
317 DLOG(
"Need to go one level further up\n");
321 (parent->
type == CT_FLOATING_CON ||
322 parent->
type == CT_OUTPUT ||
328 DLOG(
"Result: %p\n", parent);
348 Con *current, *child;
359 current = entry->
con;
379 TAILQ_FOREACH(child, &(current->floating_head), floating_windows) {
394 return (con->
name[0] ==
'_' && con->
name[1] ==
'_');
403 DLOG(
"checking if con %p is floating\n", con);
404 return (con->
floating >= FLOATING_AUTO_ON);
414 if (con->
type == CT_FLOATING_CON)
417 if (con->
floating >= FLOATING_AUTO_ON)
420 if (con->
type == CT_WORKSPACE || con->
type == CT_OUTPUT)
459 if (con->
frame == frame)
479 if (store_match != NULL)
480 *store_match = match;
488 TAILQ_FOREACH(child, &(con->floating_head), floating_windows) {
492 if (store_match != NULL)
493 *store_match = match;
531 int children_with_percent = 0;
535 ++children_with_percent;
541 if (children_with_percent != children) {
544 if (children_with_percent == 0)
545 total += (child->
percent = 1.0);
546 else total += (child->
percent = total / children_with_percent);
555 child->
percent = 1.0 / children;
556 }
else if (total != 1.0) {
568 Con *workspace, *fullscreen;
570 if (con->
type == CT_WORKSPACE) {
571 DLOG(
"You cannot make a workspace fullscreen.\n");
575 DLOG(
"toggling fullscreen for %p / %s\n", con, con->
name);
578 if (fullscreen_mode == CF_GLOBAL)
584 if (fullscreen != NULL) {
588 LOG(
"Disabling fullscreen for (%p/%s) upon user request\n",
589 fullscreen, fullscreen->
name);
609 unsigned int num = 0;
612 values[num++] = A__NET_WM_STATE_FULLSCREEN;
614 xcb_change_property(
conn, XCB_PROP_MODE_REPLACE, con->
window->
id,
638 LOG(
"Cannot move out of a fullscreen container");
643 DLOG(
"Using FLOATINGCON instead\n");
648 if (workspace == source_ws) {
649 DLOG(
"Not moving, already there\n");
653 if (con->
type == CT_WORKSPACE) {
656 while (!
TAILQ_EMPTY(&(source_ws->floating_head))) {
667 ELOG(
"Workspace failed to move its contents into a container!\n");
687 if (next->
type != CT_WORKSPACE) {
688 DLOG(
"next originally = %p / %s / type %d\n", next, next->
name, next->
type);
696 if (floatingcon != NULL) {
697 DLOG(
"floatingcon, going up even further\n");
698 next = floatingcon->
parent;
701 if (con->
type == CT_FLOATING_CON) {
703 DLOG(
"This is a floating window, using workspace %p / %s\n", ws, ws->
name);
707 if (source_output != dest_output) {
710 if (fix_coordinates && con->
type == CT_FLOATING_CON) {
712 }
else DLOG(
"Not fixing coordinates, fix_coordinates flag = %d\n", fix_coordinates);
737 DLOG(
"Re-attaching container to %p / %s\n", next, next->
name);
768 if (source_output != dest_output &&
771 DLOG(
"Moved to a different output, focusing target\n");
780 if (source_ws == current_ws)
787 xcb_get_property_cookie_t cookie;
788 xcb_get_property_reply_t *startup_id_reply;
796 cookie = xcb_get_property(
conn,
false, child->
window->
id,
797 A__NET_STARTUP_ID, XCB_GET_PROPERTY_TYPE_ANY, 0, 512);
798 startup_id_reply = xcb_get_property_reply(
conn, cookie, NULL);
801 if (sequence != NULL)
808 A__NET_STARTUP_ID, XCB_GET_PROPERTY_TYPE_ANY, 0, 512);
809 startup_id_reply = xcb_get_property_reply(
conn, cookie, NULL);
812 if (sequence != NULL)
816 CALL(parent, on_remove_child);
838 DLOG(
"Someone called con_orientation() on a con with L_DEFAULT, this is a bug in the code.\n");
844 DLOG(
"con_orientation() called on dockarea/output (%d) container %p\n", con->
layout, con);
849 DLOG(
"con_orientation() ran into default\n");
864 if (con->
type == CT_FLOATING_CON) {
865 DLOG(
"selecting next for CT_FLOATING_CON\n");
867 DLOG(
"next = %p\n", next);
869 next =
TAILQ_PREV(con, floating_head, floating_windows);
870 DLOG(
"using prev, next = %p\n", next);
875 DLOG(
"no more floating containers for next = %p, restoring workspace focus\n", next);
879 DLOG(
"skipping container itself, we want the next client\n");
883 if (next ==
TAILQ_END(&(ws->focus_head))) {
884 DLOG(
"Focus list empty, returning ws\n");
897 DLOG(
"selecting workspace for dock client\n");
905 DLOG(
"Using first entry %p\n", first);
929 DLOG(
"con_get_next(way=%c, orientation=%d)\n", way, orientation);
933 DLOG(
"need to go one level further up\n");
935 LOG(
"that's a workspace, we can't go further up\n");
946 if (next ==
TAILQ_END(&(parent->nodes_head)))
951 if (next ==
TAILQ_END(&(cur->nodes_head)))
954 DLOG(
"next = %p\n", next);
989 if (child->
type == CT_FLOATING_CON)
995 }
while (before != next && next !=
focused);
1010 DLOG(
"con_descend_direction(%p, orientation %d, direction %d)\n", con, orientation, direction);
1012 if (orientation ==
HORIZ) {
1017 else most =
TAILQ_LAST(&(con->nodes_head), nodes_head);
1018 }
else if (orientation ==
VERT) {
1023 if (current->
type != CT_FLOATING_CON) {
1035 if (direction ==
D_UP || direction ==
D_DOWN) {
1036 if (orientation ==
VERT) {
1039 if (direction ==
D_UP)
1040 most =
TAILQ_LAST(&(con->nodes_head), nodes_head);
1042 }
else if (orientation ==
HORIZ) {
1047 if (current->
type != CT_FLOATING_CON) {
1077 DLOG(
"Effective border width is set to: %d\n", border_width);
1081 return (
Rect){ 0, 0, 0, 0 };
1084 result = (
Rect){border_width, 0 , -(2 * border_width), -(border_width)};
1086 result = (
Rect){border_width, border_width, -(2 * border_width), -(2 * border_width)};
1089 result.
x -= border_width;
1090 result.
width += border_width;
1093 result.
width += border_width;
1096 result.
y -= border_width;
1097 result.
height += border_width;
1100 result.
height += border_width;
1137 DLOG(
"this one is fullscreen! overriding BS_NONE\n");
1171 DLOG(
"This is a floating container\n");
1205 DLOG(
"con_set_layout(%p, %d), con->type = %d\n",
1206 con, layout, con->
type);
1211 if (con->
type != CT_WORKSPACE)
1217 if (con->
layout == L_SPLITH || con->
layout == L_SPLITV)
1224 if (con->
type == CT_WORKSPACE &&
1225 (layout == L_STACKED || layout == L_TABBED)) {
1227 DLOG(
"Setting workspace_layout to %d\n", layout);
1230 DLOG(
"Creating new split container\n");
1241 if (old_focused ==
TAILQ_END(&(con->focus_head)))
1245 DLOG(
"Moving cons\n");
1254 DLOG(
"Attaching new split to ws\n");
1266 if (layout == L_DEFAULT) {
1278 if (con->
layout == L_DEFAULT)
1298 if (con->
type != CT_WORKSPACE)
1300 DLOG(
"con_toggle_layout(%p, %s), parent = %p\n", con, toggle_mode, parent);
1302 if (strcmp(toggle_mode,
"split") == 0) {
1306 if (parent->
layout != L_SPLITH && parent->
layout != L_SPLITV)
1309 if (parent->
layout == L_SPLITH)
1314 if (parent->
layout == L_STACKED)
1316 else if (parent->
layout == L_TABBED) {
1317 if (strcmp(toggle_mode,
"all") == 0)
1320 }
else if (parent->
layout == L_SPLITH || parent->
layout == L_SPLITV) {
1321 if (strcmp(toggle_mode,
"all") == 0) {
1325 if (parent->
layout == L_SPLITH)
1342 DLOG(
"on_remove_child\n");
1346 if (con->
type == CT_OUTPUT ||
1347 con->
type == CT_ROOT ||
1348 con->
type == CT_DOCKAREA) {
1349 DLOG(
"not handling, type = %d\n", con->
type);
1354 if (con->
type == CT_WORKSPACE) {
1356 LOG(
"Closing old workspace (%p / %s), it is empty\n", con, con->
name);
1358 ipc_send_event(
"workspace", I3_IPC_EVENT_WORKSPACE,
"{\"change\":\"empty\"}");
1368 if (children == 0) {
1369 DLOG(
"Container empty, closing\n");
1381 DLOG(
"Determining minimum size for con %p\n", con);
1384 DLOG(
"leaf node, returning 75x50\n");
1385 return (
Rect){ 0, 0, 75, 50 };
1388 if (con->
type == CT_FLOATING_CON) {
1389 DLOG(
"floating con\n");
1394 if (con->
layout == L_STACKED || con->
layout == L_TABBED) {
1395 uint32_t max_width = 0, max_height = 0, deco_height = 0;
1400 max_width =
max(max_width, min.
width);
1401 max_height =
max(max_height, min.
height);
1403 DLOG(
"stacked/tabbed now, returning %d x %d + deco_rect = %d\n",
1404 max_width, max_height, deco_height);
1405 return (
Rect){ 0, 0, max_width, max_height + deco_height };
1416 if (con->
layout == L_SPLITH) {
1424 DLOG(
"split container, returning width = %d x height = %d\n", width,
height);
1428 ELOG(
"Unhandled case, type = %d, layout = %d, split = %d\n",
1470 if (fs->
type == CT_WORKSPACE)
1525 bool new_urgency_value = con->
urgent;
1526 while (parent && parent->
type != CT_WORKSPACE && parent->
type != CT_DOCKAREA) {
1527 if (new_urgency_value) {
1566 if (con->
layout == L_DEFAULT)
1568 else if (con->
layout == L_SPLITV)
1570 else if (con->
layout == L_SPLITH)
1572 else if (con->
layout == L_TABBED)
1574 else if (con->
layout == L_STACKED)
1584 (
TAILQ_FIRST(&(con->nodes_head)) == child ?
"" :
" "), child_txt);
1594 return complete_buf;