1 /* @(#)win.c 8.1 (Berkeley) 6/6/93 */ 2 /* $NetBSD: win.c,v 1.14 2009/04/14 08:50:06 lukem Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Edward Wang at The University of California, Berkeley. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <string.h> 37 #include "defs.h" 38 #include "char.h" 39 #include "window_string.h" 40 41 /* 42 * Higher level routines for dealing with windows. 43 * 44 * There are two types of windows: user window, and information window. 45 * User windows are the ones with a pty and shell. Information windows 46 * are for displaying error messages, and other information. 47 * 48 * The windows are doubly linked in overlapping order and divided into 49 * two groups: foreground and normal. Information 50 * windows are always foreground. User windows can be either. 51 * Addwin() adds a window to the list at the top of one of the two groups. 52 * Deletewin() deletes a window. Front() moves a window to the front 53 * of its group. Wwopen(), wwadd(), and wwdelete() should never be called 54 * directly. 55 */ 56 57 /* 58 * Open a user window. 59 */ 60 struct ww * 61 openwin(int id, int row, int col, int nrow, int ncol, int nline, char *label, int type, int uflags, char *shf, char **sh) 62 { 63 struct ww *w; 64 65 if (id < 0 && (id = findid()) < 0) 66 return 0; 67 if (row + nrow <= 0 || row > wwnrow - 1 68 || col + ncol <= 0 || col > wwncol - 1) { 69 error("Illegal window position."); 70 return 0; 71 } 72 w = wwopen(type, 0, nrow, ncol, row, col, nline); 73 if (w == NULL) { 74 error("Can't open window: %s.", wwerror()); 75 return 0; 76 } 77 w->ww_id = id; 78 window[id] = w; 79 CLR(w->ww_uflags, WWU_ALLFLAGS); 80 SET(w->ww_uflags, uflags); 81 w->ww_alt = w->ww_w; 82 if (label != NULL && setlabel(w, label) < 0) 83 error("No memory for label."); 84 wwcursor(w, 1); 85 /* 86 * We have to do this little maneuver to make sure 87 * addwin() puts w at the top, so we don't waste an 88 * insert and delete operation. 89 */ 90 setselwin((struct ww *)0); 91 addwin(w, 0); 92 setselwin(w); 93 if (wwspawn(w, shf, sh) < 0) { 94 error("Can't execute %s: %s.", shf, wwerror()); 95 closewin(w); 96 return 0; 97 } 98 return w; 99 } 100 101 int 102 findid(void) 103 { 104 int i; 105 106 for (i = 0; i < NWINDOW && window[i] != 0; i++) 107 ; 108 if (i >= NWINDOW) { 109 error("Too many windows."); 110 return -1; 111 } 112 return i; 113 } 114 115 struct ww * 116 findselwin(void) 117 { 118 struct ww *w, *s = NULL; 119 int i; 120 121 for (i = 0; i < NWINDOW; i++) 122 if ((w = window[i]) != NULL && w != selwin && 123 (s == NULL || 124 (!isfg(w) && (w->ww_order < s->ww_order || isfg(s))))) 125 s = w; 126 return s; 127 } 128 129 /* 130 * Close a user window. Close all if w == 0. 131 */ 132 void 133 closewin(struct ww *w) 134 { 135 char didit = 0; 136 int i; 137 138 if (w != NULL) { 139 closewin1(w); 140 didit++; 141 } else 142 for (i = 0; i < NWINDOW; i++) { 143 if ((w = window[i]) == NULL) 144 continue; 145 closewin1(w); 146 didit++; 147 } 148 if (didit) { 149 if (selwin == 0) { 150 if (lastselwin != 0) { 151 setselwin(lastselwin); 152 lastselwin = 0; 153 } else if ((w = findselwin())) 154 setselwin(w); 155 } 156 if (lastselwin == 0 && selwin) 157 if ((w = findselwin())) 158 lastselwin = w; 159 reframe(); 160 } 161 } 162 163 /* 164 * Open an information (display) window. 165 */ 166 struct ww * 167 openiwin(int nrow, const char *label) 168 { 169 struct ww *w; 170 171 if ((w = wwopen(WWT_INTERNAL, 0, nrow, wwncol, 2, 0, 0)) == NULL) 172 return 0; 173 SET(w->ww_wflags, WWW_MAPNL | WWW_NOINTR | WWW_NOUPDATE | WWW_UNCTRL); 174 SET(w->ww_uflags, WWU_HASFRAME | WWU_CENTER); 175 w->ww_id = -1; 176 (void) setlabel(w, label); 177 addwin(w, 1); 178 reframe(); 179 return w; 180 } 181 182 /* 183 * Close an information window. 184 */ 185 void 186 closeiwin(struct ww *w) 187 { 188 closewin1(w); 189 reframe(); 190 } 191 192 void 193 closewin1(struct ww *w) 194 { 195 if (w == selwin) 196 selwin = 0; 197 if (w == lastselwin) 198 lastselwin = 0; 199 if (w->ww_id >= 0 && w->ww_id < NWINDOW) 200 window[w->ww_id] = 0; 201 if (w->ww_label) 202 str_free(w->ww_label); 203 deletewin(w); 204 wwclose(w); 205 } 206 207 /* 208 * Move the window to the top of its group. 209 * Don't do it if already fully visible. 210 * Wwvisible() doesn't work for tinted windows. 211 * But anything to make it faster. 212 * Always reframe() if doreframe is true. 213 */ 214 void 215 front(struct ww *w, char doreframe) 216 { 217 if (w->ww_back != (isfg(w) ? framewin : fgwin) && !wwvisible(w)) { 218 deletewin(w); 219 addwin(w, isfg(w)); 220 doreframe = 1; 221 } 222 if (doreframe) 223 reframe(); 224 } 225 226 /* 227 * Add a window at the top of normal windows or foreground windows. 228 * For normal windows, we put it behind the current window. 229 */ 230 void 231 addwin(struct ww *w, char fg) 232 { 233 if (fg) { 234 wwadd(w, framewin); 235 if (fgwin == framewin) 236 fgwin = w; 237 } else 238 wwadd(w, selwin != 0 && selwin != w && !isfg(selwin) 239 ? selwin : fgwin); 240 } 241 242 /* 243 * Delete a window. 244 */ 245 void 246 deletewin(struct ww *w) 247 { 248 if (fgwin == w) 249 fgwin = w->ww_back; 250 wwdelete(w); 251 } 252 253 void 254 reframe(void) 255 { 256 struct ww *w; 257 258 wwunframe(framewin); 259 for (w = wwhead.ww_back; w != &wwhead; w = w->ww_back) 260 if (ISSET(w->ww_uflags, WWU_HASFRAME)) { 261 wwframe(w, framewin); 262 labelwin(w); 263 } 264 } 265 266 void 267 labelwin(struct ww *w) 268 { 269 int mode = w == selwin ? WWM_REV : 0; 270 271 if (!ISSET(w->ww_uflags, WWU_HASFRAME)) 272 return; 273 if (w->ww_id >= 0) { 274 char buf[2]; 275 276 buf[0] = w->ww_id + '1'; 277 buf[1] = 0; 278 wwlabel(w, framewin, 1, buf, mode); 279 } 280 if (w->ww_label) { 281 int col; 282 283 if (ISSET(w->ww_uflags, WWU_CENTER)) { 284 col = (w->ww_w.nc - strlen(w->ww_label)) / 2; 285 col = MAX(3, col); 286 } else 287 col = 3; 288 wwlabel(w, framewin, col, w->ww_label, mode); 289 } 290 } 291 292 void 293 stopwin(struct ww *w) 294 { 295 if (w->ww_pty >= 0 && w->ww_type == WWT_PTY && wwstoptty(w->ww_pty) < 0) 296 error("Can't stop output: %s.", wwerror()); 297 else 298 SET(w->ww_pflags, WWP_STOPPED); 299 } 300 301 void 302 startwin(struct ww *w) 303 { 304 if (w->ww_pty >= 0 && w->ww_type == WWT_PTY && 305 wwstarttty(w->ww_pty) < 0) 306 error("Can't start output: %s.", wwerror()); 307 else 308 CLR(w->ww_pflags, WWP_STOPPED); 309 } 310 311 void 312 sizewin(struct ww *w, int nrow, int ncol) 313 { 314 struct ww *back = w->ww_back; 315 316 w->ww_alt.nr = w->ww_w.nr; 317 w->ww_alt.nc = w->ww_w.nc; 318 wwdelete(w); 319 if (wwsize(w, nrow, ncol) < 0) 320 error("Can't resize window: %s.", wwerror()); 321 wwadd(w, back); 322 reframe(); 323 } 324 325 void 326 waitnl(struct ww *w) 327 { 328 (void) waitnl1(w, "[Type any key to continue]"); 329 } 330 331 int 332 more(struct ww *w, char always) 333 { 334 int c; 335 int uc = ISSET(w->ww_wflags, WWW_UNCTRL); 336 337 if (!always && w->ww_cur.r < w->ww_w.b - 2) 338 return 0; 339 c = waitnl1(w, "[Type escape to abort, any other key to continue]"); 340 CLR(w->ww_wflags, WWW_UNCTRL); 341 wwputs("\033E", w); 342 SET(w->ww_wflags, uc); 343 return c == ctrl('[') ? 2 : 1; 344 } 345 346 int 347 waitnl1(struct ww *w, const char *prompt) 348 { 349 int uc = ISSET(w->ww_wflags, WWW_UNCTRL); 350 351 CLR(w->ww_wflags, WWW_UNCTRL); 352 front(w, 0); 353 wwprintf(w, "\033Y%c%c\033sA%s\033rA ", 354 w->ww_w.nr - 1 + ' ', ' ', prompt); /* print on last line */ 355 wwcurtowin(w); 356 while (wwpeekc() < 0) 357 wwiomux(); 358 SET(w->ww_wflags, uc); 359 return wwgetc(); 360 } 361