Annotation of src/usr.bin/tmux/layout.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: layout.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <string.h>
22:
23: #include "tmux.h"
24:
25: /*
26: * Each layout has two functions, _refresh to relayout the panes and _resize to
27: * resize a single pane.
28: *
29: * Second argument (int) to _refresh is 1 if the only change has been that the
30: * active pane has changed. If 0 then panes, active pane or both may have
31: * changed.
32: */
33:
34: void layout_active_only_refresh(struct window *, int);
35: void layout_even_h_refresh(struct window *, int);
36: void layout_even_v_refresh(struct window *, int);
37: void layout_main_h_refresh(struct window *, int);
38: void layout_main_v_refresh(struct window *, int);
39:
40: const struct {
41: const char *name;
42: void (*refresh)(struct window *, int);
43: void (*resize)(struct window_pane *, int);
44: } layouts[] = {
45: { "manual-vertical", layout_manual_v_refresh, layout_manual_v_resize },
46: { "active-only", layout_active_only_refresh, NULL },
47: { "even-horizontal", layout_even_h_refresh, NULL },
48: { "even-vertical", layout_even_v_refresh, NULL },
49: { "main-horizontal", layout_main_h_refresh, NULL },
50: { "main-vertical", layout_main_v_refresh, NULL },
51: };
52:
53: const char *
54: layout_name(struct window *w)
55: {
56: return (layouts[w->layout].name);
57: }
58:
59: int
60: layout_lookup(const char *name)
61: {
62: u_int i;
63: int matched = -1;
64:
65: for (i = 0; i < nitems(layouts); i++) {
66: if (strncmp(layouts[i].name, name, strlen(name)) == 0) {
67: if (matched != -1) /* ambiguous */
68: return (-1);
69: matched = i;
70: }
71: }
72:
73: return (matched);
74: }
75:
76: int
77: layout_select(struct window *w, u_int layout)
78: {
79: if (layout > nitems(layouts) - 1 || layout == w->layout)
80: return (-1);
81: w->layout = layout;
82:
83: layout_refresh(w, 0);
84: return (0);
85: }
86:
87: void
88: layout_next(struct window *w)
89: {
90: w->layout++;
91: if (w->layout > nitems(layouts) - 1)
92: w->layout = 0;
93: layout_refresh(w, 0);
94: }
95:
96: void
97: layout_previous(struct window *w)
98: {
99: if (w->layout == 0)
100: w->layout = nitems(layouts) - 1;
101: else
102: w->layout--;
103: layout_refresh(w, 0);
104: }
105:
106: void
107: layout_refresh(struct window *w, int active_only)
108: {
109: layouts[w->layout].refresh(w, active_only);
110: server_redraw_window(w);
111: }
112:
113: int
114: layout_resize(struct window_pane *wp, int adjust)
115: {
116: struct window *w = wp->window;
117:
118: if (layouts[w->layout].resize == NULL)
119: return (-1);
120: layouts[w->layout].resize(wp, adjust);
121: return (0);
122: }
123:
124: void
125: layout_active_only_refresh(struct window *w, unused int active_only)
126: {
127: struct window_pane *wp;
1.2 ! nicm 128: u_int xoff;
1.1 nicm 129:
1.2 ! nicm 130: xoff = w->sx;
1.1 nicm 131: TAILQ_FOREACH(wp, &w->panes, entry) {
1.2 ! nicm 132: /* Put the active pane on screen and the rest to the right. */
! 133: if (wp == w->active)
! 134: wp->xoff = 0;
! 135: else {
! 136: wp->xoff = xoff;
! 137: xoff += w->sx;
! 138: }
! 139: wp->yoff = 0;
! 140: window_pane_resize(wp, w->sx, w->sy);
1.1 nicm 141: }
142: }
143:
144: void
145: layout_even_h_refresh(struct window *w, int active_only)
146: {
147: struct window_pane *wp;
148: u_int i, n, width, xoff;
149:
150: if (active_only)
151: return;
152:
1.2 ! nicm 153: /* If the screen is too small, show active only. */
! 154: if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) {
! 155: layout_active_only_refresh(w, active_only);
! 156: return;
! 157: }
! 158:
1.1 nicm 159: /* Get number of panes. */
160: n = window_count_panes(w);
161: if (n == 0)
162: return;
163:
164: /* How many can we fit? */
165: if (w->sx / n < PANE_MINIMUM) {
166: width = PANE_MINIMUM;
1.2 ! nicm 167: n = UINT_MAX;
1.1 nicm 168: } else
169: width = w->sx / n;
170:
171: /* Fit the panes. */
172: i = xoff = 0;
173: TAILQ_FOREACH(wp, &w->panes, entry) {
174: wp->xoff = xoff;
175: wp->yoff = 0;
176: if (i != n - 1)
177: window_pane_resize(wp, width - 1, w->sy);
178: else
179: window_pane_resize(wp, width, w->sy);
180:
181: i++;
182: xoff += width;
183: }
184:
185: /* Any space left? */
186: while (xoff++ < w->sx) {
187: wp = TAILQ_LAST(&w->panes, window_panes);
188: window_pane_resize(wp, wp->sx + 1, wp->sy);
189: }
190: }
191:
192: void
193: layout_even_v_refresh(struct window *w, int active_only)
194: {
195: struct window_pane *wp;
196: u_int i, n, height, yoff;
197:
198: if (active_only)
199: return;
200:
1.2 ! nicm 201: /* If the screen is too small, show active only. */
! 202: if (w->sx < PANE_MINIMUM || w->sy < PANE_MINIMUM) {
! 203: layout_active_only_refresh(w, active_only);
! 204: return;
! 205: }
! 206:
1.1 nicm 207: /* Get number of panes. */
208: n = window_count_panes(w);
209: if (n == 0)
210: return;
211:
212: /* How many can we fit? */
213: if (w->sy / n < PANE_MINIMUM) {
214: height = PANE_MINIMUM;
1.2 ! nicm 215: n = UINT_MAX;
1.1 nicm 216: } else
217: height = w->sy / n;
218:
219: /* Fit the panes. */
220: i = yoff = 0;
221: TAILQ_FOREACH(wp, &w->panes, entry) {
222: wp->xoff = 0;
223: wp->yoff = yoff;
224: if (i != n - 1)
225: window_pane_resize(wp, w->sx, height - 1);
226: else
227: window_pane_resize(wp, w->sx, height);
228:
229: i++;
230: yoff += height;
231: }
232:
233: /* Any space left? */
234: while (yoff++ < w->sy) {
235: wp = TAILQ_LAST(&w->panes, window_panes);
236: window_pane_resize(wp, wp->sx, wp->sy + 1);
237: }
238: }
239:
240: void
241: layout_main_v_refresh(struct window *w, int active_only)
242: {
243: struct window_pane *wp;
244: u_int i, n, mainwidth, height, yoff;
245:
246: if (active_only)
247: return;
248:
249: /* Get number of panes. */
250: n = window_count_panes(w);
251: if (n == 0)
252: return;
253:
254: /* Get the main pane width and add one for separator line. */
255: mainwidth = options_get_number(&w->options, "main-pane-width") + 1;
256:
257: /* Need >1 pane and minimum columns; if fewer, display active only. */
1.2 ! nicm 258: if (n == 1 ||
! 259: w->sx < mainwidth + PANE_MINIMUM || w->sy < PANE_MINIMUM) {
1.1 nicm 260: layout_active_only_refresh(w, active_only);
261: return;
262: }
263: n--;
264:
265: /* How many can we fit, not including first? */
266: if (w->sy / n < PANE_MINIMUM) {
267: height = PANE_MINIMUM;
268: n = w->sy / PANE_MINIMUM;
269: } else
270: height = w->sy / n;
271:
272: /* Fit the panes. */
273: i = yoff = 0;
274: TAILQ_FOREACH(wp, &w->panes, entry) {
275: if (wp == TAILQ_FIRST(&w->panes)) {
276: wp->xoff = 0;
277: wp->yoff = 0;
278: window_pane_resize(wp, mainwidth - 1, w->sy);
279: continue;
280: }
281:
282: wp->xoff = mainwidth;
283: wp->yoff = yoff;
284: if (i != n - 1)
285: window_pane_resize(wp, w->sx - mainwidth, height - 1);
286: else
287: window_pane_resize(wp, w->sx - mainwidth, height);
288:
289: i++;
290: yoff += height;
291: }
292:
293: /* Any space left? */
294: while (yoff++ < w->sy) {
295: wp = TAILQ_LAST(&w->panes, window_panes);
296: while (wp != NULL && wp == TAILQ_FIRST(&w->panes))
297: wp = TAILQ_PREV(wp, window_panes, entry);
298: if (wp == NULL)
299: break;
300: window_pane_resize(wp, wp->sx, wp->sy + 1);
301: }
302: }
303:
304: void
305: layout_main_h_refresh(struct window *w, int active_only)
306: {
307: struct window_pane *wp;
308: u_int i, n, mainheight, width, xoff;
309:
310: if (active_only)
311: return;
312:
313: /* Get number of panes. */
314: n = window_count_panes(w);
315: if (n == 0)
316: return;
317:
318: /* Get the main pane height and add one for separator line. */
319: mainheight = options_get_number(&w->options, "main-pane-height") + 1;
320:
321: /* Need >1 pane and minimum rows; if fewer, display active only. */
1.2 ! nicm 322: if (n == 1 ||
! 323: w->sy < mainheight + PANE_MINIMUM || w->sx < PANE_MINIMUM) {
1.1 nicm 324: layout_active_only_refresh(w, active_only);
325: return;
326: }
327: n--;
328:
329: /* How many can we fit, not including first? */
330: if (w->sx / n < PANE_MINIMUM) {
331: width = PANE_MINIMUM;
332: n = w->sx / PANE_MINIMUM;
333: } else
334: width = w->sx / n;
335:
336: /* Fit the panes. */
337: i = xoff = 0;
338: TAILQ_FOREACH(wp, &w->panes, entry) {
339: if (wp == TAILQ_FIRST(&w->panes)) {
340: wp->xoff = 0;
341: wp->yoff = 0;
342: window_pane_resize(wp, w->sx, mainheight - 1);
343: continue;
344: }
345:
346: wp->xoff = xoff;
347: wp->yoff = mainheight;
348: if (i != n - 1)
349: window_pane_resize(wp, width - 1, w->sy - mainheight);
350: else
351: window_pane_resize(wp, width - 1, w->sy - mainheight);
352:
353: i++;
354: xoff += width;
355: }
356:
357: /* Any space left? */
358: while (xoff++ < w->sx + 1) {
359: wp = TAILQ_LAST(&w->panes, window_panes);
360: while (wp != NULL && wp == TAILQ_FIRST(&w->panes))
361: wp = TAILQ_PREV(wp, window_panes, entry);
362: if (wp == NULL)
363: break;
364: window_pane_resize(wp, wp->sx + 1, wp->sy);
365: }
366: }