18 split, stack, max, tab
22 /* Window structure types */
31 list_t *rows; // of row_t
38 list_t *cols; // of col_t
44 list_t *dpys; // of dpy_t
50 list_t *tags; // of tag_t
55 static drag_t move_mode;
56 static list_t *move_lrow;
57 static list_t *move_lcol;
58 static ptr_t move_prev;
59 static struct { int v, h; } move_dir;
61 /* Window management data */
63 #define wm_focus wm->tag->dpy->col->row->win
64 #define wm_row wm->tag->dpy->col->row
65 #define wm_col wm->tag->dpy->col
66 #define wm_dpy wm->tag->dpy
67 #define wm_tag wm->tag
69 #define ROW(l) ((row_t*)(l)->data)
70 #define COL(l) ((col_t*)(l)->data)
71 #define DPY(l) ((dpy_t*)(l)->data)
72 #define TAG(l) ((tag_t*)(l)->data)
74 /* Helper functions */
75 static int searchl(tag_t *tag, win_t *target,
76 list_t **_dpy, list_t **_col, list_t **_row)
78 for (list_t *dpy = tag ->dpys; dpy; dpy = dpy->next)
79 for (list_t *col = DPY(dpy)->cols; col; col = col->next)
80 for (list_t *row = COL(col)->rows; row; row = row->next) {
81 win_t *win = ROW(row)->win;
83 if (_dpy) *_dpy = dpy;
84 if (_col) *_col = col;
85 if (_row) *_row = row;
92 static int search(tag_t *tag, win_t *target,
93 dpy_t **_dpy, col_t **_col, row_t **_row)
95 list_t *dpy, *col, *row;
96 if (searchl(tag, target, &dpy, &col, &row)) {
97 if (_dpy) *_dpy = DPY(dpy);
98 if (_col) *_col = COL(col);
99 if (_row) *_row = ROW(row);
105 static void set_mode(win_t *win, mode_t mode)
108 search(wm_tag, win, NULL, &col, NULL);
109 printf("set_mode: %p, %d -> %d\n",
110 col, col->mode, mode);
112 if (col->mode == split)
113 for (list_t *cur = col->rows; cur; cur = cur->next) {
114 row_t *row = cur->data;
115 row->height = wm_dpy->root->h;
120 static void set_focus(win_t *win)
122 /* - Only grab mouse button on unfocused window,
123 * this prevents stealing all mouse clicks from client windows,
124 * - A better way may be to re-send mouse clicks to client windows
125 * using the return value from wm_handle_key */
126 for (int i = key_mouse1; i < key_mouse7; i++) {
128 sys_watch(wm_focus, i, MOD());
129 sys_unwatch(win, i, MOD());
132 dpy_t *dpy; col_t *col; row_t *row;
133 if (search(wm_tag, win, &dpy, &col, &row)) {
141 static void set_move(win_t *win, ptr_t ptr, drag_t drag)
143 printf("set_move: %d - %p@%d,%d\n",
144 drag, win, ptr.rx, ptr.ry);
146 if (drag == move || drag == resize) {
147 searchl(wm_tag, win, NULL, &move_lcol, &move_lrow);
149 int my = win->y + (win->h/2);
150 int mx = win->x + (win->w/2);
151 move_dir.v = ptr.ry < my ? -1 : +1;
152 move_dir.h = ptr.rx < mx ? -1 : +1;
156 static void print_txt(list_t *cols)
158 for (list_t *lcol = cols; lcol; lcol = lcol->next) {
159 col_t *col = lcol->data;
160 printf("col:\t<%-9p [%-20p] >%-9p - %dpx @ %d !!%p\n",
161 ( lcol->prev ? lcol->prev->data : NULL ),
163 ( lcol->next ? lcol->next->data : NULL ),
164 col->width, col->mode, col->row);
165 for (list_t *lrow = col->rows; lrow; lrow = lrow->next) {
166 row_t *row = lrow->data;
167 win_t *win = row->win;
168 printf(" win:\t<%-9p [%p>>%p] >%-9p - %4dpx focus=%d%d\n",
169 lrow->prev, lrow, win, lrow->next,
170 win->h, col->row == row, wm_focus == win);
175 static void cut_win(win_t *win)
177 list_t *ldpy, *lcol, *lrow;
178 searchl(wm_tag, win, &ldpy, &lcol, &lrow);
179 col_t *col = COL(lcol);
180 dpy_t *dpy = DPY(ldpy);
182 col->row = lrow->prev ? lrow->prev->data :
183 lrow->next ? lrow->next->data : NULL;
184 col->rows = list_remove(col->rows, lrow);
186 if (col->rows == NULL && (lcol->next || lcol->prev)) {
187 dpy->col = lcol->prev ? lcol->prev->data :
188 lcol->next ? lcol->next->data : NULL;
189 dpy->cols = list_remove(wm_dpy->cols, lcol);
193 static void put_win(win_t *win, col_t *col)
195 row_t *row = new0(row_t);
200 wm_dpy->cols = list_insert(wm_dpy->cols, col);
203 int nrows = list_length(col->rows);
205 list_t *prev = list_find(col->rows, col->row);
206 list_insert_after(prev, row);
208 col->rows = list_insert(col->rows, row);
213 row->height = wm_dpy->root->h / MAX(nrows,1);
215 int ncols = list_length(wm_dpy->cols);
216 col->width = wm_dpy->root->w / MAX(ncols-1,1);
220 static void shift_window(win_t *win, int col, int row)
222 printf("shift_window: %p - %+d,%+d\n", win, col, row);
223 print_txt(wm_dpy->cols);
224 printf("shift_window: >>>\n");
225 list_t *ldpy, *lcol, *lrow;
226 searchl(wm_tag, win, &ldpy, &lcol, &lrow);
228 list_t *src = lrow, *dst = NULL;
229 if (row < 0) dst = src->prev;
230 if (row > 0) dst = src->next;
232 printf("swap: %p <-> %p\n", src->data, dst->data);
233 row_t *tmp = src->data;
234 src->data = dst->data;
239 int onlyrow = !lrow->prev && !lrow->next;
240 list_t *src = lcol, *dst = NULL;
242 if (!src->prev && !onlyrow)
243 wm_dpy->cols = list_insert(wm_dpy->cols, new0(col_t));
247 if (!src->next && !onlyrow)
248 wm_dpy->cols = list_append(wm_dpy->cols, new0(col_t));
253 put_win(win, COL(dst));
259 print_txt(wm_dpy->cols);
263 static list_t *get_next(list_t *list, int forward)
265 list_t *next = forward ? list->next : list->prev;
268 while ((list = forward ? next->prev : next->next))
273 static void shift_focus(win_t *win, int col, int row)
275 printf("shift_focus: %p - %+d,%+d\n", win, col, row);
276 list_t *ldpy, *lcol, *lrow;
277 searchl(wm_tag, win, &ldpy, &lcol, &lrow);
279 row_t *next = get_next(lrow, row > 0)->data;
280 set_focus(next->win);
281 if (COL(lcol)->mode != split)
285 col_t *next = get_next(lcol, col > 0)->data;
286 set_focus(next->row->win);
290 /* Window management functions */
293 int x=0, y=0; // Current window top-left position
294 int tx=0, ty=0; // Total x/y size
295 int mx=0, my=0; // Maximum x/y size (screen size)
296 int sy=0; // Size of focused stack window
298 /* Scale horizontally */
300 mx = wm_dpy->root->w - (list_length(wm_dpy->cols)+1)*MARGIN;
301 for (list_t *lx = wm_dpy->cols; lx; lx = lx->next)
302 tx += COL(lx)->width;
303 for (list_t *lx = wm_dpy->cols; lx; lx = lx->next)
304 COL(lx)->width *= (float)mx / tx;
306 /* Scale each column vertically */
307 for (list_t *lx = wm_dpy->cols; lx; lx = lx->next) {
308 col_t *col = lx->data;
310 for (list_t *ly = col->rows; ly; ly = ly->next)
311 ty += ROW(ly)->height;
313 my = wm_dpy->root->h - (list_length(col->rows)+1)*MARGIN;
314 sy = my - (list_length(col->rows)-1)*STACK;
315 for (list_t *ly = col->rows; ly; ly = ly->next) {
316 win_t *win = ROW(ly)->win;
317 win->h = ROW(ly)->height;
321 sys_move(win, x+MARGIN, y+MARGIN,
322 col->width, win->h * ((float)my / ty));
326 height = col->row->win == win ? sy : STACK;
327 sys_move(win, x+MARGIN, y+MARGIN,
332 sys_move(win, x+MARGIN, 0+MARGIN,
333 col->width, wm_dpy->root->h-2*MARGIN);
334 if (col->row->win == win)
338 y += height + MARGIN;
339 ROW(ly)->height = win->h;
341 x += col->width + MARGIN;
345 int wm_handle_key(win_t *win, Key_t key, mod_t mod, ptr_t ptr)
347 if (!win || win == wm_dpy->root) return 0;
348 //printf("wm_handle_key: %p - %x %c%c%c%c%c\n", win, key,
349 // mod.up ? '^' : 'v',
350 // mod.alt ? 'a' : '-',
351 // mod.ctrl ? 'c' : '-',
352 // mod.shift ? 's' : '-',
353 // mod.win ? 'w' : '-');
356 if (key_mouse0 <= key && key <= key_mouse7 && mod.up)
357 return set_move(win,ptr,none), 1;
358 else if (key == key_mouse1 && mod.MODKEY)
359 return set_move(win,ptr,move), 1;
360 else if (key == key_mouse3 && mod.MODKEY)
361 return set_move(win,ptr,resize), 1;
363 /* Only handle key-down */
369 if (key == key_f1) return sys_raise(win), 1;
370 if (key == key_f2) return set_focus(win), 1;
371 if (key == key_f5) return wm_update(), 1;
372 if (key == key_f6) return print_txt(wm_dpy->cols), 1;
374 if (key_mouse0 <= key && key <= key_mouse7)
377 /* Movement commands */
378 if (mod.MODKEY && mod.shift) {
380 case 'h': return shift_window(win,-1, 0), 1;
381 case 'j': return shift_window(win, 0,+1), 1;
382 case 'k': return shift_window(win, 0,-1), 1;
383 case 'l': return shift_window(win,+1, 0), 1;
387 else if (mod.MODKEY) {
389 case 'h': return shift_focus(win,-1, 0), 1;
390 case 'j': return shift_focus(win, 0,+1), 1;
391 case 'k': return shift_focus(win, 0,-1), 1;
392 case 'l': return shift_focus(win,+1, 0), 1;
397 /* Column mode commands */
400 case 'd': return set_mode(win, split), 1;
401 case 's': return set_mode(win, stack), 1;
402 case 'm': return set_mode(win, max), 1;
403 case 't': return set_mode(win, tab), 1;
409 if (key == key_enter)
410 return set_focus(win), 1;
412 if (key_mouse0 <= key && key <= key_mouse7)
413 return set_focus(win), 0;
415 /* Reset focus after after focus change,
416 * not sure what is causing the focus change in the first place
417 * but preventing that would be a better solution */
418 if (key == key_focus)
424 int wm_handle_ptr(win_t *cwin, ptr_t ptr)
426 //printf("wm_handle_ptr: %p - %d,%d %d,%d (%d) -- \n",
427 // cwin, ptr.x, ptr.y, ptr.rx, ptr.ry, move_mode);
429 if (move_mode == none)
433 int dx = ptr.rx - move_prev.rx;
434 int dy = ptr.ry - move_prev.ry;
436 if (move_mode == resize) {
437 list_t *vert = move_dir.v < 0 ? move_lrow->prev : move_lrow->next;
438 list_t *horz = move_dir.h < 0 ? move_lcol->prev : move_lcol->next;
440 ROW(move_lrow)->height += move_dir.v * dy;
441 ROW(vert)->height -= move_dir.v * dy;
444 COL(move_lcol)->width += move_dir.h * dx;
445 COL(horz)->width -= move_dir.h * dx;
451 //win_t *mwin = move_win;
452 //int dx = ptr.rx - move_prev.rx;
453 //int dy = ptr.ry - move_prev.ry;
455 //if (move_mode == move)
456 // sys_move(mwin, mwin->x+dx, mwin->y+dy, mwin->w, mwin->h);
457 //else if (move_mode == resize)
458 // sys_move(mwin, mwin->x, mwin->y, mwin->w+dx, mwin->h+dy);
463 void wm_insert(win_t *win)
465 printf("wm_insert: %p\n", win);
466 print_txt(wm_dpy->cols);
468 /* Initialize window */
469 win->wm = new0(win_wm_t);
470 sys_watch(win, key_enter, MOD());
471 sys_watch(win, key_focus, MOD());
474 put_win(win, wm_col);
479 print_txt(wm_dpy->cols);
482 void wm_remove(win_t *win)
484 printf("wm_remove: %p\n", win);
485 print_txt(wm_dpy->cols);
490 sys_focus(wm_dpy->root);
492 print_txt(wm_dpy->cols);
495 void wm_init(win_t *root)
497 printf("wm_init: %p\n", root);
499 tag_t *tag = new0(tag_t);
500 dpy_t *dpy = new0(dpy_t);
503 tag->dpys = list_insert(NULL, dpy);
506 wm->tags = list_insert(NULL, tag);
509 Key_t keys_e[] = {key_enter, key_focus};
510 Key_t keys_s[] = {'h', 'j', 'k', 'l'};
511 Key_t keys_m[] = {'h', 'j', 'k', 'l', 'd', 's', 'm', 't',
512 key_f1, key_f2, key_f5, key_f6, key_mouse1, key_mouse3};
513 for (int i = 0; i < countof(keys_e); i++)
514 sys_watch(root, keys_e[i], MOD());
515 for (int i = 0; i < countof(keys_m); i++)
516 sys_watch(root, keys_m[i], MOD(.MODKEY=1));
517 for (int i = 0; i < countof(keys_s); i++)
518 sys_watch(root, keys_s[i], MOD(.MODKEY=1,.shift=1));