2
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3
* Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 3, or (at your option)
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program (see the file COPYING); if not, see
17
* http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
18
* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
20
****************************************************************
23
/* Deals with the list of windows */
25
/* NOTE: A 'struct win *' is used as the 'data' for each row. It might make more sense
26
* to use 'struct win* ->w_number' as the 'data', instead, because that way, we can
27
* verify that the window does exist (by looking at wtab[]).
34
#include "list_generic.h"
36
extern struct layer *flayer;
37
extern struct display *display, *displays;
39
extern char *wlisttit;
40
extern char *wliststr;
42
extern struct mchar mchar_blank, mchar_so;
43
extern int renditions[];
45
extern struct win **wtab, *windows, *fore;
48
extern char *noargs[];
50
static char ListID[] = "window";
54
struct win *group; /* Set only for a W_TYPE_GROUP window */
55
int order; /* MRU? NUM? */
58
struct win *fore; /* The foreground window we had. */
61
/* Is this wdata for a group window? */
62
#define WLIST_FOR_GROUP(wdate) ((wdata)->group && !(wdata)->onblank && Layer2Window(flayer) && Layer2Window(flayer)->w_type == W_TYPE_GROUP)
64
/* This macro should not be used if 'fn' is expected to update the window list */
65
#define FOR_EACH_WINDOW(_wdata, _w, fn) do { \
66
if ((_wdata)->order == WLIST_MRU) \
69
for (_ww = windows; _ww; _ww = _ww->w_next) \
77
struct win **_ww, *_witer; \
78
for (_ww = wtab, _witer = windows; _witer && _ww - wtab < maxwin; _ww++) \
80
if (!(_w = *_ww)) continue; \
82
_witer = _witer->w_next; \
87
/* Is 'a' an ancestor of 'd'? */
89
window_ancestor(struct win *a, struct win *d)
92
return 1; /* Every window is a descendant of the 'null' group */
93
for (; d; d = d->w_group)
100
window_kill_confirm(char *buf, int len, char *data)
102
struct win *w = windows;
105
if (len || (*buf != 'y' && *buf != 'Y'))
111
/* Loop over the windows to make sure that the window actually still exists. */
112
for (; w; w = w->w_next)
113
if (w == (struct win *)data)
119
/* Pretend the selected window is the foreground window. Then trigger a non-interactive 'kill' */
128
static struct ListRow *
129
gl_Window_add_group(struct ListData *ldata, struct ListRow *row)
131
/* Right now, 'row' doesn't have any child. */
132
struct gl_Window_Data *wdata = ldata->data;
133
struct win *group = row->data, *w;
134
struct ListRow *cur = row;
136
ASSERT(wdata->nested);
138
FOR_EACH_WINDOW(wdata, w,
139
if (w->w_group != group)
142
cur = glist_add_row(ldata, w, cur);
143
if (w == wdata->fore)
144
ldata->selected = cur;
146
if (w->w_type == W_TYPE_GROUP)
147
cur = gl_Window_add_group(ldata, cur);
154
gl_Window_rebuild(struct ListData *ldata)
156
struct ListRow *row = NULL;
157
struct gl_Window_Data *wdata = ldata->data;
160
FOR_EACH_WINDOW(wdata, w,
161
if (w->w_group != wdata->group)
163
row = glist_add_row(ldata, w, row);
164
if (w == wdata->fore)
165
ldata->selected = row;
166
if (w->w_type == W_TYPE_GROUP && wdata->nested)
167
row = gl_Window_add_group(ldata, row);
169
glist_display_all(ldata);
172
static struct ListRow *
173
gl_Window_findrow(struct ListData *ldata, struct win *p)
175
struct ListRow *row = ldata->root;
176
for (; row; row = row->next)
185
gl_Window_remove(struct ListData *ldata, struct win *p)
187
struct ListRow *row = gl_Window_findrow(ldata, p);
191
/* Remove 'row'. Update 'selected', 'top', 'root' if necessary. */
193
row->next->prev = row->prev;
195
row->prev->next = row->next;
197
if (ldata->selected == row)
198
ldata->selected = row->prev ? row->prev : row->next;
199
if (ldata->top == row)
200
ldata->top = row->prev ? row->prev : row->next;
201
if (ldata->root == row)
202
ldata->root = row->next;
204
ldata->list_fn->gl_freerow(ldata, row);
211
gl_Window_header(struct ListData *ldata)
214
struct gl_Window_Data *wdata = ldata->data;
217
if ((g = (wdata->group != NULL)))
219
LPutWinMsg(flayer, "Group: ", 7, &mchar_blank, 0, 0);
220
LPutWinMsg(flayer, wdata->group->w_title, strlen(wdata->group->w_title), &mchar_blank, 7, 0);
224
str = MakeWinMsgEv(wlisttit, (struct win *)0, '%', flayer->l_width, (struct event *)0, 0);
226
LPutWinMsg(flayer, str, strlen(str), &mchar_blank, 0, g);
231
gl_Window_footer(struct ListData *ldata)
237
gl_Window_row(struct ListData *ldata, struct ListRow *lrow)
243
struct mchar mchar_rend = mchar_blank;
244
struct gl_Window_Data *wdata = ldata->data;
248
/* First, make sure we want to display this window in the list.
249
* If we are showing a list for a group, and not on blank, then we must
250
* only show the windows directly belonging to that group.
251
* Otherwise, do some more checks. */
253
for (xoff = 0, g = w->w_group; g != wdata->group; g = g->w_group)
255
display = Layer2Window(flayer) ? 0 : flayer->l_cvlist ? flayer->l_cvlist->c_display : 0;
256
str = MakeWinMsgEv(wliststr, w, '%', flayer->l_width - xoff, NULL, 0);
257
if (ldata->selected == lrow)
259
else if (w->w_monitor == MON_DONE && renditions[REND_MONITOR] != -1)
262
ApplyAttrColor(renditions[REND_MONITOR], mchar);
264
else if ((w->w_bell == BELL_DONE || w->w_bell == BELL_FOUND) && renditions[REND_BELL] != -1)
267
ApplyAttrColor(renditions[REND_BELL], mchar);
269
else if ((w->w_silence == SILENCE_FOUND || w->w_silence == SILENCE_DONE) && renditions[REND_SILENCE] != -1)
272
ApplyAttrColor(renditions[REND_SILENCE], mchar);
275
mchar = &mchar_blank;
277
LPutWinMsg(flayer, str, flayer->l_width, mchar, xoff, lrow->y);
279
LPutWinMsg(flayer, "", xoff, mchar, 0, lrow->y);
285
gl_Window_input(struct ListData *ldata, char **inp, int *len)
289
struct display *cd = display;
290
struct gl_Window_Data *wdata = ldata->data;
292
if (!ldata->selected)
295
ch = (unsigned char) **inp;
299
win = ldata->selected->data;
308
if (display && AclCheckPermWin(D_user, ACL_READ, win))
309
return; /* Not allowed to switch to this window. */
311
if (WLIST_FOR_GROUP(wdata))
312
SwitchWindow(win->w_number);
315
/* Abort list only when not in a group window. */
319
SwitchWindow(win->w_number);
325
/* Toggle MRU-ness */
326
wdata->order = wdata->order == WLIST_MRU ? WLIST_NUM : WLIST_MRU;
327
glist_remove_rows(ldata);
328
gl_Window_rebuild(ldata);
332
/* Toggle nestedness */
333
wdata->nested = !wdata->nested;
334
glist_remove_rows(ldata);
335
gl_Window_rebuild(ldata);
339
/* All-window view */
342
int order = wdata->order | (wdata->nested ? WLIST_NESTED : 0);
345
display_windows(1, order, NULL);
348
else if (!wdata->nested)
351
glist_remove_rows(ldata);
352
gl_Window_rebuild(ldata);
357
case 0177: /* Backspace */
360
if (wdata->group->w_group)
362
/* The parent is another group window. So switch to that window. */
363
struct win *g = wdata->group->w_group;
371
/* We were in a group view. Now we are moving to an all-window view.
372
* So treat it as 'windowlist on blank'. */
373
int order = wdata->order | (wdata->nested ? WLIST_NESTED : 0);
376
display_windows(1, order, NULL);
381
case ',': /* Switch numbers with the previous window. */
382
if (wdata->order == WLIST_NUM && ldata->selected->prev)
384
struct win *pw = ldata->selected->prev->data;
385
if (win->w_group != pw->w_group)
386
break; /* Do not allow switching with the parent group */
388
/* When a windows's number is successfully changed, it triggers a WListUpdatecv
389
* with NULL window. So that causes a redraw of the entire list. So reset the
390
* 'selected' after that. */
392
WindowChangeNumber(win, pw->w_number);
396
case '.': /* Switch numbers with the next window. */
397
if (wdata->order == WLIST_NUM && ldata->selected->next)
399
struct win *nw = ldata->selected->next->data;
400
if (win->w_group != nw->w_group)
401
break; /* Do not allow switching with the parent group */
404
WindowChangeNumber(win, nw->w_number);
408
case 'K': /* Kill a window */
411
snprintf(str, sizeof(str) - 1, "Really kill window %d (%s) [y/n]",
412
win->w_number, win->w_title);
413
Input(str, 1, INP_RAW, window_kill_confirm, (char *)win, 0);
417
case 033: /* escape */
419
if (!WLIST_FOR_GROUP(wdata))
421
int fnumber = wdata->onblank ? wdata->fore->w_number : -1;
425
SwitchWindow(fnumber);
430
if (ch >= '0' && ch <= '9')
432
struct ListRow *row = ldata->root;
433
for (; row; row = row->next)
435
struct win *w = row->data;
436
if (w->w_number == ch - '0')
438
struct ListRow *old = ldata->selected;
441
ldata->selected = row;
442
if (ldata->selected->y == -1)
444
/* We need to list all the rows, since we are scrolling down. But first,
445
* find the top of the visible list. */
447
glist_display_all(ldata);
451
/* just redisplay the two lines. */
452
ldata->list_fn->gl_printrow(ldata, old);
453
ldata->list_fn->gl_printrow(ldata, ldata->selected);
454
flayer->l_y = ldata->selected->y;
470
gl_Window_freerow(struct ListData *ldata, struct ListRow *row)
476
gl_Window_free(struct ListData *ldata)
483
gl_Window_match(struct ListData *ldata, struct ListRow *row, const char *needle)
485
struct win *w = row->data;
486
if (InStr(w->w_title, needle))
491
static struct GenericList gl_Window =
503
display_windows(int onblank, int order, struct win *group)
506
struct ListData *ldata;
507
struct gl_Window_Data *wdata;
509
if (flayer->l_width < 10 || flayer->l_height < 6)
511
LMsg(0, "Window size too small for window list page");
516
onblank = 0; /* When drawing a group window, ignore 'onblank' */
520
debug3("flayer %x %d %x\n", flayer, flayer->l_width, flayer->l_height);
523
LMsg(0, "windowlist -b: display required");
529
SetForeWindow((struct win *)0);
533
flayer->l_data = (char *)p->w_group;
537
if (flayer->l_width < 10 || flayer->l_height < 6)
539
LMsg(0, "Window size too small for window list page");
544
p = Layer2Window(flayer);
548
ldata = glist_display(&gl_Window, ListID);
553
/* Could not display the list. So restore the window. */
560
wdata = calloc(1, sizeof(struct gl_Window_Data));
561
wdata->group = group;
562
wdata->order = (order & ~WLIST_NESTED);
563
wdata->nested = !!(order & WLIST_NESTED);
564
wdata->onblank = onblank;
566
/* Set the most recent window as selected. */
567
wdata->fore = windows;
568
while (wdata->fore && wdata->fore->w_group != group)
569
wdata->fore = wdata->fore->w_next;
573
gl_Window_rebuild(ldata);
577
WListUpdate(struct win *p, struct ListData *ldata)
579
struct gl_Window_Data *wdata = ldata->data;
580
struct ListRow *row, *rbefore;
587
wdata->fore = ldata->selected->data; /* Try to retain the current selection */
588
glist_remove_rows(ldata);
589
gl_Window_rebuild(ldata);
593
/* First decide if this window should be displayed at all. */
595
if (wdata->order == WLIST_NUM || wdata->order == WLIST_MRU)
597
if (p->w_group != wdata->group)
602
d = window_ancestor(wdata->group, p);
608
if (gl_Window_remove(ldata, p))
609
glist_display_all(ldata);
613
/* OK, so we keep the window in the list. Update the ordering.
614
* First, find the row where this window should go to. Then, either create
615
* a new row for that window, or move the exising row for the window to the
618
if (wdata->order == WLIST_MRU)
621
for (before = windows; before; before = before->w_next)
622
if (before->w_next == p)
625
else if (wdata->order == WLIST_NUM)
627
if (p->w_number != 0)
629
struct win **w = wtab + p->w_number - 1;
630
for (; w >= wtab; w--)
632
if (*w && (*w)->w_group == wdata->group)
641
/* Now, find the row belonging to 'before' */
643
rbefore = gl_Window_findrow(ldata, before);
644
else if (wdata->nested && p->w_group) /* There's no 'before'. So find the group window */
645
rbefore = gl_Window_findrow(ldata, p->w_group);
649
/* For now, just remove the row containing 'p' if it is not already in the right place . */
650
row = gl_Window_findrow(ldata, p);
653
if (row->prev != rbefore)
655
sel = ldata->selected->data == p;
656
gl_Window_remove(ldata, p);
659
p = NULL; /* the window is in the correct place */
663
row = glist_add_row(ldata, p, rbefore);
665
ldata->selected = row;
667
glist_display_all(ldata);
675
struct ListData *ldata;
676
struct gl_Window_Data *wdata;
678
if (cv->c_layer->l_layfn != &ListLf)
680
ldata = cv->c_layer->l_data;
681
if (ldata->name != ListID)
684
CV_CALL(cv, WListUpdate(p, ldata));
690
struct display *olddisplay = display;
692
struct ListData *ldata;
693
struct gl_Window_Data *wdata;
695
for (display = displays; display; display = display->d_next)
696
for (cv = D_cvlist; cv; cv = cv->c_next)
698
if (!cv->c_layer || cv->c_layer->l_layfn != &ListLf)
700
ldata = cv->c_layer->l_data;
701
if (ldata->name != ListID)
704
if (!(wdata->order & WLIST_MRU))
706
CV_CALL(cv, WListUpdate(0, ldata));
708
display = olddisplay;