1 |
|
|
/* $OpenBSD: resizeterm.c,v 1.3 2010/01/12 23:22:06 nicm Exp $ */ |
2 |
|
|
|
3 |
|
|
/**************************************************************************** |
4 |
|
|
* Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * |
5 |
|
|
* * |
6 |
|
|
* Permission is hereby granted, free of charge, to any person obtaining a * |
7 |
|
|
* copy of this software and associated documentation files (the * |
8 |
|
|
* "Software"), to deal in the Software without restriction, including * |
9 |
|
|
* without limitation the rights to use, copy, modify, merge, publish, * |
10 |
|
|
* distribute, distribute with modifications, sublicense, and/or sell * |
11 |
|
|
* copies of the Software, and to permit persons to whom the Software is * |
12 |
|
|
* furnished to do so, subject to the following conditions: * |
13 |
|
|
* * |
14 |
|
|
* The above copyright notice and this permission notice shall be included * |
15 |
|
|
* in all copies or substantial portions of the Software. * |
16 |
|
|
* * |
17 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
18 |
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
19 |
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
20 |
|
|
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
21 |
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
22 |
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
23 |
|
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
24 |
|
|
* * |
25 |
|
|
* Except as contained in this notice, the name(s) of the above copyright * |
26 |
|
|
* holders shall not be used in advertising or otherwise to promote the * |
27 |
|
|
* sale, use or other dealings in this Software without prior written * |
28 |
|
|
* authorization. * |
29 |
|
|
****************************************************************************/ |
30 |
|
|
|
31 |
|
|
/**************************************************************************** |
32 |
|
|
* Author: Thomas E. Dickey * |
33 |
|
|
****************************************************************************/ |
34 |
|
|
|
35 |
|
|
/* |
36 |
|
|
* This is an extension to the curses library. It provides callers with a hook |
37 |
|
|
* into the NCURSES data to resize windows, primarily for use by programs |
38 |
|
|
* running in an X Window terminal (e.g., xterm). I abstracted this module |
39 |
|
|
* from my application library for NCURSES because it must be compiled with |
40 |
|
|
* the private data structures -- T.Dickey 1995/7/4. |
41 |
|
|
*/ |
42 |
|
|
|
43 |
|
|
#include <curses.priv.h> |
44 |
|
|
#include <term.h> |
45 |
|
|
|
46 |
|
|
MODULE_ID("$Id: resizeterm.c,v 1.3 2010/01/12 23:22:06 nicm Exp $") |
47 |
|
|
|
48 |
|
|
#define stolen_lines (screen_lines - SP->_lines_avail) |
49 |
|
|
|
50 |
|
|
/* |
51 |
|
|
* If we're trying to be reentrant, do not want any local statics. |
52 |
|
|
*/ |
53 |
|
|
#if USE_REENTRANT |
54 |
|
|
#define EXTRA_ARGS , CurLines, CurCols |
55 |
|
|
#define EXTRA_DCLS , int CurLines, int CurCols |
56 |
|
|
#else |
57 |
|
|
static int current_lines; |
58 |
|
|
static int current_cols; |
59 |
|
|
#define CurLines current_lines |
60 |
|
|
#define CurCols current_cols |
61 |
|
|
#define EXTRA_ARGS /* nothing */ |
62 |
|
|
#define EXTRA_DCLS /* nothing */ |
63 |
|
|
#endif |
64 |
|
|
|
65 |
|
|
#ifdef TRACE |
66 |
|
|
static void |
67 |
|
|
show_window_sizes(const char *name) |
68 |
|
|
{ |
69 |
|
|
WINDOWLIST *wp; |
70 |
|
|
|
71 |
|
|
_nc_lock_global(curses); |
72 |
|
|
_tracef("%s resizing: %2d x %2d (%2d x %2d)", name, LINES, COLS, |
73 |
|
|
screen_lines, screen_columns); |
74 |
|
|
for (each_window(wp)) { |
75 |
|
|
_tracef(" window %p is %2ld x %2ld at %2ld,%2ld", |
76 |
|
|
&(wp->win), |
77 |
|
|
(long) wp->win._maxy + 1, |
78 |
|
|
(long) wp->win._maxx + 1, |
79 |
|
|
(long) wp->win._begy, |
80 |
|
|
(long) wp->win._begx); |
81 |
|
|
} |
82 |
|
|
_nc_unlock_global(curses); |
83 |
|
|
} |
84 |
|
|
#endif |
85 |
|
|
|
86 |
|
|
/* |
87 |
|
|
* Return true if the given dimensions do not match the internal terminal |
88 |
|
|
* structure's size. |
89 |
|
|
*/ |
90 |
|
|
NCURSES_EXPORT(bool) |
91 |
|
|
is_term_resized(int ToLines, int ToCols) |
92 |
|
|
{ |
93 |
|
|
T((T_CALLED("is_term_resized(%d, %d)"), ToLines, ToCols)); |
94 |
|
|
returnCode(ToLines > 0 |
95 |
|
|
&& ToCols > 0 |
96 |
|
|
&& (ToLines != screen_lines |
97 |
|
|
|| ToCols != screen_columns)); |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
/* |
101 |
|
|
*/ |
102 |
|
|
static ripoff_t * |
103 |
|
|
ripped_window(WINDOW *win) |
104 |
|
|
{ |
105 |
|
|
ripoff_t *result = 0; |
106 |
|
|
ripoff_t *rop; |
107 |
|
|
|
108 |
|
|
if (win != 0) { |
109 |
|
|
for (each_ripoff(rop)) { |
110 |
|
|
if (rop->win == win && rop->line != 0) { |
111 |
|
|
result = rop; |
112 |
|
|
break; |
113 |
|
|
} |
114 |
|
|
} |
115 |
|
|
} |
116 |
|
|
return result; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
/* |
120 |
|
|
* Returns the number of lines from the bottom for the beginning of a ripped |
121 |
|
|
* off window. |
122 |
|
|
*/ |
123 |
|
|
static int |
124 |
|
|
ripped_bottom(WINDOW *win) |
125 |
|
|
{ |
126 |
|
|
int result = 0; |
127 |
|
|
ripoff_t *rop; |
128 |
|
|
|
129 |
|
|
if (win != 0) { |
130 |
|
|
for (each_ripoff(rop)) { |
131 |
|
|
if (rop->line < 0) { |
132 |
|
|
result -= rop->line; |
133 |
|
|
if (rop->win == win) { |
134 |
|
|
break; |
135 |
|
|
} |
136 |
|
|
} |
137 |
|
|
} |
138 |
|
|
} |
139 |
|
|
return result; |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
/* |
143 |
|
|
* Return the number of levels of child-windows under the current window. |
144 |
|
|
*/ |
145 |
|
|
static int |
146 |
|
|
child_depth(WINDOW *cmp) |
147 |
|
|
{ |
148 |
|
|
int depth = 0; |
149 |
|
|
|
150 |
|
|
if (cmp != 0) { |
151 |
|
|
WINDOWLIST *wp; |
152 |
|
|
|
153 |
|
|
for (each_window(wp)) { |
154 |
|
|
WINDOW *tst = &(wp->win); |
155 |
|
|
if (tst->_parent == cmp) { |
156 |
|
|
depth = 1 + child_depth(tst); |
157 |
|
|
break; |
158 |
|
|
} |
159 |
|
|
} |
160 |
|
|
} |
161 |
|
|
return depth; |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
/* |
165 |
|
|
* Return the number of levels of parent-windows above the current window. |
166 |
|
|
*/ |
167 |
|
|
static int |
168 |
|
|
parent_depth(WINDOW *cmp) |
169 |
|
|
{ |
170 |
|
|
int depth = 0; |
171 |
|
|
|
172 |
|
|
if (cmp != 0) { |
173 |
|
|
WINDOW *tst; |
174 |
|
|
while ((tst = cmp->_parent) != 0) { |
175 |
|
|
++depth; |
176 |
|
|
cmp = tst; |
177 |
|
|
} |
178 |
|
|
} |
179 |
|
|
return depth; |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
/* |
183 |
|
|
* FIXME: must adjust position so it's within the parent! |
184 |
|
|
*/ |
185 |
|
|
static int |
186 |
|
|
adjust_window(WINDOW *win, int ToLines, int ToCols, int stolen EXTRA_DCLS) |
187 |
|
|
{ |
188 |
|
|
int result; |
189 |
|
|
int bottom = CurLines + SP->_topstolen - stolen; |
190 |
|
|
int myLines = win->_maxy + 1; |
191 |
|
|
int myCols = win->_maxx + 1; |
192 |
|
|
ripoff_t *rop = ripped_window(win); |
193 |
|
|
|
194 |
|
|
T((T_CALLED("adjust_window(%p,%d,%d)%s depth %d/%d currently %ldx%ld at %ld,%ld"), |
195 |
|
|
win, ToLines, ToCols, |
196 |
|
|
(rop != 0) ? " (rip)" : "", |
197 |
|
|
parent_depth(win), |
198 |
|
|
child_depth(win), |
199 |
|
|
(long) getmaxy(win), (long) getmaxx(win), |
200 |
|
|
(long) getbegy(win) + win->_yoffset, (long) getbegx(win))); |
201 |
|
|
|
202 |
|
|
if (rop != 0 && rop->line < 0) { |
203 |
|
|
/* |
204 |
|
|
* If it is a ripped-off window at the bottom of the screen, simply |
205 |
|
|
* move it to the same relative position. |
206 |
|
|
*/ |
207 |
|
|
win->_begy = ToLines - ripped_bottom(win) - 0 - win->_yoffset; |
208 |
|
|
} else if (win->_begy >= bottom) { |
209 |
|
|
/* |
210 |
|
|
* If it is below the bottom of the new screen, move up by the same |
211 |
|
|
* amount that the screen shrank. |
212 |
|
|
*/ |
213 |
|
|
win->_begy += (ToLines - CurLines); |
214 |
|
|
} else { |
215 |
|
|
if (myLines == (CurLines - stolen) |
216 |
|
|
&& ToLines != CurLines) { |
217 |
|
|
myLines = ToLines - stolen; |
218 |
|
|
} else if (myLines == CurLines |
219 |
|
|
&& ToLines != CurLines) { |
220 |
|
|
myLines = ToLines; |
221 |
|
|
} |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
if (myLines > ToLines) { |
225 |
|
|
myLines = ToLines; |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
if (myCols > ToCols) |
229 |
|
|
myCols = ToCols; |
230 |
|
|
|
231 |
|
|
if (myCols == CurCols |
232 |
|
|
&& ToCols != CurCols) |
233 |
|
|
myCols = ToCols; |
234 |
|
|
|
235 |
|
|
result = wresize(win, myLines, myCols); |
236 |
|
|
returnCode(result); |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
/* |
240 |
|
|
* If we're decreasing size, recursively search for windows that have no |
241 |
|
|
* children, decrease those to fit, then decrease the containing window, etc. |
242 |
|
|
*/ |
243 |
|
|
static int |
244 |
|
|
decrease_size(int ToLines, int ToCols, int stolen EXTRA_DCLS) |
245 |
|
|
{ |
246 |
|
|
bool found; |
247 |
|
|
int depth = 0; |
248 |
|
|
WINDOWLIST *wp; |
249 |
|
|
|
250 |
|
|
T((T_CALLED("decrease_size(%d, %d)"), ToLines, ToCols)); |
251 |
|
|
|
252 |
|
|
do { |
253 |
|
|
found = FALSE; |
254 |
|
|
TR(TRACE_UPDATE, ("decreasing size of windows to %dx%d, depth=%d", |
255 |
|
|
ToLines, ToCols, depth)); |
256 |
|
|
for (each_window(wp)) { |
257 |
|
|
WINDOW *win = &(wp->win); |
258 |
|
|
|
259 |
|
|
if (!(win->_flags & _ISPAD)) { |
260 |
|
|
if (child_depth(win) == depth) { |
261 |
|
|
found = TRUE; |
262 |
|
|
if (adjust_window(win, ToLines, ToCols, |
263 |
|
|
stolen EXTRA_ARGS) != OK) |
264 |
|
|
returnCode(ERR); |
265 |
|
|
} |
266 |
|
|
} |
267 |
|
|
} |
268 |
|
|
++depth; |
269 |
|
|
} while (found); |
270 |
|
|
returnCode(OK); |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
/* |
274 |
|
|
* If we're increasing size, recursively search for windows that have no |
275 |
|
|
* parent, increase those to fit, then increase the contained window, etc. |
276 |
|
|
*/ |
277 |
|
|
static int |
278 |
|
|
increase_size(int ToLines, int ToCols, int stolen EXTRA_DCLS) |
279 |
|
|
{ |
280 |
|
|
bool found; |
281 |
|
|
int depth = 0; |
282 |
|
|
WINDOWLIST *wp; |
283 |
|
|
|
284 |
|
|
T((T_CALLED("increase_size(%d, %d)"), ToLines, ToCols)); |
285 |
|
|
|
286 |
|
|
do { |
287 |
|
|
found = FALSE; |
288 |
|
|
TR(TRACE_UPDATE, ("increasing size of windows to %dx%d, depth=%d", |
289 |
|
|
ToLines, ToCols, depth)); |
290 |
|
|
for (each_window(wp)) { |
291 |
|
|
WINDOW *win = &(wp->win); |
292 |
|
|
|
293 |
|
|
if (!(win->_flags & _ISPAD)) { |
294 |
|
|
if (parent_depth(win) == depth) { |
295 |
|
|
found = TRUE; |
296 |
|
|
if (adjust_window(win, ToLines, ToCols, |
297 |
|
|
stolen EXTRA_ARGS) != OK) |
298 |
|
|
returnCode(ERR); |
299 |
|
|
} |
300 |
|
|
} |
301 |
|
|
} |
302 |
|
|
++depth; |
303 |
|
|
} while (found); |
304 |
|
|
returnCode(OK); |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
/* |
308 |
|
|
* This function reallocates NCURSES window structures, with no side-effects |
309 |
|
|
* such as ungetch(). |
310 |
|
|
*/ |
311 |
|
|
NCURSES_EXPORT(int) |
312 |
|
|
resize_term(int ToLines, int ToCols) |
313 |
|
|
{ |
314 |
|
|
int result = OK EXTRA_ARGS; |
315 |
|
|
int was_stolen; |
316 |
|
|
|
317 |
|
|
T((T_CALLED("resize_term(%d,%d) old(%d,%d)"), |
318 |
|
|
ToLines, ToCols, |
319 |
|
|
screen_lines, screen_columns)); |
320 |
|
|
|
321 |
|
|
if (SP == 0) { |
322 |
|
|
returnCode(ERR); |
323 |
|
|
} |
324 |
|
|
|
325 |
|
|
_nc_lock_global(curses); |
326 |
|
|
|
327 |
|
|
was_stolen = (screen_lines - SP->_lines_avail); |
328 |
|
|
if (is_term_resized(ToLines, ToCols)) { |
329 |
|
|
int myLines = CurLines = screen_lines; |
330 |
|
|
int myCols = CurCols = screen_columns; |
331 |
|
|
|
332 |
|
|
#ifdef TRACE |
333 |
|
|
if (USE_TRACEF(TRACE_UPDATE)) { |
334 |
|
|
show_window_sizes("before"); |
335 |
|
|
_nc_unlock_global(tracef); |
336 |
|
|
} |
337 |
|
|
#endif |
338 |
|
|
if (ToLines > screen_lines) { |
339 |
|
|
increase_size(myLines = ToLines, myCols, was_stolen EXTRA_ARGS); |
340 |
|
|
CurLines = myLines; |
341 |
|
|
CurCols = myCols; |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
if (ToCols > screen_columns) { |
345 |
|
|
increase_size(myLines, myCols = ToCols, was_stolen EXTRA_ARGS); |
346 |
|
|
CurLines = myLines; |
347 |
|
|
CurCols = myCols; |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
if (ToLines < myLines || |
351 |
|
|
ToCols < myCols) { |
352 |
|
|
decrease_size(ToLines, ToCols, was_stolen EXTRA_ARGS); |
353 |
|
|
} |
354 |
|
|
|
355 |
|
|
screen_lines = lines = ToLines; |
356 |
|
|
screen_columns = columns = ToCols; |
357 |
|
|
|
358 |
|
|
SP->_lines_avail = lines - was_stolen; |
359 |
|
|
|
360 |
|
|
if (SP->oldhash) { |
361 |
|
|
FreeAndNull(SP->oldhash); |
362 |
|
|
} |
363 |
|
|
if (SP->newhash) { |
364 |
|
|
FreeAndNull(SP->newhash); |
365 |
|
|
} |
366 |
|
|
#ifdef TRACE |
367 |
|
|
if (USE_TRACEF(TRACE_UPDATE)) { |
368 |
|
|
SET_LINES(ToLines - was_stolen); |
369 |
|
|
SET_COLS(ToCols); |
370 |
|
|
show_window_sizes("after"); |
371 |
|
|
_nc_unlock_global(tracef); |
372 |
|
|
} |
373 |
|
|
#endif |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
/* |
377 |
|
|
* Always update LINES, to allow for call from lib_doupdate.c which |
378 |
|
|
* needs to have the count adjusted by the stolen (ripped off) lines. |
379 |
|
|
*/ |
380 |
|
|
SET_LINES(ToLines - was_stolen); |
381 |
|
|
SET_COLS(ToCols); |
382 |
|
|
|
383 |
|
|
_nc_unlock_global(curses); |
384 |
|
|
|
385 |
|
|
returnCode(result); |
386 |
|
|
} |
387 |
|
|
|
388 |
|
|
/* |
389 |
|
|
* This function reallocates NCURSES window structures. It is invoked in |
390 |
|
|
* response to a SIGWINCH interrupt. Other user-defined windows may also need |
391 |
|
|
* to be reallocated. |
392 |
|
|
* |
393 |
|
|
* Because this performs memory allocation, it should not (in general) be |
394 |
|
|
* invoked directly from the signal handler. |
395 |
|
|
*/ |
396 |
|
|
NCURSES_EXPORT(int) |
397 |
|
|
resizeterm(int ToLines, int ToCols) |
398 |
|
|
{ |
399 |
|
|
int result = ERR; |
400 |
|
|
|
401 |
|
|
T((T_CALLED("resizeterm(%d,%d) old(%d,%d)"), |
402 |
|
|
ToLines, ToCols, |
403 |
|
|
screen_lines, screen_columns)); |
404 |
|
|
|
405 |
|
|
if (SP != 0) { |
406 |
|
|
result = OK; |
407 |
|
|
SP->_sig_winch = FALSE; |
408 |
|
|
|
409 |
|
|
if (is_term_resized(ToLines, ToCols)) { |
410 |
|
|
#if USE_SIGWINCH |
411 |
|
|
ripoff_t *rop; |
412 |
|
|
bool slk_visible = (SP != 0 |
413 |
|
|
&& SP->_slk != 0 |
414 |
|
|
&& !(SP->_slk->hidden)); |
415 |
|
|
|
416 |
|
|
if (slk_visible) { |
417 |
|
|
slk_clear(); |
418 |
|
|
} |
419 |
|
|
#endif |
420 |
|
|
result = resize_term(ToLines, ToCols); |
421 |
|
|
|
422 |
|
|
#if USE_SIGWINCH |
423 |
|
|
_nc_ungetch(SP, KEY_RESIZE); /* so application can know this */ |
424 |
|
|
clearok(curscr, TRUE); /* screen contents are unknown */ |
425 |
|
|
|
426 |
|
|
/* ripped-off lines are a special case: if we did not lengthen |
427 |
|
|
* them, we haven't moved them either. repaint them, too. |
428 |
|
|
* |
429 |
|
|
* for the rest - stdscr and other windows - the client has to |
430 |
|
|
* decide which to repaint, since without panels, ncurses does |
431 |
|
|
* not know which are really on top. |
432 |
|
|
*/ |
433 |
|
|
for (each_ripoff(rop)) { |
434 |
|
|
if (rop->win != stdscr |
435 |
|
|
&& rop->win != 0 |
436 |
|
|
&& rop->line < 0) { |
437 |
|
|
|
438 |
|
|
if (rop->hook != _nc_slk_initialize) { |
439 |
|
|
touchwin(rop->win); |
440 |
|
|
wnoutrefresh(rop->win); |
441 |
|
|
} |
442 |
|
|
} |
443 |
|
|
} |
444 |
|
|
|
445 |
|
|
/* soft-keys are a special case: we _know_ how to repaint them */ |
446 |
|
|
if (slk_visible) { |
447 |
|
|
slk_restore(); |
448 |
|
|
slk_touch(); |
449 |
|
|
|
450 |
|
|
slk_refresh(); |
451 |
|
|
} |
452 |
|
|
#endif |
453 |
|
|
} |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
returnCode(result); |
457 |
|
|
} |