home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
x
/
xvisrc.zoo
/
windows.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
10KB
|
472 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)windows.c 2.2 (Chris & John Downey) 8/28/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
windows.c
* module function:
Window handling functions.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
#undef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
static int nwindows = 0;
static Xviwin *new_window P((Xviwin *, Xviwin *));
static bool_t setup_window P((Xviwin *));
Xviwin *
init_window(vs)
VirtScr *vs;
{
Xviwin *newwin;
newwin = new_window((Xviwin *) NULL, (Xviwin *) NULL);
if (newwin == NULL) {
return(NULL);
}
newwin->w_vs = vs;
newwin->w_nrows = (*vs->v_rows)(vs);
newwin->w_ncols = (*vs->v_cols)(vs);
/*
* Initialise screen stuff.
*/
init_screen(newwin);
newwin->w_winpos = 0;
newwin->w_cmdline = Rows - 1;
return(newwin);
}
/*
* Split the given window in half, placing a new empty
* window in the bottom section and resizing the old one
* in the top half.
*/
Xviwin *
split_window(oldwin)
Xviwin *oldwin;
{
Xviwin *newwin;
/*
* Make sure there are enough rows for the new window.
* This does not obey the minrows parameter, because
* the point is to have enough space to actually display
* a window, not just to have a zero-size one.
*/
if (oldwin->w_nrows < (MINROWS * 2))
return(NULL);
newwin = new_window(oldwin, oldwin->w_next);
if (newwin == NULL) {
return(NULL);
}
newwin->w_vs = oldwin->w_vs;
/*
* Calculate size and position of new and old windows.
*/
newwin->w_nrows = oldwin->w_nrows / 2;
newwin->w_cmdline = oldwin->w_cmdline;
newwin->w_winpos = (newwin->w_cmdline - newwin->w_nrows) + 1;
oldwin->w_nrows -= newwin->w_nrows;
oldwin->w_cmdline = newwin->w_winpos - 1;
newwin->w_ncols = oldwin->w_ncols;
return(newwin);
}
/*
* Delete the given window.
*/
void
free_window(window)
Xviwin *window;
{
if (window == NULL || nwindows < 1)
return;
if (window->w_next != NULL) {
window->w_next->w_last = window->w_last;
}
if (window->w_last != NULL) {
window->w_last->w_next = window->w_next;
}
nwindows -= 1;
window->w_buffer->b_nwindows -= 1;
free((char *) window->w_cursor);
flexdelete(&window->w_statusline);
free((char *) window);
}
/*
* Allocate a new window.
*/
static Xviwin *
new_window(last, next)
Xviwin *last, *next;
{
Xviwin *newwin;
newwin = (Xviwin *) malloc(sizeof(Xviwin));
if (newwin == NULL) {
return(NULL);
}
if (setup_window(newwin) == FALSE) {
free((char *) newwin);
return(NULL);
}
/*
* Link the window into the list.
*/
if (last != NULL) {
last->w_next = newwin;
}
if (next != NULL) {
next->w_last = newwin;
}
newwin->w_last = last;
newwin->w_next = next;
nwindows += 1;
return(newwin);
}
/*
* Set up and allocate data structures for the given window,
* assumed to contain a valid pointer to a buffer.
*
* This routine should be called after setup_buffer().
*/
static bool_t
setup_window(w)
Xviwin *w;
{
/*
* Allocate space for the status line.
*/
flexnew(&w->w_statusline);
/*
* Allocate a Posn structure for the cursor.
*/
w->w_cursor = (Posn *) malloc(sizeof(Posn));
if (w->w_cursor == NULL) {
return(FALSE);
}
return(TRUE);
}
void
map_window_onto_buffer(w, b)
Xviwin *w;
Buffer *b;
{
/*
* Connect the two together.
*/
w->w_buffer = b;
b->b_nwindows += 1;
/*
* Put the cursor and the screen in the right place.
*/
move_cursor(w, b->b_file, 0);
w->w_topline = b->b_file;
w->w_botline = b->b_lastline;
/*
* Miscellany.
*/
w->w_row = w->w_col = 0;
w->w_virtcol = 0;
w->w_curswant = 0;
w->w_set_want_col = FALSE;
w->w_curs_new = TRUE;
}
/*
* Unmap the given window from its buffer.
* We don't need to do much here, on the assumption that the
* calling code is going to do a map_window_onto_buffer()
* immediately afterwards; the vital thing is to decrement
* the window reference count.
*/
void
unmap_window(w)
Xviwin *w;
{
w->w_buffer->b_nwindows -= 1;
w->w_cursor->p_line = NULL;
w->w_topline = NULL;
w->w_botline = NULL;
}
/*
* Given a window, find the "next" one in the list.
*/
Xviwin *
next_window(window)
Xviwin *window;
{
if (window == NULL) {
return(NULL);
} else if (window->w_next != NULL) {
return(window->w_next);
} else {
Xviwin *tmp;
/*
* No next window; go to start of list.
*/
for (tmp = window; tmp->w_last != NULL; tmp = tmp->w_last)
;
return(tmp);
}
}
/*
* Find the next window onto the buffer with the given filename,
* starting at the current one; if there isn't one, or if it is
* too small to move into, return NULL.
*/
Xviwin *
find_window(window, filename)
Xviwin *window;
char *filename;
{
Xviwin *wp;
char *f;
if (window != NULL && filename != NULL) {
wp = window;
do {
f = wp->w_buffer->b_filename;
if (f != NULL && strcmp(filename, f) == 0) {
return(wp);
}
wp = next_window(wp);
} while (wp != window);
}
return(NULL);
}
/*
* Grow or shrink the given buffer window by "nlines" lines.
* We prefer to move the bottom of the window, and will only
* move the top when there is no room for manoeuvre below
* the current one - i.e. any windows are at minimum size.
*/
void
resize_window(window, nlines)
Xviwin *window;
int nlines;
{
unsigned savecho;
if (nlines == 0 || nwindows == 1) {
/*
* Nothing to do.
*/
return;
}
savecho = echo;
if (nlines < 0) {
int spare; /* num spare lines in this window */
nlines = - nlines;
/*
* The current window must always contain 2 rows,
* so that the cursor has somewhere to go.
*/
spare = window->w_nrows - MINROWS;
/*
* If the window is already as small as it
* can get, don't bother to do anything.
*/
if (spare <= 0)
return;
/*
* Don't allow any screen updating until we've
* finished moving things around.
*/
echo &= ~e_CHARUPDATE;
/*
* First shrink the current window up from the bottom.
*
* move_sline()'s return value should be negative or 0
* in this case.
*/
nlines += move_sline(window, - min(spare, nlines));
/*
* If that wasn't enough, grow the window above us
* by the appropriate number of lines.
*/
if (nlines > 0) {
(void) move_sline(window->w_last, nlines);
}
} else {
/*
* Don't allow any screen updating until we've
* finished moving things around.
*/
echo &= ~e_CHARUPDATE;
/*
* Expand window.
*/
nlines -= move_sline(window, nlines);
if (nlines > 0) {
(void) move_sline(window->w_last, -nlines);
}
}
/*
* Update screen. Note that status lines have
* already been updated by move_sline().
*
* This still needs a lot more optimization.
*/
echo = savecho;
update_all();
}
/*
* Adjust the boundary between two adjacent windows by moving the status line
* up or down, updating parameters for both windows as appropriate.
*
* Note that this can shrink the window to size 0.
*/
int
move_sline(wp, nlines)
Xviwin *wp; /* window whose status line we have to move */
int nlines; /*
* number of lines to move (negative for
* upward moves, positive for downwards)
*/
{
Xviwin *nextwin;
if (wp == NULL || (nextwin = wp->w_next) == NULL) {
return(0);
}
if (nlines < 0) { /* move upwards */
int amount;
int spare;
amount = -nlines;
spare = wp->w_nrows - Pn(P_minrows);
if (amount > spare && wp->w_last != NULL) {
/*
* Not enough space: call move_sline() recursively
* for previous line; note that the second parameter
* should be negative.
*/
(void) move_sline(wp->w_last, spare - amount);
spare = wp->w_nrows - Pn(P_minrows);
}
if (amount > spare)
amount = spare;
if (amount != 0) {
wp->w_nrows -= amount;
wp->w_cmdline -= amount;
nextwin->w_winpos -= amount;
nextwin->w_nrows += amount;
(void) shiftdown(nextwin, (unsigned) amount);
if (wp->w_nrows > 0) {
show_file_info(wp);
}
}
nlines = -amount; /* return value */
} else { /* move downwards */
int spare;
spare = nextwin->w_nrows - Pn(P_minrows);
if (nlines > spare) {
/*
* Not enough space: call move_sline()
* recursively for next line.
*/
(void) move_sline(nextwin, nlines - spare);
spare = nextwin->w_nrows - Pn(P_minrows);
}
if (nlines > spare)
nlines = spare;
if (nlines != 0) {
wp->w_nrows += nlines;
wp->w_cmdline += nlines;
nextwin->w_winpos += nlines;
nextwin->w_nrows -= nlines;
(void) shiftup(nextwin, (unsigned) nlines);
if (wp->w_nrows > 0) {
show_file_info(wp);
}
}
}
return(nlines);
}
/*
* Update all windows associated with the given buffer.
*/
void
update_buffer(buffer)
Buffer *buffer;
{
Xviwin *w;
w = curwin; /* as good a place as any to start */
do {
if (w->w_buffer == buffer) {
update_window(w);
}
w = next_window(w);
} while (w != curwin);
}
bool_t
can_split()
{
return(nwindows < Pn(P_autosplit));
}