00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdio.h>
00014 #include <string.h>
00015 #include <stdlib.h>
00016 #include <xcb/xcb.h>
00017 #include <assert.h>
00018 #include <math.h>
00019
00020 #include "config.h"
00021 #include "i3.h"
00022 #include "xcb.h"
00023 #include "table.h"
00024 #include "util.h"
00025 #include "randr.h"
00026 #include "layout.h"
00027 #include "client.h"
00028 #include "floating.h"
00029 #include "handlers.h"
00030 #include "workspace.h"
00031 #include "log.h"
00032 #include "container.h"
00033
00034
00035
00036
00037
00038
00039
00040 int get_unoccupied_x(Workspace *workspace) {
00041 double unoccupied = workspace->rect.width;
00042 double default_factor = ((float)workspace->rect.width / workspace->cols) / workspace->rect.width;
00043
00044 DLOG("get_unoccupied_x(), starting with %f, default_factor = %f\n", unoccupied, default_factor);
00045
00046 for (int cols = 0; cols < workspace->cols; cols++) {
00047 DLOG("width_factor[%d] = %f, unoccupied = %f\n", cols, workspace->width_factor[cols], unoccupied);
00048
00049 if (workspace->width_factor[cols] == 0)
00050 unoccupied -= workspace->rect.width * default_factor;
00051 }
00052
00053 DLOG("unoccupied space: %f\n", unoccupied);
00054 return unoccupied;
00055 }
00056
00057
00058 int get_unoccupied_y(Workspace *workspace) {
00059 int height = workspace_height(workspace);
00060 double unoccupied = height;
00061 double default_factor = ((float)height / workspace->rows) / height;
00062
00063 DLOG("get_unoccupied_y(), starting with %f, default_factor = %f\n", unoccupied, default_factor);
00064
00065 for (int rows = 0; rows < workspace->rows; rows++) {
00066 DLOG("height_factor[%d] = %f, unoccupied = %f\n", rows, workspace->height_factor[rows], unoccupied);
00067 if (workspace->height_factor[rows] == 0)
00068 unoccupied -= height * default_factor;
00069 }
00070
00071 DLOG("unoccupied space: %f\n", unoccupied);
00072 return unoccupied;
00073 }
00074
00075
00076
00077
00078
00079
00080
00081 void redecorate_window(xcb_connection_t *conn, Client *client) {
00082 if (client->container != NULL &&
00083 (client->container->mode == MODE_STACK ||
00084 client->container->mode == MODE_TABBED)) {
00085 render_container(conn, client->container);
00086
00087
00088 xcb_clear_area(conn, true, client->frame, 0, 0, client->rect.width, client->rect.height);
00089 } else decorate_window(conn, client, client->frame, client->titlegc, 0, 0);
00090 xcb_flush(conn);
00091 }
00092
00093
00094
00095
00096
00097
00098 void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t drawable,
00099 xcb_gcontext_t gc, int offset_x, int offset_y) {
00100 i3Font *font = load_font(conn, config.font);
00101 int decoration_height = font->height + 2 + 2;
00102 struct Colortriple *color;
00103 Client *last_focused;
00104
00105
00106 if (client->dock)
00107 return;
00108
00109 last_focused = SLIST_FIRST(&(client->workspace->focus_stack));
00110
00111 if (client->urgent)
00112 color = &(config.client.urgent);
00113 else {
00114 if (client_is_floating(client)) {
00115 if (last_focused == client)
00116 color = &(config.client.focused);
00117 else color = &(config.client.unfocused);
00118 } else {
00119 if (client->container->currently_focused == client) {
00120
00121 if (last_focused == client && c_ws == client->workspace)
00122 color = &(config.client.focused);
00123
00124 else color = &(config.client.focused_inactive);
00125 } else color = &(config.client.unfocused);
00126 }
00127 }
00128
00129
00130
00131
00132
00133
00134 int mode = container_mode(client->container, true);
00135
00136
00137 if (client->borderless && mode == MODE_DEFAULT)
00138 xcb_change_gc_single(conn, gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#000000"));
00139 else xcb_change_gc_single(conn, gc, XCB_GC_FOREGROUND, color->background);
00140
00141
00142 if (mode == MODE_STACK || mode == MODE_TABBED) {
00143
00144
00145
00146 xcb_rectangle_t rect = {offset_x, offset_y,
00147 offset_x + client->container->width,
00148 offset_y + decoration_height };
00149 xcb_poly_fill_rectangle(conn, drawable, gc, 1, &rect);
00150 } else {
00151 xcb_rectangle_t rect = {0, 0, client->rect.width, client->rect.height};
00152 xcb_poly_fill_rectangle(conn, drawable, gc, 1, &rect);
00153
00154
00155
00156 xcb_change_gc_single(conn, client->titlegc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#000000"));
00157 if (client->titlebar_position == TITLEBAR_OFF && client->borderless) {
00158 xcb_rectangle_t crect = {0, 0, client->rect.width, client->rect.height};
00159 xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &crect);
00160 } else if (client->titlebar_position == TITLEBAR_OFF && !client->borderless) {
00161 xcb_rectangle_t crect = {1, 1, client->rect.width - (1 + 1), client->rect.height - (1 + 1)};
00162 xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &crect);
00163 } else {
00164 xcb_rectangle_t crect = {2, decoration_height,
00165 client->rect.width - (2 + 2), client->rect.height - 2 - decoration_height};
00166 xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &crect);
00167 }
00168 }
00169
00170 mode = container_mode(client->container, false);
00171
00172 if (client->titlebar_position != TITLEBAR_OFF) {
00173
00174 xcb_draw_line(conn, drawable, gc, color->border, offset_x, offset_y, offset_x + client->rect.width, offset_y);
00175 xcb_draw_line(conn, drawable, gc, color->border,
00176 offset_x + 2,
00177 offset_y + font->height + 3,
00178 offset_x + client->rect.width - 3,
00179 offset_y + font->height + 3 );
00180 }
00181
00182
00183 if (client->name != NULL &&
00184 (mode != MODE_DEFAULT || client->titlebar_position != TITLEBAR_OFF)) {
00185
00186 uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
00187 uint32_t values[] = { color->text, color->background, font->id };
00188 xcb_change_gc(conn, gc, mask, values);
00189
00190
00191
00192
00193 if (client->name_len == -1)
00194 xcb_image_text_8(conn, strlen(client->name), drawable, gc, offset_x + 3 ,
00195 offset_y + font->height , client->name);
00196 else
00197 xcb_image_text_16(conn, client->name_len, drawable, gc, offset_x + 3 ,
00198 offset_y + font->height , (xcb_char2b_t*)client->name);
00199 }
00200 }
00201
00202
00203
00204
00205
00206 void reposition_client(xcb_connection_t *conn, Client *client) {
00207 Output *output;
00208
00209 DLOG("frame 0x%08x needs to be pushed to %dx%d\n", client->frame, client->rect.x, client->rect.y);
00210
00211
00212 xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &(client->rect.x));
00213
00214 if (!client_is_floating(client))
00215 return;
00216
00217
00218 output = get_output_containing(client->rect.x + (client->rect.width / 2),
00219 client->rect.y + (client->rect.height / 2));
00220 if (client->workspace->output == output)
00221 return;
00222
00223 if (output == NULL) {
00224 DLOG("Boundary checking disabled, no output found for (%d, %d)\n", client->rect.x, client->rect.y);
00225 return;
00226 }
00227
00228 if (output->current_workspace == NULL) {
00229 DLOG("Boundary checking deferred, no current workspace on output\n");
00230 client->force_reconfigure = true;
00231 return;
00232 }
00233
00234 DLOG("Client is on workspace %p with output %p\n", client->workspace, client->workspace->output);
00235 DLOG("but output at %d, %d is %p\n", client->rect.x, client->rect.y, output);
00236 floating_assign_to_workspace(client, output->current_workspace);
00237
00238 set_focus(conn, client, true);
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248 void resize_client(xcb_connection_t *conn, Client *client) {
00249 i3Font *font = load_font(conn, config.font);
00250
00251 DLOG("frame 0x%08x needs to be pushed to %dx%d\n", client->frame, client->rect.x, client->rect.y);
00252 DLOG("resizing client 0x%08x to %d x %d\n", client->frame, client->rect.width, client->rect.height);
00253 xcb_set_window_rect(conn, client->frame, client->rect);
00254
00255
00256
00257
00258 Rect *rect = &(client->child_rect);
00259 switch (container_mode(client->container, true)) {
00260 case MODE_STACK:
00261 case MODE_TABBED:
00262 rect->x = 2;
00263 rect->y = 0;
00264 rect->width = client->rect.width - (2 + 2);
00265 rect->height = client->rect.height - 2;
00266 break;
00267 default:
00268 if (client->titlebar_position == TITLEBAR_OFF && client->borderless) {
00269 rect->x = 0;
00270 rect->y = 0;
00271 rect->width = client->rect.width;
00272 rect->height = client->rect.height;
00273 } else if (client->titlebar_position == TITLEBAR_OFF && !client->borderless) {
00274 rect->x = 1;
00275 rect->y = 1;
00276 rect->width = client->rect.width - 1 - 1;
00277 rect->height = client->rect.height - 1 - 1;
00278 } else {
00279 rect->x = 2;
00280 rect->y = font->height + 2 + 2;
00281 rect->width = client->rect.width - (2 + 2);
00282 rect->height = client->rect.height - ((font->height + 2 + 2) + 2);
00283 }
00284 break;
00285 }
00286
00287 rect->width -= (2 * client->border_width);
00288 rect->height -= (2 * client->border_width);
00289
00290
00291 if (client->proportional_height != 0 &&
00292 client->proportional_width != 0) {
00293 DLOG("proportional height = %d, width = %d\n", client->proportional_height, client->proportional_width);
00294 double new_height = rect->height + 1;
00295 int new_width = rect->width;
00296
00297 while (new_height > rect->height) {
00298 new_height = ((double)client->proportional_height / client->proportional_width) * new_width;
00299
00300 if (new_height > rect->height)
00301 new_width--;
00302 }
00303
00304 rect->y += ceil(rect->height / 2) - floor(new_height / 2);
00305 rect->x += ceil(rect->width / 2) - floor(new_width / 2);
00306
00307 rect->height = new_height;
00308 rect->width = new_width;
00309 DLOG("new_height = %f, new_width = %d\n", new_height, new_width);
00310 }
00311
00312 if (client->height_increment > 1) {
00313 int old_height = rect->height;
00314 rect->height -= (rect->height - client->base_height) % client->height_increment;
00315 DLOG("Lost %d pixel due to client's height_increment (%d px, base_height = %d)\n",
00316 old_height - rect->height, client->height_increment, client->base_height);
00317 }
00318
00319 if (client->width_increment > 1) {
00320 int old_width = rect->width;
00321 rect->width -= (rect->width - client->base_width) % client->width_increment;
00322 DLOG("Lost %d pixel due to client's width_increment (%d px, base_width = %d)\n",
00323 old_width - rect->width, client->width_increment, client->base_width);
00324 }
00325
00326 DLOG("child will be at %dx%d with size %dx%d\n", rect->x, rect->y, rect->width, rect->height);
00327
00328 xcb_set_window_rect(conn, client->child, *rect);
00329
00330
00331
00332
00333 fake_absolute_configure_notify(conn, client);
00334
00335
00336
00337 xcb_expose_event_t generated;
00338 generated.window = client->frame;
00339 generated.count = 0;
00340 handle_expose_event(NULL, conn, &generated);
00341 }
00342
00343
00344
00345
00346
00347
00348 void render_container(xcb_connection_t *conn, Container *container) {
00349 Client *client;
00350 int num_clients = 0, current_client = 0;
00351
00352 CIRCLEQ_FOREACH(client, &(container->clients), clients)
00353 num_clients++;
00354
00355 if (container->mode == MODE_DEFAULT) {
00356 int height = (container->height / max(1, num_clients));
00357 int rest_pixels = (container->height % max(1, num_clients));
00358 DLOG("height per client = %d, rest = %d\n", height, rest_pixels);
00359
00360 CIRCLEQ_FOREACH(client, &(container->clients), clients) {
00361
00362 if (container->workspace->fullscreen_client == client) {
00363 current_client++;
00364 continue;
00365 }
00366
00367
00368
00369 int this_height = height;
00370 if (rest_pixels > 0) {
00371 height++;
00372 rest_pixels--;
00373 }
00374
00375
00376 if (client->force_reconfigure |
00377 update_if_necessary(&(client->rect.x), container->x) |
00378 update_if_necessary(&(client->rect.y), container->y +
00379 (container->height / num_clients) * current_client) |
00380 update_if_necessary(&(client->rect.width), container->width) |
00381 update_if_necessary(&(client->rect.height), this_height))
00382 resize_client(conn, client);
00383
00384
00385
00386 client->force_reconfigure = false;
00387
00388 current_client++;
00389 }
00390 } else {
00391 i3Font *font = load_font(conn, config.font);
00392 int decoration_height = (font->height + 2 + 2);
00393 struct Stack_Window *stack_win = &(container->stack_win);
00394
00395
00396 int size_each = (num_clients == 0 ? container->width : container->width / num_clients);
00397 int stack_lines = num_clients;
00398
00399
00400
00401 if (stack_win->rect.height == 0 && num_clients > 1) {
00402 DLOG("remapping stack win\n");
00403 xcb_map_window(conn, stack_win->window);
00404 } else DLOG("not remapping stackwin, height = %d, num_clients = %d\n",
00405 stack_win->rect.height, num_clients);
00406
00407 if (container->mode == MODE_TABBED) {
00408
00409
00410 DLOG("tabbed mode, setting num_clients = 1\n");
00411 if (stack_lines > 1)
00412 stack_lines = 1;
00413 }
00414
00415 if (container->stack_limit == STACK_LIMIT_COLS) {
00416 stack_lines = ceil((float)num_clients / container->stack_limit_value);
00417 } else if (container->stack_limit == STACK_LIMIT_ROWS) {
00418 stack_lines = min(num_clients, container->stack_limit_value);
00419 }
00420
00421 int height = decoration_height * stack_lines;
00422 if (num_clients == 1) {
00423 height = 0;
00424 stack_win->rect.height = 0;
00425 xcb_unmap_window(conn, stack_win->window);
00426
00427 DLOG("Just one client, setting height to %d\n", height);
00428 }
00429
00430
00431 if (height > 0 && (
00432 update_if_necessary(&(stack_win->rect.x), container->x) |
00433 update_if_necessary(&(stack_win->rect.y), container->y) |
00434 update_if_necessary(&(stack_win->rect.width), container->width) |
00435 update_if_necessary(&(stack_win->rect.height), height))) {
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 uint32_t values[] = { stack_win->rect.x, stack_win->rect.y,
00448 stack_win->rect.width, stack_win->rect.height,
00449 XCB_STACK_MODE_ABOVE, XCB_STACK_MODE_BELOW };
00450 uint32_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
00451 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
00452 XCB_CONFIG_WINDOW_STACK_MODE;
00453
00454
00455
00456 Client *first_floating = TAILQ_FIRST(&(container->workspace->floating_clients));
00457 if (first_floating != TAILQ_END(&(container->workspace->floating_clients))) {
00458 mask |= XCB_CONFIG_WINDOW_SIBLING;
00459 values[4] = first_floating->frame;
00460 } else if (container->workspace->fullscreen_client != NULL) {
00461 mask |= XCB_CONFIG_WINDOW_SIBLING;
00462 values[4] = container->workspace->fullscreen_client->frame;
00463 }
00464
00465 xcb_configure_window(conn, stack_win->window, mask, values);
00466 }
00467
00468
00469 if (num_clients > 1)
00470 cached_pixmap_prepare(conn, &(stack_win->pixmap));
00471
00472 int current_row = 0, current_col = 0;
00473 int wrap = 0;
00474
00475 if (container->stack_limit == STACK_LIMIT_COLS) {
00476
00477
00478 wrap = ceil((float)num_clients / container->stack_limit_value);
00479 } else if (container->stack_limit == STACK_LIMIT_ROWS) {
00480
00481
00482
00483
00484
00485 wrap = (stack_win->rect.width / ceil((float)num_clients / container->stack_limit_value));
00486 }
00487
00488
00489 CIRCLEQ_FOREACH(client, &(container->clients), clients) {
00490
00491 if (container->workspace->fullscreen_client == client) {
00492 current_client++;
00493 continue;
00494 }
00495
00496
00497
00498 if (client->force_reconfigure |
00499 update_if_necessary(&(client->rect.x), container->x) |
00500 update_if_necessary(&(client->rect.y), container->y + height) |
00501 update_if_necessary(&(client->rect.width), container->width) |
00502 update_if_necessary(&(client->rect.height), container->height - height))
00503 resize_client(conn, client);
00504
00505 client->force_reconfigure = false;
00506
00507 int offset_x = 0;
00508 int offset_y = 0;
00509 if (container->mode == MODE_STACK ||
00510 (container->mode == MODE_TABBED &&
00511 container->stack_limit == STACK_LIMIT_COLS)) {
00512 if (container->stack_limit == STACK_LIMIT_COLS) {
00513 offset_x = current_col * (stack_win->rect.width / container->stack_limit_value);
00514 offset_y = current_row * decoration_height;
00515 current_row++;
00516 if ((current_row % wrap) == 0) {
00517 current_col++;
00518 current_row = 0;
00519 }
00520 } else if (container->stack_limit == STACK_LIMIT_ROWS) {
00521 offset_x = current_col * wrap;
00522 offset_y = current_row * decoration_height;
00523 current_row++;
00524 if ((current_row % container->stack_limit_value) == 0) {
00525 current_col++;
00526 current_row = 0;
00527 }
00528 } else {
00529 offset_y = current_client * decoration_height;
00530 }
00531 current_client++;
00532 } else if (container->mode == MODE_TABBED) {
00533 if (container->stack_limit == STACK_LIMIT_ROWS) {
00534 LOG("You limited a tabbed container in its rows. "
00535 "This makes no sense in tabbing mode.\n");
00536 }
00537 offset_x = current_client++ * size_each;
00538 }
00539 if (stack_win->pixmap.id == XCB_NONE)
00540 continue;
00541 decorate_window(conn, client, stack_win->pixmap.id,
00542 stack_win->pixmap.gc, offset_x, offset_y);
00543 }
00544
00545
00546
00547 if (container->mode == MODE_STACK) {
00548 if (container->stack_limit == STACK_LIMIT_COLS && (current_col % 2) != 0) {
00549 xcb_change_gc_single(conn, stack_win->pixmap.gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#000000"));
00550
00551 int offset_x = current_col * (stack_win->rect.width / container->stack_limit_value);
00552 int offset_y = current_row * decoration_height;
00553 xcb_rectangle_t rect = {offset_x, offset_y,
00554 offset_x + container->width,
00555 offset_y + decoration_height };
00556 xcb_poly_fill_rectangle(conn, stack_win->pixmap.id, stack_win->pixmap.gc, 1, &rect);
00557 } else if (container->stack_limit == STACK_LIMIT_ROWS && (current_row % 2) != 0) {
00558 xcb_change_gc_single(conn, stack_win->pixmap.gc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#000000"));
00559
00560 int offset_x = current_col * wrap;
00561 int offset_y = current_row * decoration_height;
00562 xcb_rectangle_t rect = {offset_x, offset_y,
00563 offset_x + container->width,
00564 offset_y + decoration_height };
00565 xcb_poly_fill_rectangle(conn, stack_win->pixmap.id, stack_win->pixmap.gc, 1, &rect);
00566 }
00567 }
00568
00569 if (stack_win->pixmap.id == XCB_NONE)
00570 return;
00571 xcb_copy_area(conn, stack_win->pixmap.id, stack_win->window, stack_win->pixmap.gc,
00572 0, 0, 0, 0, stack_win->rect.width, stack_win->rect.height);
00573 }
00574 }
00575
00576 static void render_bars(xcb_connection_t *conn, Workspace *r_ws, int width, int *height) {
00577 Client *client;
00578 SLIST_FOREACH(client, &(r_ws->output->dock_clients), dock_clients) {
00579 DLOG("client is at %d, should be at %d\n", client->rect.y, *height);
00580 if (client->force_reconfigure |
00581 update_if_necessary(&(client->rect.x), r_ws->rect.x) |
00582 update_if_necessary(&(client->rect.y), *height))
00583 reposition_client(conn, client);
00584
00585 if (client->force_reconfigure |
00586 update_if_necessary(&(client->rect.width), width) |
00587 update_if_necessary(&(client->rect.height), client->desired_height))
00588 resize_client(conn, client);
00589
00590 client->force_reconfigure = false;
00591 DLOG("desired_height = %d\n", client->desired_height);
00592 *height += client->desired_height;
00593 }
00594 }
00595
00596 static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int width, int height) {
00597 i3Font *font = load_font(conn, config.font);
00598 Output *output = r_ws->output;
00599 enum { SET_NORMAL = 0, SET_FOCUSED = 1 };
00600
00601
00602 xcb_change_gc_single(conn, output->bargc, XCB_GC_FOREGROUND, get_colorpixel(conn, "#000000"));
00603 xcb_rectangle_t rect = {0, 0, width, height};
00604 xcb_poly_fill_rectangle(conn, output->bar, output->bargc, 1, &rect);
00605
00606
00607 xcb_change_gc_single(conn, output->bargc, XCB_GC_FONT, font->id);
00608
00609 int drawn = 0;
00610 Workspace *ws;
00611 TAILQ_FOREACH(ws, workspaces, workspaces) {
00612 if (ws->output != output)
00613 continue;
00614
00615 struct Colortriple *color;
00616
00617 if (output->current_workspace == ws)
00618 color = &(config.bar.focused);
00619 else if (ws->urgent)
00620 color = &(config.bar.urgent);
00621 else color = &(config.bar.unfocused);
00622
00623
00624 xcb_draw_rect(conn, output->bar, output->bargc, color->border,
00625 drawn,
00626 1,
00627 ws->text_width + 5 + 5,
00628 height - 2 );
00629
00630
00631 xcb_draw_rect(conn, output->bar, output->bargc, color->background,
00632 drawn + 1,
00633 2,
00634 ws->text_width + 4 + 4,
00635 height - 4);
00636
00637 xcb_change_gc_single(conn, output->bargc, XCB_GC_FOREGROUND, color->text);
00638 xcb_change_gc_single(conn, output->bargc, XCB_GC_BACKGROUND, color->background);
00639 xcb_image_text_16(conn, ws->name_len, output->bar, output->bargc, drawn + 5 ,
00640 font->height + 1 ,
00641 (xcb_char2b_t*)ws->name);
00642 drawn += ws->text_width + 12;
00643 }
00644 }
00645
00646
00647
00648
00649
00650
00651
00652 void ignore_enter_notify_forall(xcb_connection_t *conn, Workspace *workspace, bool ignore_enter_notify) {
00653 Client *client;
00654 uint32_t values[1];
00655
00656 FOR_TABLE(workspace) {
00657 if (workspace->table[cols][rows] == NULL)
00658 continue;
00659
00660 CIRCLEQ_FOREACH(client, &(workspace->table[cols][rows]->clients), clients) {
00661
00662 values[0] = FRAME_EVENT_MASK;
00663 if (ignore_enter_notify)
00664 values[0] &= ~(XCB_EVENT_MASK_ENTER_WINDOW);
00665 xcb_change_window_attributes(conn, client->frame, XCB_CW_EVENT_MASK, values);
00666
00667
00668 values[0] = CHILD_EVENT_MASK;
00669 if (ignore_enter_notify)
00670 values[0] &= ~(XCB_EVENT_MASK_ENTER_WINDOW);
00671 xcb_change_window_attributes(conn, client->child, XCB_CW_EVENT_MASK, values);
00672 }
00673 }
00674 }
00675
00676
00677
00678
00679
00680 void render_workspace(xcb_connection_t *conn, Output *output, Workspace *r_ws) {
00681 i3Font *font = load_font(conn, config.font);
00682 int width = r_ws->rect.width;
00683 int height = r_ws->rect.height;
00684
00685
00686 Client *client;
00687 SLIST_FOREACH(client, &(output->dock_clients), dock_clients)
00688 height -= client->desired_height;
00689
00690
00691 if (!config.disable_workspace_bar)
00692 height -= (font->height + 6);
00693
00694 int xoffset[r_ws->rows];
00695 int yoffset[r_ws->cols];
00696
00697 for (int cols = 0; cols < r_ws->cols; cols++)
00698 yoffset[cols] = r_ws->rect.y;
00699 for (int rows = 0; rows < r_ws->rows; rows++)
00700 xoffset[rows] = r_ws->rect.x;
00701
00702 ignore_enter_notify_forall(conn, r_ws, true);
00703
00704
00705 FOR_TABLE(r_ws) {
00706 Container *container = r_ws->table[cols][rows];
00707 if (container == NULL)
00708 continue;
00709 int single_width = -1, single_height = -1;
00710
00711 container->row = rows;
00712 container->col = cols;
00713 container->x = xoffset[rows];
00714 container->y = yoffset[cols];
00715 container->width = 0;
00716
00717 for (int c = 0; c < container->colspan; c++) {
00718 if (r_ws->width_factor[cols+c] == 0)
00719 container->width += (width / r_ws->cols);
00720 else container->width += get_unoccupied_x(r_ws) * r_ws->width_factor[cols+c];
00721
00722 if (single_width == -1)
00723 single_width = container->width;
00724 }
00725
00726 DLOG("height is %d\n", height);
00727
00728 container->height = 0;
00729
00730 for (int c = 0; c < container->rowspan; c++) {
00731 if (r_ws->height_factor[rows+c] == 0)
00732 container->height += (height / r_ws->rows);
00733 else container->height += get_unoccupied_y(r_ws) * r_ws->height_factor[rows+c];
00734
00735 if (single_height == -1)
00736 single_height = container->height;
00737 }
00738
00739
00740 render_container(conn, container);
00741
00742 xoffset[rows] += single_width;
00743 yoffset[cols] += single_height;
00744 }
00745
00746
00747 TAILQ_FOREACH(client, &(r_ws->floating_clients), floating_clients) {
00748 if (!client->force_reconfigure)
00749 continue;
00750
00751 client->force_reconfigure = false;
00752 reposition_client(conn, client);
00753 resize_client(conn, client);
00754 }
00755
00756 ignore_enter_notify_forall(conn, r_ws, false);
00757
00758 render_bars(conn, r_ws, width, &height);
00759 if (!config.disable_workspace_bar)
00760 render_internal_bar(conn, r_ws, width, font->height + 6);
00761 }
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771 void render_layout(xcb_connection_t *conn) {
00772 Output *output;
00773
00774 TAILQ_FOREACH(output, &outputs, outputs)
00775 if (output->current_workspace != NULL)
00776 render_workspace(conn, output, output->current_workspace);
00777
00778 xcb_flush(conn);
00779 }