00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <stdio.h>
00015 #include <assert.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <sys/types.h>
00019 #include <unistd.h>
00020 #include <stdbool.h>
00021 #include <assert.h>
00022
00023 #include "data.h"
00024 #include "table.h"
00025 #include "util.h"
00026 #include "i3.h"
00027 #include "layout.h"
00028 #include "config.h"
00029 #include "workspace.h"
00030 #include "log.h"
00031
00032 int current_workspace = 0;
00033 int num_workspaces = 1;
00034 struct workspaces_head *workspaces;
00035
00036 Workspace *c_ws;
00037 int current_col = 0;
00038 int current_row = 0;
00039
00040
00041
00042
00043
00044 void init_table() {
00045 workspaces = scalloc(sizeof(struct workspaces_head));
00046 TAILQ_INIT(workspaces);
00047
00048 c_ws = scalloc(sizeof(Workspace));
00049 workspace_set_name(c_ws, NULL);
00050 TAILQ_INIT(&(c_ws->floating_clients));
00051 TAILQ_INSERT_TAIL(workspaces, c_ws, workspaces);
00052 }
00053
00054 static void new_container(Workspace *workspace, Container **container, int col, int row, bool skip_layout_switch) {
00055 Container *new;
00056 new = *container = scalloc(sizeof(Container));
00057 CIRCLEQ_INIT(&(new->clients));
00058 new->colspan = 1;
00059 new->rowspan = 1;
00060 new->col = col;
00061 new->row = row;
00062 new->workspace = workspace;
00063 if (!skip_layout_switch)
00064 switch_layout_mode(global_conn, new, config.container_mode);
00065 new->stack_limit = config.container_stack_limit;
00066 new->stack_limit_value = config.container_stack_limit_value;
00067 }
00068
00069
00070
00071
00072
00073 void expand_table_rows(Workspace *workspace) {
00074 workspace->rows++;
00075
00076 workspace->height_factor = realloc(workspace->height_factor, sizeof(float) * workspace->rows);
00077 workspace->height_factor[workspace->rows-1] = 0;
00078
00079 for (int c = 0; c < workspace->cols; c++) {
00080 workspace->table[c] = realloc(workspace->table[c], sizeof(Container*) * workspace->rows);
00081 new_container(workspace, &(workspace->table[c][workspace->rows-1]), c, workspace->rows-1, true);
00082 }
00083
00084
00085
00086
00087 for (int c = 0; c < workspace->cols; c++)
00088 switch_layout_mode(global_conn, workspace->table[c][workspace->rows-1], config.container_mode);
00089 }
00090
00091
00092
00093
00094
00095 void expand_table_rows_at_head(Workspace *workspace) {
00096 workspace->rows++;
00097
00098 workspace->height_factor = realloc(workspace->height_factor, sizeof(float) * workspace->rows);
00099
00100 DLOG("rows = %d\n", workspace->rows);
00101 for (int rows = (workspace->rows - 1); rows >= 1; rows--) {
00102 DLOG("Moving height_factor %d (%f) to %d\n", rows-1, workspace->height_factor[rows-1], rows);
00103 workspace->height_factor[rows] = workspace->height_factor[rows-1];
00104 }
00105
00106 workspace->height_factor[0] = 0;
00107
00108 for (int cols = 0; cols < workspace->cols; cols++)
00109 workspace->table[cols] = realloc(workspace->table[cols], sizeof(Container*) * workspace->rows);
00110
00111
00112 for (int cols = 0; cols < workspace->cols; cols++)
00113 for (int rows = workspace->rows - 1; rows > 0; rows--) {
00114 DLOG("Moving row %d to %d\n", rows-1, rows);
00115 workspace->table[cols][rows] = workspace->table[cols][rows-1];
00116 workspace->table[cols][rows]->row = rows;
00117 }
00118
00119 for (int cols = 0; cols < workspace->cols; cols++)
00120 new_container(workspace, &(workspace->table[cols][0]), cols, 0, false);
00121 }
00122
00123
00124
00125
00126
00127 void expand_table_cols(Workspace *workspace) {
00128 workspace->cols++;
00129
00130 workspace->width_factor = realloc(workspace->width_factor, sizeof(float) * workspace->cols);
00131 workspace->width_factor[workspace->cols-1] = 0;
00132
00133 workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
00134 workspace->table[workspace->cols-1] = scalloc(sizeof(Container*) * workspace->rows);
00135
00136 for (int c = 0; c < workspace->rows; c++)
00137 new_container(workspace, &(workspace->table[workspace->cols-1][c]), workspace->cols-1, c, true);
00138
00139 for (int c = 0; c < workspace->rows; c++)
00140 switch_layout_mode(global_conn, workspace->table[workspace->cols-1][c], config.container_mode);
00141 }
00142
00143
00144
00145
00146
00147 void expand_table_cols_at_head(Workspace *workspace) {
00148 workspace->cols++;
00149
00150 workspace->width_factor = realloc(workspace->width_factor, sizeof(float) * workspace->cols);
00151
00152 DLOG("cols = %d\n", workspace->cols);
00153 for (int cols = (workspace->cols - 1); cols >= 1; cols--) {
00154 DLOG("Moving width_factor %d (%f) to %d\n", cols-1, workspace->width_factor[cols-1], cols);
00155 workspace->width_factor[cols] = workspace->width_factor[cols-1];
00156 }
00157
00158 workspace->width_factor[0] = 0;
00159
00160 workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
00161 workspace->table[workspace->cols-1] = scalloc(sizeof(Container*) * workspace->rows);
00162
00163
00164 for (int rows = 0; rows < workspace->rows; rows++)
00165 for (int cols = workspace->cols - 1; cols > 0; cols--) {
00166 DLOG("Moving col %d to %d\n", cols-1, cols);
00167 workspace->table[cols][rows] = workspace->table[cols-1][rows];
00168 workspace->table[cols][rows]->col = cols;
00169 }
00170
00171 for (int rows = 0; rows < workspace->rows; rows++)
00172 new_container(workspace, &(workspace->table[0][rows]), 0, rows, false);
00173 }
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 static void shrink_table_cols(Workspace *workspace) {
00184 float free_space = workspace->width_factor[workspace->cols-1];
00185
00186 workspace->cols--;
00187
00188
00189 workspace->width_factor = realloc(workspace->width_factor, sizeof(float) * workspace->cols);
00190
00191
00192 free(workspace->table[workspace->cols]);
00193
00194
00195 workspace->table = realloc(workspace->table, sizeof(Container**) * workspace->cols);
00196
00197
00198 if (free_space == 0)
00199 return;
00200
00201 for (int cols = (workspace->cols-1); cols >= 0; cols--) {
00202 if (workspace->width_factor[cols] == 0)
00203 continue;
00204
00205 DLOG("Added free space (%f) to %d (had %f)\n", free_space, cols,
00206 workspace->width_factor[cols]);
00207 workspace->width_factor[cols] += free_space;
00208 break;
00209 }
00210 }
00211
00212
00213
00214
00215
00216 static void shrink_table_rows(Workspace *workspace) {
00217 float free_space = workspace->height_factor[workspace->rows-1];
00218
00219 workspace->rows--;
00220 for (int cols = 0; cols < workspace->cols; cols++)
00221 workspace->table[cols] = realloc(workspace->table[cols], sizeof(Container*) * workspace->rows);
00222
00223
00224 workspace->height_factor = realloc(workspace->height_factor, sizeof(float) * workspace->rows);
00225
00226
00227 if (free_space == 0)
00228 return;
00229
00230 for (int rows = (workspace->rows-1); rows >= 0; rows--) {
00231 if (workspace->height_factor[rows] == 0)
00232 continue;
00233
00234 DLOG("Added free space (%f) to %d (had %f)\n", free_space, rows,
00235 workspace->height_factor[rows]);
00236 workspace->height_factor[rows] += free_space;
00237 break;
00238 }
00239 }
00240
00241
00242
00243
00244
00245 bool cell_exists(Workspace *ws, int col, int row) {
00246 return (col >= 0 && col < ws->cols) &&
00247 (row >= 0 && row < ws->rows);
00248 }
00249
00250 static void free_container(xcb_connection_t *conn, Workspace *workspace, int col, int row) {
00251 Container *old_container = workspace->table[col][row];
00252
00253 if (old_container->mode == MODE_STACK || old_container->mode == MODE_TABBED)
00254 leave_stack_mode(conn, old_container);
00255
00256 free(old_container);
00257 }
00258
00259 static void move_columns_from(xcb_connection_t *conn, Workspace *workspace, int cols) {
00260 DLOG("firstly freeing \n");
00261
00262
00263 for (int rows = 0; rows < workspace->rows; rows++)
00264 free_container(conn, workspace, cols-1, rows);
00265
00266 for (; cols < workspace->cols; cols++)
00267 for (int rows = 0; rows < workspace->rows; rows++) {
00268 DLOG("at col = %d, row = %d\n", cols, rows);
00269 Container *new_container = workspace->table[cols][rows];
00270
00271 DLOG("moving cols = %d to cols -1 = %d\n", cols, cols-1);
00272 workspace->table[cols-1][rows] = new_container;
00273
00274 new_container->row = rows;
00275 new_container->col = cols-1;
00276 }
00277 }
00278
00279 static void move_rows_from(xcb_connection_t *conn, Workspace *workspace, int rows) {
00280 for (int cols = 0; cols < workspace->cols; cols++)
00281 free_container(conn, workspace, cols, rows-1);
00282
00283 for (; rows < workspace->rows; rows++)
00284 for (int cols = 0; cols < workspace->cols; cols++) {
00285 Container *new_container = workspace->table[cols][rows];
00286
00287 DLOG("moving rows = %d to rows -1 = %d\n", rows, rows - 1);
00288 workspace->table[cols][rows-1] = new_container;
00289
00290 new_container->row = rows-1;
00291 new_container->col = cols;
00292 }
00293 }
00294
00295
00296
00297
00298
00299 void dump_table(xcb_connection_t *conn, Workspace *workspace) {
00300 DLOG("dump_table()\n");
00301 FOR_TABLE(workspace) {
00302 Container *con = workspace->table[cols][rows];
00303 DLOG("----\n");
00304 DLOG("at col=%d, row=%d\n", cols, rows);
00305 DLOG("currently_focused = %p\n", con->currently_focused);
00306 Client *loop;
00307 CIRCLEQ_FOREACH(loop, &(con->clients), clients) {
00308 DLOG("got client %08x / %s\n", loop->child, loop->name);
00309 }
00310 DLOG("----\n");
00311 }
00312 DLOG("done\n");
00313 }
00314
00315
00316
00317
00318
00319 void cleanup_table(xcb_connection_t *conn, Workspace *workspace) {
00320 DLOG("cleanup_table()\n");
00321
00322
00323 for (int cols = 0; (workspace->cols > 1) && (cols < workspace->cols);) {
00324 bool completely_empty = true;
00325 for (int rows = 0; rows < workspace->rows; rows++)
00326 if (workspace->table[cols][rows]->currently_focused != NULL) {
00327 completely_empty = false;
00328 break;
00329 }
00330 if (completely_empty) {
00331 DLOG("Removing completely empty column %d\n", cols);
00332 if (cols < (workspace->cols - 1))
00333 move_columns_from(conn, workspace, cols+1);
00334 else {
00335 for (int rows = 0; rows < workspace->rows; rows++)
00336 free_container(conn, workspace, cols, rows);
00337 }
00338 shrink_table_cols(workspace);
00339
00340 if (workspace->current_col >= workspace->cols)
00341 workspace->current_col = workspace->cols - 1;
00342 } else cols++;
00343 }
00344
00345
00346 for (int rows = 0; (workspace->rows > 1) && (rows < workspace->rows);) {
00347 bool completely_empty = true;
00348 DLOG("Checking row %d\n", rows);
00349 for (int cols = 0; cols < workspace->cols; cols++)
00350 if (workspace->table[cols][rows]->currently_focused != NULL) {
00351 completely_empty = false;
00352 break;
00353 }
00354 if (completely_empty) {
00355 DLOG("Removing completely empty row %d\n", rows);
00356 if (rows < (workspace->rows - 1))
00357 move_rows_from(conn, workspace, rows+1);
00358 else {
00359 for (int cols = 0; cols < workspace->cols; cols++)
00360 free_container(conn, workspace, cols, rows);
00361 }
00362 shrink_table_rows(workspace);
00363
00364 if (workspace->current_row >= workspace->rows)
00365 workspace->current_row = workspace->rows - 1;
00366 } else rows++;
00367 }
00368
00369
00370 if (current_col >= c_ws->cols)
00371 current_col = c_ws->cols-1;
00372
00373 if (current_row >= c_ws->rows)
00374 current_row = c_ws->rows-1;
00375
00376 if (CUR_CELL->currently_focused != NULL)
00377 set_focus(conn, CUR_CELL->currently_focused, true);
00378 }
00379
00380
00381
00382
00383
00384 void fix_colrowspan(xcb_connection_t *conn, Workspace *workspace) {
00385 DLOG("Fixing col/rowspan\n");
00386
00387 FOR_TABLE(workspace) {
00388 Container *con = workspace->table[cols][rows];
00389 if (con->colspan > 1) {
00390 DLOG("gots one with colspan %d (at %d c, %d r)\n", con->colspan, cols, rows);
00391 while (con->colspan > 1 &&
00392 (!cell_exists(workspace, cols + (con->colspan-1), rows) &&
00393 workspace->table[cols + (con->colspan - 1)][rows]->currently_focused != NULL))
00394 con->colspan--;
00395 DLOG("fixed it to %d\n", con->colspan);
00396 }
00397 if (con->rowspan > 1) {
00398 DLOG("gots one with rowspan %d (at %d c, %d r)\n", con->rowspan, cols, rows);
00399 while (con->rowspan > 1 &&
00400 (!cell_exists(workspace, cols, rows + (con->rowspan - 1)) &&
00401 workspace->table[cols][rows + (con->rowspan - 1)]->currently_focused != NULL))
00402 con->rowspan--;
00403 DLOG("fixed it to %d\n", con->rowspan);
00404 }
00405 }
00406 }