00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "all.h"
00013
00014 char *colors[] = {
00015 "#ff0000",
00016 "#00FF00",
00017 "#0000FF",
00018 "#ff00ff",
00019 "#00ffff",
00020 "#ffff00",
00021 "#aa0000",
00022 "#00aa00",
00023 "#0000aa",
00024 "#aa00aa"
00025 };
00026
00027 static void con_on_remove_child(Con *con);
00028
00029
00030
00031
00032
00033
00034
00035 Con *con_new(Con *parent, i3Window *window) {
00036 Con *new = scalloc(sizeof(Con));
00037 new->on_remove_child = con_on_remove_child;
00038 TAILQ_INSERT_TAIL(&all_cons, new, all_cons);
00039 new->type = CT_CON;
00040 new->window = window;
00041 new->border_style = config.default_border;
00042 static int cnt = 0;
00043 DLOG("opening window %d\n", cnt);
00044
00045
00046 DLOG("color %s\n", colors[cnt]);
00047 new->name = strdup(colors[cnt]);
00048
00049 cnt++;
00050 if ((cnt % (sizeof(colors) / sizeof(char*))) == 0)
00051 cnt = 0;
00052
00053 x_con_init(new);
00054
00055 TAILQ_INIT(&(new->floating_head));
00056 TAILQ_INIT(&(new->nodes_head));
00057 TAILQ_INIT(&(new->focus_head));
00058 TAILQ_INIT(&(new->swallow_head));
00059
00060 if (parent != NULL)
00061 con_attach(new, parent, false);
00062
00063 return new;
00064 }
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 void con_attach(Con *con, Con *parent, bool ignore_focus) {
00077 con->parent = parent;
00078 Con *loop;
00079 Con *current = NULL;
00080 struct nodes_head *nodes_head = &(parent->nodes_head);
00081 struct focus_head *focus_head = &(parent->focus_head);
00082
00083
00084
00085 if (con->type == CT_WORKSPACE) {
00086 DLOG("it's a workspace. num = %d\n", con->num);
00087 if (con->num == -1 || TAILQ_EMPTY(nodes_head)) {
00088 TAILQ_INSERT_TAIL(nodes_head, con, nodes);
00089 } else {
00090 current = TAILQ_FIRST(nodes_head);
00091 if (con->num < current->num) {
00092
00093 TAILQ_INSERT_HEAD(nodes_head, con, nodes);
00094 } else {
00095 while (current->num != -1 && con->num > current->num) {
00096 current = TAILQ_NEXT(current, nodes);
00097 if (current == TAILQ_END(nodes_head)) {
00098 current = NULL;
00099 break;
00100 }
00101 }
00102
00103 if (current)
00104 TAILQ_INSERT_BEFORE(current, con, nodes);
00105 else TAILQ_INSERT_TAIL(nodes_head, con, nodes);
00106 }
00107 }
00108 goto add_to_focus_head;
00109 }
00110
00111 if (con->type == CT_FLOATING_CON) {
00112 DLOG("Inserting into floating containers\n");
00113 TAILQ_INSERT_TAIL(&(parent->floating_head), con, floating_windows);
00114 } else {
00115 if (!ignore_focus) {
00116
00117 TAILQ_FOREACH(loop, &(parent->focus_head), focused) {
00118 if (loop->type == CT_FLOATING_CON)
00119 continue;
00120 current = loop;
00121 break;
00122 }
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132 if (con->window != NULL && parent->type == CT_WORKSPACE) {
00133 DLOG("Parent is a workspace. Applying default layout...\n");
00134 Con *target = workspace_attach_to(parent);
00135
00136
00137 nodes_head = &(target->nodes_head);
00138 focus_head = &(target->focus_head);
00139 con->parent = target;
00140 current = NULL;
00141
00142 DLOG("done\n");
00143 }
00144
00145
00146
00147 if (current && parent->type != CT_OUTPUT) {
00148 DLOG("Inserting con = %p after last focused tiling con %p\n",
00149 con, current);
00150 TAILQ_INSERT_AFTER(nodes_head, current, con, nodes);
00151 } else TAILQ_INSERT_TAIL(nodes_head, con, nodes);
00152 }
00153
00154 add_to_focus_head:
00155
00156
00157
00158 TAILQ_INSERT_TAIL(focus_head, con, focused);
00159 }
00160
00161
00162
00163
00164
00165 void con_detach(Con *con) {
00166 if (con->type == CT_FLOATING_CON) {
00167 TAILQ_REMOVE(&(con->parent->floating_head), con, floating_windows);
00168 TAILQ_REMOVE(&(con->parent->focus_head), con, focused);
00169 } else {
00170 TAILQ_REMOVE(&(con->parent->nodes_head), con, nodes);
00171 TAILQ_REMOVE(&(con->parent->focus_head), con, focused);
00172 }
00173 }
00174
00175
00176
00177
00178
00179
00180 void con_focus(Con *con) {
00181 assert(con != NULL);
00182 DLOG("con_focus = %p\n", con);
00183
00184
00185
00186 TAILQ_REMOVE(&(con->parent->focus_head), con, focused);
00187 TAILQ_INSERT_HEAD(&(con->parent->focus_head), con, focused);
00188 if (con->parent->parent != NULL)
00189 con_focus(con->parent);
00190
00191 focused = con;
00192 if (con->urgent) {
00193 con->urgent = false;
00194 workspace_update_urgent_flag(con_get_workspace(con));
00195 }
00196 DLOG("con_focus done = %p\n", con);
00197 }
00198
00199
00200
00201
00202
00203 bool con_is_leaf(Con *con) {
00204 return TAILQ_EMPTY(&(con->nodes_head));
00205 }
00206
00207
00208
00209
00210
00211
00212 bool con_accepts_window(Con *con) {
00213
00214 if (con->type == CT_WORKSPACE)
00215 return false;
00216
00217 if (con->orientation != NO_ORIENTATION) {
00218 DLOG("container %p does not accepts windows, orientation != NO_ORIENTATION\n", con);
00219 return false;
00220 }
00221
00222
00223 return (con->window == NULL);
00224 }
00225
00226
00227
00228
00229
00230
00231 Con *con_get_output(Con *con) {
00232 Con *result = con;
00233 while (result != NULL && result->type != CT_OUTPUT)
00234 result = result->parent;
00235
00236
00237 assert(result != NULL);
00238 return result;
00239 }
00240
00241
00242
00243
00244
00245 Con *con_get_workspace(Con *con) {
00246 Con *result = con;
00247 while (result != NULL && result->type != CT_WORKSPACE)
00248 result = result->parent;
00249 return result;
00250 }
00251
00252
00253
00254
00255
00256
00257 Con *con_parent_with_orientation(Con *con, orientation_t orientation) {
00258 DLOG("Searching for parent of Con %p with orientation %d\n", con, orientation);
00259 Con *parent = con->parent;
00260 if (parent->type == CT_FLOATING_CON)
00261 return NULL;
00262 while (con_orientation(parent) != orientation) {
00263 DLOG("Need to go one level further up\n");
00264 parent = parent->parent;
00265
00266 if (parent && parent->type == CT_FLOATING_CON)
00267 parent = NULL;
00268 if (parent == NULL)
00269 break;
00270 }
00271 DLOG("Result: %p\n", parent);
00272 return parent;
00273 }
00274
00275
00276
00277
00278
00279
00280 struct bfs_entry {
00281 Con *con;
00282
00283 TAILQ_ENTRY(bfs_entry) entries;
00284 };
00285
00286
00287
00288
00289
00290 Con *con_get_fullscreen_con(Con *con, int fullscreen_mode) {
00291 Con *current, *child;
00292
00293
00294
00295 TAILQ_HEAD(bfs_head, bfs_entry) bfs_head = TAILQ_HEAD_INITIALIZER(bfs_head);
00296 struct bfs_entry *entry = smalloc(sizeof(struct bfs_entry));
00297 entry->con = con;
00298 TAILQ_INSERT_TAIL(&bfs_head, entry, entries);
00299
00300 while (!TAILQ_EMPTY(&bfs_head)) {
00301 entry = TAILQ_FIRST(&bfs_head);
00302 current = entry->con;
00303 if (current != con && current->fullscreen_mode == fullscreen_mode) {
00304
00305 while (!TAILQ_EMPTY(&bfs_head)) {
00306 entry = TAILQ_FIRST(&bfs_head);
00307 TAILQ_REMOVE(&bfs_head, entry, entries);
00308 free(entry);
00309 }
00310 return current;
00311 }
00312
00313 TAILQ_REMOVE(&bfs_head, entry, entries);
00314 free(entry);
00315
00316 TAILQ_FOREACH(child, &(current->nodes_head), nodes) {
00317 entry = smalloc(sizeof(struct bfs_entry));
00318 entry->con = child;
00319 TAILQ_INSERT_TAIL(&bfs_head, entry, entries);
00320 }
00321
00322 TAILQ_FOREACH(child, &(current->floating_head), floating_windows) {
00323 entry = smalloc(sizeof(struct bfs_entry));
00324 entry->con = child;
00325 TAILQ_INSERT_TAIL(&bfs_head, entry, entries);
00326 }
00327 }
00328
00329 return NULL;
00330 }
00331
00332
00333
00334
00335
00336 bool con_is_floating(Con *con) {
00337 assert(con != NULL);
00338 DLOG("checking if con %p is floating\n", con);
00339 return (con->floating >= FLOATING_AUTO_ON);
00340 }
00341
00342
00343
00344
00345
00346
00347 Con *con_inside_floating(Con *con) {
00348 assert(con != NULL);
00349 if (con->type == CT_FLOATING_CON)
00350 return con;
00351
00352 if (con->floating >= FLOATING_AUTO_ON)
00353 return con->parent;
00354
00355 if (con->type == CT_WORKSPACE || con->type == CT_OUTPUT)
00356 return NULL;
00357
00358 return con_inside_floating(con->parent);
00359 }
00360
00361
00362
00363
00364
00365
00366 Con *con_by_window_id(xcb_window_t window) {
00367 Con *con;
00368 TAILQ_FOREACH(con, &all_cons, all_cons)
00369 if (con->window != NULL && con->window->id == window)
00370 return con;
00371 return NULL;
00372 }
00373
00374
00375
00376
00377
00378
00379 Con *con_by_frame_id(xcb_window_t frame) {
00380 Con *con;
00381 TAILQ_FOREACH(con, &all_cons, all_cons)
00382 if (con->frame == frame)
00383 return con;
00384 return NULL;
00385 }
00386
00387
00388
00389
00390
00391
00392 Con *con_for_window(Con *con, i3Window *window, Match **store_match) {
00393 Con *child;
00394 Match *match;
00395 DLOG("searching con for window %p starting at con %p\n", window, con);
00396 DLOG("class == %s\n", window->class_class);
00397
00398 TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
00399 TAILQ_FOREACH(match, &(child->swallow_head), matches) {
00400 if (!match_matches_window(match, window))
00401 continue;
00402 if (store_match != NULL)
00403 *store_match = match;
00404 return child;
00405 }
00406 Con *result = con_for_window(child, window, store_match);
00407 if (result != NULL)
00408 return result;
00409 }
00410
00411 TAILQ_FOREACH(child, &(con->floating_head), floating_windows) {
00412 TAILQ_FOREACH(match, &(child->swallow_head), matches) {
00413 if (!match_matches_window(match, window))
00414 continue;
00415 if (store_match != NULL)
00416 *store_match = match;
00417 return child;
00418 }
00419 Con *result = con_for_window(child, window, store_match);
00420 if (result != NULL)
00421 return result;
00422 }
00423
00424 return NULL;
00425 }
00426
00427
00428
00429
00430
00431 int con_num_children(Con *con) {
00432 Con *child;
00433 int children = 0;
00434
00435 TAILQ_FOREACH(child, &(con->nodes_head), nodes)
00436 children++;
00437
00438 return children;
00439 }
00440
00441
00442
00443
00444
00445
00446
00447 void con_fix_percent(Con *con) {
00448 Con *child;
00449 int children = con_num_children(con);
00450
00451
00452
00453 double total = 0.0;
00454 int children_with_percent = 0;
00455 TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
00456 if (child->percent > 0.0) {
00457 total += child->percent;
00458 ++children_with_percent;
00459 }
00460 }
00461
00462
00463
00464 if (children_with_percent != children) {
00465 TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
00466 if (child->percent <= 0.0) {
00467 if (children_with_percent == 0)
00468 total += (child->percent = 1.0);
00469 else total += (child->percent = total / children_with_percent);
00470 }
00471 }
00472 }
00473
00474
00475
00476 if (total == 0.0) {
00477 TAILQ_FOREACH(child, &(con->nodes_head), nodes)
00478 child->percent = 1.0 / children;
00479 } else if (total != 1.0) {
00480 TAILQ_FOREACH(child, &(con->nodes_head), nodes)
00481 child->percent /= total;
00482 }
00483 }
00484
00485
00486
00487
00488
00489
00490 void con_toggle_fullscreen(Con *con, int fullscreen_mode) {
00491 Con *workspace, *fullscreen;
00492
00493 if (con->type == CT_WORKSPACE) {
00494 DLOG("You cannot make a workspace fullscreen.\n");
00495 return;
00496 }
00497
00498 DLOG("toggling fullscreen for %p / %s\n", con, con->name);
00499 if (con->fullscreen_mode == CF_NONE) {
00500
00501 if (fullscreen_mode == CF_GLOBAL)
00502 fullscreen = con_get_fullscreen_con(croot, CF_GLOBAL);
00503 else {
00504 workspace = con_get_workspace(con);
00505 fullscreen = con_get_fullscreen_con(workspace, CF_OUTPUT);
00506 }
00507 if (fullscreen != NULL) {
00508 LOG("Not entering fullscreen mode, container (%p/%s) "
00509 "already is in fullscreen mode\n",
00510 fullscreen, fullscreen->name);
00511 goto update_netwm_state;
00512 }
00513
00514
00515 con->fullscreen_mode = fullscreen_mode;
00516 } else {
00517
00518 con->fullscreen_mode = CF_NONE;
00519 }
00520
00521 update_netwm_state:
00522 DLOG("mode now: %d\n", con->fullscreen_mode);
00523
00524
00525
00526
00527 if (con->window == NULL)
00528 return;
00529
00530 uint32_t values[1];
00531 unsigned int num = 0;
00532
00533 if (con->fullscreen_mode != CF_NONE)
00534 values[num++] = A__NET_WM_STATE_FULLSCREEN;
00535
00536 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id,
00537 A__NET_WM_STATE, A_ATOM, 32, num, values);
00538 }
00539
00540
00541
00542
00543
00544
00545
00546 void con_move_to_workspace(Con *con, Con *workspace) {
00547 if (con->type == CT_WORKSPACE) {
00548 DLOG("Moving workspaces is not yet implemented.\n");
00549 return;
00550 }
00551
00552 if (con_is_floating(con)) {
00553 DLOG("Using FLOATINGCON instead\n");
00554 con = con->parent;
00555 }
00556
00557 Con *source_output = con_get_output(con),
00558 *dest_output = con_get_output(workspace);
00559
00560
00561
00562 Con *focus_next = con_next_focused(con);
00563
00564
00565 Con *next = con_descend_focused(workspace);
00566
00567
00568 if (next->type != CT_WORKSPACE) {
00569 DLOG("next originally = %p / %s / type %d\n", next, next->name, next->type);
00570 next = next->parent;
00571 }
00572
00573
00574
00575
00576 Con *floatingcon = con_inside_floating(next);
00577 if (floatingcon != NULL) {
00578 DLOG("floatingcon, going up even further\n");
00579 next = floatingcon->parent;
00580 }
00581
00582 if (con->type == CT_FLOATING_CON) {
00583 Con *ws = con_get_workspace(next);
00584 DLOG("This is a floating window, using workspace %p / %s\n", ws, ws->name);
00585 next = ws;
00586 }
00587
00588 DLOG("Re-attaching container to %p / %s\n", next, next->name);
00589
00590 Con *parent = con->parent;
00591 con_detach(con);
00592 con_attach(con, next, false);
00593
00594
00595 con_fix_percent(parent);
00596 con->percent = 0.0;
00597 con_fix_percent(next);
00598
00599
00600
00601 con_focus(con);
00602
00603
00604
00605
00606 if (source_output != dest_output &&
00607 workspace_is_visible(workspace)) {
00608 DLOG("Moved to a different output, focusing target\n");
00609 } else {
00610 con_focus(focus_next);
00611 }
00612
00613 CALL(parent, on_remove_child);
00614 }
00615
00616
00617
00618
00619
00620
00621
00622 int con_orientation(Con *con) {
00623
00624 if (con->layout == L_STACKED)
00625 return VERT;
00626
00627 if (con->layout == L_TABBED)
00628 return HORIZ;
00629
00630 return con->orientation;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639 Con *con_next_focused(Con *con) {
00640 Con *next;
00641
00642
00643 if (con->type == CT_FLOATING_CON) {
00644 DLOG("selecting next for CT_FLOATING_CON\n");
00645 next = TAILQ_NEXT(con, floating_windows);
00646 DLOG("next = %p\n", next);
00647 if (!next) {
00648 next = TAILQ_PREV(con, floating_head, floating_windows);
00649 DLOG("using prev, next = %p\n", next);
00650 }
00651 if (!next) {
00652 Con *ws = con_get_workspace(con);
00653 next = ws;
00654 DLOG("no more floating containers for next = %p, restoring workspace focus\n", next);
00655 while (next != TAILQ_END(&(ws->focus_head)) && !TAILQ_EMPTY(&(next->focus_head))) {
00656 next = TAILQ_FIRST(&(next->focus_head));
00657 if (next == con) {
00658 DLOG("skipping container itself, we want the next client\n");
00659 next = TAILQ_NEXT(next, focused);
00660 }
00661 }
00662 if (next == TAILQ_END(&(ws->focus_head))) {
00663 DLOG("Focus list empty, returning ws\n");
00664 next = ws;
00665 }
00666 } else {
00667
00668
00669 next = con_descend_focused(next);
00670 }
00671 return next;
00672 }
00673
00674
00675 if (con->parent->type == CT_DOCKAREA) {
00676 DLOG("selecting workspace for dock client\n");
00677 return con_descend_focused(output_get_content(con->parent->parent));
00678 }
00679
00680
00681
00682 Con *first = TAILQ_FIRST(&(con->parent->focus_head));
00683 if (first != con) {
00684 DLOG("Using first entry %p\n", first);
00685 next = first;
00686 } else {
00687
00688
00689 if (!(next = TAILQ_NEXT(con, focused)))
00690 next = con->parent;
00691 }
00692
00693
00694
00695 while (!TAILQ_EMPTY(&(next->focus_head)) &&
00696 TAILQ_FIRST(&(next->focus_head)) != con)
00697 next = TAILQ_FIRST(&(next->focus_head));
00698
00699 return next;
00700 }
00701
00702
00703
00704
00705
00706
00707 Con *con_get_next(Con *con, char way, orientation_t orientation) {
00708 DLOG("con_get_next(way=%c, orientation=%d)\n", way, orientation);
00709
00710 Con *cur = con;
00711 while (con_orientation(cur->parent) != orientation) {
00712 DLOG("need to go one level further up\n");
00713 if (cur->parent->type == CT_WORKSPACE) {
00714 LOG("that's a workspace, we can't go further up\n");
00715 return NULL;
00716 }
00717 cur = cur->parent;
00718 }
00719
00720
00721 Con *next;
00722 if (way == 'n') {
00723 next = TAILQ_NEXT(cur, nodes);
00724
00725 if (next == TAILQ_END(&(parent->nodes_head)))
00726 return NULL;
00727 } else {
00728 next = TAILQ_PREV(cur, nodes_head, nodes);
00729
00730 if (next == TAILQ_END(&(cur->nodes_head)))
00731 return NULL;
00732 }
00733 DLOG("next = %p\n", next);
00734
00735 return next;
00736 }
00737
00738
00739
00740
00741
00742
00743
00744 Con *con_descend_focused(Con *con) {
00745 Con *next = con;
00746 while (!TAILQ_EMPTY(&(next->focus_head)))
00747 next = TAILQ_FIRST(&(next->focus_head));
00748 return next;
00749 }
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 Con *con_descend_tiling_focused(Con *con) {
00760 Con *next = con;
00761 Con *before;
00762 Con *child;
00763 do {
00764 before = next;
00765 TAILQ_FOREACH(child, &(next->focus_head), focused) {
00766 if (child->type == CT_FLOATING_CON)
00767 continue;
00768
00769 next = child;
00770 break;
00771 }
00772 } while (before != next);
00773 return next;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783 Rect con_border_style_rect(Con *con) {
00784 switch (con_border_style(con)) {
00785 case BS_NORMAL:
00786 return (Rect){2, 0, -(2 * 2), -2};
00787
00788 case BS_1PIXEL:
00789 return (Rect){1, 1, -2, -2};
00790
00791 case BS_NONE:
00792 return (Rect){0, 0, 0, 0};
00793
00794 default:
00795 assert(false);
00796 }
00797 }
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809 int con_border_style(Con *con) {
00810 Con *fs = con_get_fullscreen_con(con->parent, CF_OUTPUT);
00811 if (fs == con) {
00812 DLOG("this one is fullscreen! overriding BS_NONE\n");
00813 return BS_NONE;
00814 }
00815
00816 if (con->parent->layout == L_STACKED)
00817 return (con_num_children(con->parent) == 1 ? con->border_style : BS_NORMAL);
00818
00819 if (con->parent->layout == L_TABBED && con->border_style != BS_NORMAL)
00820 return (con_num_children(con->parent) == 1 ? con->border_style : BS_NORMAL);
00821
00822 if (con->parent->type == CT_DOCKAREA)
00823 return BS_NONE;
00824
00825 return con->border_style;
00826 }
00827
00828
00829
00830
00831
00832
00833
00834 void con_set_layout(Con *con, int layout) {
00835
00836
00837
00838
00839 if (con->type == CT_WORKSPACE) {
00840 DLOG("Creating new split container\n");
00841
00842 Con *new = con_new(NULL, NULL);
00843 new->parent = con;
00844
00845
00846 new->layout = layout;
00847
00848
00849
00850
00851 if (config.default_orientation == NO_ORIENTATION) {
00852 new->orientation = (con->rect.height > con->rect.width) ? VERT : HORIZ;
00853 } else {
00854 new->orientation = config.default_orientation;
00855 }
00856
00857 Con *old_focused = TAILQ_FIRST(&(con->focus_head));
00858 if (old_focused == TAILQ_END(&(con->focus_head)))
00859 old_focused = NULL;
00860
00861
00862 DLOG("Moving cons\n");
00863 Con *child;
00864 while (!TAILQ_EMPTY(&(con->nodes_head))) {
00865 child = TAILQ_FIRST(&(con->nodes_head));
00866 con_detach(child);
00867 con_attach(child, new, true);
00868 }
00869
00870
00871 DLOG("Attaching new split to ws\n");
00872 con_attach(new, con, false);
00873
00874 if (old_focused)
00875 con_focus(old_focused);
00876
00877 tree_flatten(croot);
00878
00879 return;
00880 }
00881
00882 con->layout = layout;
00883 }
00884
00885
00886
00887
00888
00889
00890
00891 static void con_on_remove_child(Con *con) {
00892 DLOG("on_remove_child\n");
00893
00894
00895
00896 if (con->type == CT_WORKSPACE ||
00897 con->type == CT_OUTPUT ||
00898 con->type == CT_ROOT ||
00899 con->type == CT_DOCKAREA) {
00900 DLOG("not handling, type = %d\n", con->type);
00901 return;
00902 }
00903
00904
00905
00906 int children = con_num_children(con);
00907 if (children == 0) {
00908 DLOG("Container empty, closing\n");
00909 tree_close(con, DONT_KILL_WINDOW, false);
00910 return;
00911 }
00912 }
00913
00914
00915
00916
00917
00918
00919 Rect con_minimum_size(Con *con) {
00920 DLOG("Determining minimum size for con %p\n", con);
00921
00922 if (con_is_leaf(con)) {
00923 DLOG("leaf node, returning 75x50\n");
00924 return (Rect){ 0, 0, 75, 50 };
00925 }
00926
00927 if (con->type == CT_FLOATING_CON) {
00928 DLOG("floating con\n");
00929 Con *child = TAILQ_FIRST(&(con->nodes_head));
00930 return con_minimum_size(child);
00931 }
00932
00933 if (con->layout == L_STACKED || con->layout == L_TABBED) {
00934 uint32_t max_width = 0, max_height = 0, deco_height = 0;
00935 Con *child;
00936 TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
00937 Rect min = con_minimum_size(child);
00938 deco_height += child->deco_rect.height;
00939 max_width = max(max_width, min.width);
00940 max_height = max(max_height, min.height);
00941 }
00942 DLOG("stacked/tabbed now, returning %d x %d + deco_rect = %d\n",
00943 max_width, max_height, deco_height);
00944 return (Rect){ 0, 0, max_width, max_height + deco_height };
00945 }
00946
00947
00948
00949
00950 if (con->orientation == HORIZ || con->orientation == VERT) {
00951 uint32_t width = 0, height = 0;
00952 Con *child;
00953 TAILQ_FOREACH(child, &(con->nodes_head), nodes) {
00954 Rect min = con_minimum_size(child);
00955 if (con->orientation == HORIZ) {
00956 width += min.width;
00957 height = max(height, min.height);
00958 } else {
00959 height += min.height;
00960 width = max(width, min.width);
00961 }
00962 }
00963 DLOG("split container, returning width = %d x height = %d\n", width, height);
00964 return (Rect){ 0, 0, width, height };
00965 }
00966
00967 ELOG("Unhandled case, type = %d, layout = %d, orientation = %d\n",
00968 con->type, con->layout, con->orientation);
00969 assert(false);
00970 }