#ident "@(#)window.c 1.13"
/*
* window.c: Handles the Main Window stuff for irc. This includes proper
* scrolling, saving of screen memory, refreshing, clearing, etc.
*
* Written By Michael Sandrof
*
* Copyright(c) 1990
* Modified 1996 Colten Edwards
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "irc.h"
#include "screen.h"
#include "window.h"
#include "vars.h"
#include "server.h"
#include "list.h"
#include "ircterm.h"
#include "names.h"
#include "ircaux.h"
#include "input.h"
#include "status.h"
#include "output.h"
#include "log.h"
#include "hook.h"
#include "dcc.h"
#include "misc.h"
#include "tcommand.h"
/* Resize relatively or absolutely? */
#define RESIZE_REL 1
#define RESIZE_ABS 2
Window *invisible_list = NULL; /* list of hidden windows */
char *who_from = NULL;
int who_level = LOG_CRAP; /* Log level of message being displayed */
int in_window_command = 0; /* set to true if we are in window(). This is used if a put_it() is called within the window()
* command. We make sure all windows are fully updated before doing the put_it(). */
/*
* window_display: this controls the display, 1 being ON, 0 being OFF. The
* DISPLAY var sets this.
*/
unsigned int window_display = 1;
/*
* status_update_flag: if 1, the status is updated as normal. If 0, then all
* status updating is suppressed
*/
int status_update_flag = 1;
static void remove_from_invisible_list(Window * window);
void remove_from_window_list(Window * window);
static void swap_window(Window * v_window, Window * window);
static Window *get_next_window(void);
static Window *get_previous_window(void);
static void revamp_window_levels(Window * window);
void clear_window(Window * window);
static void resize_window_display(Window * window);
/*
* new_window: This creates a new window on the screen. It does so by either
* splitting the current window, or if it can't do that, it splits the
* largest window. The new window is added to the window list and made the
* current window
*/
Window *new_window(void)
{
Window *new;
Window *tmp;
static int no_screens = 1;
unsigned int new_refnum = 1;
if (no_screens) {
set_current_screen(create_new_screen());
no_screens = 0;
}
new = (Window *) new_malloc(sizeof(Window));
tmp = NULL;
while (traverse_all_windows(&tmp)) {
if (tmp->refnum == new_refnum) {
new_refnum++;
tmp = NULL;
}
}
new->refnum = new_refnum;
if (curr_scr_win)
new->server = curr_scr_win->server;
else
new->server = primary_server;
if (current_screen->visible_windows)
new->window_level = LOG_NONE;
new->scroll = get_int_var(SCROLL_VAR);
new->lastlog_level = real_lastlog_level();
new->lastlog_max = get_int_var(LASTLOG_VAR);
new->status_line[0] = NULL;
new->status_line[1] = NULL;
new->w_status_size = 1;
new->display_size = 1;
new->old_size = 1;
new->visible = 1;
new->screen = current_screen;
new->notify_level = real_notify_level();
new->display_buffer_max = 1024;
new->hold_mode = get_int_var(HOLD_MODE_VAR);
new->current_channel = NULL;
if (add_to_window_list(new)) {
set_current_window(new);
resize_window_display(new);
} else
new_free(&new);
term_flush();
return (new);
}
/*
* delete_window: This deletes the given window. It frees all data and
* structures associated with the window, and it adjusts the other windows so
* they will display correctly on the screen.
*/
void delete_window(Window * window)
{
char buffer[BIG_BUFFER_SIZE + 1];
if (window == NULL)
window = curr_scr_win;
if (window->visible && (current_screen->visible_windows == 1)) {
if (invisible_list) {
swap_window(window, invisible_list);
window = invisible_list;
} else {
if (!get_int_var(WINDOW_QUIET_VAR))
say("You can't kill the last window!");
return;
}
}
if (window->name)
strmcpy(buffer, window->name, BIG_BUFFER_SIZE - 1);
else
sprintf(buffer, "%u", window->refnum);
if (current_screen->last_window_refnum == window->refnum)
current_screen->last_window_refnum = curr_scr_win->refnum;
new_free(&window->query_nick);
new_free(&window->query_host);
new_free(&window->query_cmd);
new_free(&window->current_channel);
new_free(&window->bind_channel);
new_free(&window->waiting_channel);
new_free(&window->logfile);
new_free(&window->name);
/*
* Free off the display
*/
{
Display *next;
while (window->top_of_scrollback) {
next = window->top_of_scrollback->next;
new_free(&window->top_of_scrollback->line);
new_free((char **) &window->top_of_scrollback);
window->display_buffer_size--;
window->top_of_scrollback = next;
}
window->display_ip = NULL;
if (window->display_buffer_size != 0)
ircpanic("Ack. fix this.");
}
/*
* Free off the lastlog
*/
while (window->lastlog_size)
remove_from_lastlog(window);
/*
* Free off the nick list
*/
{
struct nick_list *next;
while (window->nicks) {
next = window->nicks->next;
new_free(&window->nicks->nick);
new_free((char **) &window->nicks);
window->nicks = next;
}
}
if (window->visible)
remove_from_window_list(window);
else
remove_from_invisible_list(window);
/*
* status lines
*/
new_free(&window->status_line[0]);
new_free(&window->status_line[1]);
new_free((char **) &window);
window_check_servers();
do_hook(WINDOW_KILL_LIST, "%s", buffer);
}
/*
* traverse_all_windows: Based on the idea from phone that you should
* be able to do more than one iteration simultaneously.
*
* To initialize, *ptr should be NULL. The function will return 1 each time
* *ptr is set to the next valid window. When the function returns 0, then
* you have iterated all windows.
*/
int traverse_all_windows(Window ** ptr)
{
/*
* If this is the first time through...
*/
if (!*ptr) {
/*
* If there are no windows or screens, punt it.
*/
if (!screen_list || !screen_list->window_list)
return 0;
/*
* Start with the first window on first screen
*/
*ptr = screen_list->window_list;
}
/*
* As long as there is another window on this screen, keep going.
*/
else if ((*ptr)->next) {
*ptr = (*ptr)->next;
}
/*
* If there are no more windows on this screen, but we do belong to
* a screen (eg, we're not invisible), try the next screen
*/
else if ((*ptr)->screen) {
/*
* Skip any dead screens
*/
Screen *ns = (*ptr)->screen->next;
while (ns && !ns->alive)
ns = ns->next;
/*
* If there are no other screens, then if there is a list
* of hidden windows, try that. Otherwise we're done.
*/
if (!ns || !ns->window_list) {
if (invisible_list)
*ptr = invisible_list;
else
return 0;
}
/*
* There is another screen, move to it.
*/
else
*ptr = ns->window_list;
}
/*
* Otherwise there are no other windows, and we're not on a screen
* (eg, we're hidden), so we're all done here.
*/
else
return 0;
/*
* If we get here, we're in business!
*/
return 1;
}
static void remove_from_invisible_list(Window * window)
{
window->visible = 1;
window->screen = current_screen;
window->miscflags &= ~WINDOW_NOTIFIED;
if (window->prev)
window->prev->next = window->next;
else
invisible_list = window->next;
if (window->next)
window->next->prev = window->prev;
}
void add_to_invisible_list(Window * window)
{
if ((window->next = invisible_list) != NULL)
invisible_list->prev = window;
invisible_list = window;
window->prev = NULL;
window->visible = 0;
window->screen = NULL;
}
/*
* add_to_window_list: This inserts the given window into the visible window
* list (and thus adds it to the displayed windows on the screen). The
* window is added by splitting the current window. If the current window is
* too small, the next largest window is used. The added window is returned
* as the function value or null is returned if the window couldn't be added
*/
Window *add_to_window_list(Window * new)
{
Window *biggest = NULL, *tmp;
current_screen->visible_windows++;
if (curr_scr_win == NULL) {
current_screen->window_list_end = current_screen->window_list = new;
recalculate_windows();
} else {
int min = (2 * MIN_WINDOW_SIZE) + new->w_status_size;
/* split current window, or find a better window to split */
if ((curr_scr_win->display_size < min) || get_int_var(ALWAYS_SPLIT_BIGGEST_VAR)) {
int size = 0;
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
if (tmp->display_size > size) {
size = tmp->display_size;
biggest = tmp;
}
}
if ((biggest == NULL) || (size < min)) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("Not enough room for another window!");
current_screen->visible_windows--;
return NULL;
}
} else
biggest = curr_scr_win;
if ((new->prev = biggest->prev) != NULL)
new->prev->next = new;
else
current_screen->window_list = new;
new->next = biggest;
biggest->prev = new;
new->top = biggest->top;
new->bottom = (biggest->top + biggest->bottom) / 2;
biggest->top = new->bottom + new->w_status_size;
new->display_size = new->bottom - new->top;
biggest->display_size = biggest->bottom - biggest->top;
new->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
biggest->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
}
return new;
}
/*
* remove_from_window_list: this removes the given window from the list of
* visible windows. It closes up the hole created by the windows abnsense in
* a nice way
*/
void remove_from_window_list(Window * window)
{
Window *other;
/* find adjacent visible window to close up the screen */
for (other = window->next; other; other = other->next) {
if (other->visible) {
other->top = window->top;
break;
}
}
if (other == NULL) {
for (other = window->prev; other; other = other->prev) {
if (other->visible) {
other->bottom = window->bottom + window->w_status_size - other->w_status_size;
break;
}
}
}
/* remove window from window list */
if (window->prev)
window->prev->next = window->next;
else
current_screen->window_list = window->next;
if (window->next)
window->next->prev = window->prev;
else
current_screen->window_list_end = window->prev;
if (window->visible) {
current_screen->visible_windows--;
other->display_size = other->bottom - other->top;
if (window == curr_scr_win)
set_current_window(NULL);
if (window->refnum == current_screen->last_window_refnum)
current_screen->last_window_refnum = curr_scr_win->refnum;
}
}
/*
* recalculate_window_positions: This runs through the window list and
* re-adjusts the top and bottom fields of the windows according to their
* current positions in the window list. This doesn't change any sizes of
* the windows
*/
void recalculate_window_positions(void)
{
Window *tmp = current_screen->window_list;
int top;
top = 0;
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
tmp->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
tmp->top = top;
tmp->bottom = top + tmp->display_size;
top += tmp->display_size + tmp->w_status_size;
}
}
/*
* swap_window: This swaps the given window with the current window. The
* window passed must be invisible. Swapping retains the positions of both
* windows in their respective window lists, and retains the dimensions of
* the windows as well
*/
static void swap_window(Window * v_window, Window * window)
{
Window tmp, *prev, *next;
int top, bottom, size;
if (!window) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("The window to be swapped in does not exist.");
return;
}
if (window->visible || !v_window->visible) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("You can only SWAP a hidden window with a visible window.");
return;
}
prev = v_window->prev;
next = v_window->next;
current_screen->last_window_refnum = v_window->refnum;
current_screen->last_window_refnum = v_window->refnum;
remove_from_invisible_list(window);
tmp = *v_window;
*v_window = *window;
v_window->top = tmp.top;
if (v_window->top < 0)
v_window->top = 0;
v_window->bottom = tmp.bottom + tmp.w_status_size - v_window->w_status_size;
v_window->display_size = tmp.display_size + tmp.w_status_size - v_window->w_status_size;
v_window->prev = prev;
v_window->next = next;
top = window->top;
bottom = window->bottom;
size = window->display_size;
*window = tmp;
window->top = top;
window->bottom = bottom - tmp.w_status_size;
window->display_size = size;
add_to_invisible_list(window);
v_window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
recalculate_windows();
}
/*
* move_window: This moves a window offset positions in the window list. This
* means, of course, that the window will move on the screen as well
*/
void move_window(Window * window, int offset)
{
Window *tmp, *last;
int win_pos, pos;
if (offset == 0)
return;
last = NULL;
for (win_pos = 0, tmp = current_screen->window_list; tmp; tmp = tmp->next, win_pos++) {
if (window == tmp)
break;
last = tmp;
}
if (tmp == NULL)
return;
if (last == NULL)
current_screen->window_list = tmp->next;
else
last->next = tmp->next;
if (tmp->next)
tmp->next->prev = last;
else
current_screen->window_list_end = last;
if (offset < 0)
win_pos = (current_screen->visible_windows + offset + win_pos) % current_screen->visible_windows;
else
win_pos = (offset + win_pos) % current_screen->visible_windows;
last = NULL;
for (pos = 0, tmp = current_screen->window_list; pos != win_pos; tmp = tmp->next, pos++)
last = tmp;
if (last == NULL)
current_screen->window_list = window;
else
last->next = window;
if (tmp)
tmp->prev = window;
else
current_screen->window_list_end = window;
window->prev = last;
window->next = tmp;
recalculate_window_positions();
}
/*
* resize_window: if 'how' is RESIZE_REL, then this will increase or decrease
* the size of the given window by offset lines (positive offset increases,
* negative decreases). If 'how' is RESIZE_ABS, then this will set the
* absolute size of the given window.
* Obviously, with a fixed terminal size, this means that some other window
* is going to have to change size as well. Normally, this is the next
* window in the window list (the window below the one being changed) unless
* the window is the last in the window list, then the previous window is
* changed as well
*/
void resize_window(int how, Window * window, int offset)
{
Window *other;
int after, window_size, other_size;
if (window == NULL)
window = curr_scr_win;
if (!window->visible) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("You cannot change the size of hidden windows!");
return;
}
other = window;
after = 1;
do {
if (other->next)
other = other->next;
else {
other = current_screen->window_list;
after = 0;
}
if (other == window) {
say("Can't change the size of this window!");
return;
}
}
while (other->absolute_size);
if (how == RESIZE_REL) {
window_size = window->display_size + offset;
other_size = other->display_size - offset;
} else
/* absolute size */
{
/*
* How much its growing/shrinking by. if
* offset > display_size, then window_size < 0.
* and other window is shrinking. If offset < display_size,
* the window_size > 0, and other_window is growing.
*/
window_size = offset;
offset -= window->display_size;
other_size = other->display_size - offset;
}
if ((window_size < MIN_WINDOW_SIZE) || (other_size < MIN_WINDOW_SIZE)) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("Not enough room to resize this window!");
return;
}
if (after) {
window->bottom += offset;
other->top += offset;
} else {
window->top -= offset;
other->bottom -= offset;
}
window->display_size = window_size;
other->display_size = other_size;
window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
other->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
recalculate_window_positions();
term_flush();
}
/*
* resize_display: After determining that the screen has changed sizes, this
* resizes all the internal stuff. If the screen grew, this will add extra
* empty display entries to the end of the display list. If the screen
* shrank, this will remove entries from the end of the display list. By
* doing this, we try to maintain as much of the display as possible.
*
* This has now been improved so that it returns enough information for
* redraw_resized to redisplay the contents of the window without having
* to redraw too much.
*/
void resize_window_display(Window * window)
{
int cnt, i;
Display *tmp;
/*
* This is called in new_window to initialize the
* display the first time
*/
if (!window->top_of_scrollback) {
window->top_of_scrollback = new_display_line(NULL);
window->top_of_scrollback->line = NULL;
window->top_of_scrollback->next = NULL;
window->display_buffer_size = 1;
window->display_ip = window->top_of_scrollback;
window->top_of_display = window->top_of_scrollback;
window->old_size = 1;
}
/*
* Find out how much the window has changed by
*/
cnt = window->display_size - window->old_size;
tmp = window->top_of_display;
/*
* If it got bigger, move the top_of_display back.
*/
if (tmp == window->display_ip) ;
else if (cnt > 0) {
for (i = 0; i < cnt; i++) {
if (!tmp || !tmp->prev)
break;
tmp = tmp->prev;
}
}
/*
* If it got smaller, then move the top_of_display up
*/
else if (cnt < 0) {
/* Use any whitespace we may have lying around */
cnt += (window->old_size - window->distance_from_display);
for (i = 0; i > cnt; i--) {
if (tmp == window->display_ip)
break;
tmp = tmp->next;
}
}
window->top_of_display = tmp;
/*
* Look for where the cursor is. If we're in scrollback or the
* window got smaller, or we're just plain lost, then assume
* we're at the bottom of the screen or something.
*/
window->cursor = 0;
while (tmp != window->display_ip)
window->cursor++, tmp = tmp->next;
if (window->cursor > window->display_size)
window->cursor = window->display_size;
/*
* Mark the window for redraw and store the new window size.
*/
window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
window->old_size = window->display_size;
recalculate_window_cursor(window);
return;
}
/*
* redraw_all_windows: This basically clears and redraws the entire display
* portion of the screen. All windows and status lines are draws. This does
* nothing for the input line of the screen. Only visible windows are drawn
*/
void redraw_all_windows(void)
{
Window *tmp;
for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
tmp->update = REDRAW_STATUS | REDRAW_DISPLAY_FAST;
}
/*
* Rebalance_windows: this is called when you want all the windows to be
* rebalanced, except for those who have a set size.
*/
void rebalance_windows(void)
{
Window *tmp;
int each, extra;
int window_resized = 0, window_count = 0;
/*
* Two passes -- first figure out how much we need to balance,
* and how many windows there are to balance
*/
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
if (tmp->absolute_size)
continue;
window_resized += tmp->display_size;
window_count++;
}
each = window_resized / window_count;
extra = window_resized % window_count;
/*
* And then go through and fix everybody
*/
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
if (tmp->absolute_size) ;
else {
tmp->display_size = each;
if (extra)
tmp->display_size++, extra--;
}
}
recalculate_window_positions();
}
/*
* recalculate_windows: this is called when the terminal size changes (as
* when an xterm window size is changed). It recalculates the sized and
* positions of all the windows. Currently, all windows are rebalanced and
* window size proportionality is lost
*/
void recalculate_windows(void)
{
Window *tmp;
unsigned int num_windows;
unsigned int honor_abs_sizes;
int old_size;
int old_display;
int max_loss;
int excess_li;
int adj;
int pass;
if (term_rows < 2 * MIN_WINDOW_SIZE)
irc_exit("woops my window too small", 0);
/* If its a new window, just set it and be done with it. */
if (!curr_scr_win) {
tmp = current_screen->window_list;
tmp->top = 0;
tmp->display_size = term_rows - 1 - tmp->w_status_size;
tmp->bottom = tmp->display_size;
return;
}
restart:
num_windows = 0;
honor_abs_sizes = 0;
old_display = 0;
max_loss = 0;
/* First: Are there any non-absolute windows? */
for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
if ((honor_abs_sizes = !tmp->absolute_size))
break;
/* Second: Calculate (a) old size (b) max loss (c) num windows */
old_size = 1; /* cli */
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
num_windows++;
old_size += tmp->display_size + tmp->w_status_size;
if (honor_abs_sizes && tmp->absolute_size)
continue;
old_display += tmp->display_size;
max_loss += tmp->display_size - MIN_WINDOW_SIZE;
}
/* Third: If we don't have enough room for all the windows, hide some */
if ((term_rows < old_size) && ((old_size - term_rows) > max_loss)) {
if (num_windows > 1) {
hide_window(current_screen->window_list);
goto restart;
}
}
/* Fourth: Figure out how much each window needs to be resized */
excess_li = term_rows - old_size;
pass = 1;
do {
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
if (tmp->absolute_size && tmp->next)
continue;
if (pass && tmp->next)
adj = (tmp->display_size * excess_li) / old_display;
else
adj = excess_li;
if (adj < 0)
if ((tmp->display_size + adj) < MIN_WINDOW_SIZE)
adj = MIN_WINDOW_SIZE - tmp->display_size;
tmp->display_size += adj;
if (!(excess_li -= adj))
break;
}
} while (pass-- && excess_li);
if (excess_li)
irc_exit("couldn't figure out how to resize!", 0);
recalculate_window_positions();
}
/*
* update_all_windows: This goes through each visible window and draws the
* necessary portions according the the update field of the window.
*/
void update_all_windows()
{
Window *tmp;
int fast_window, full_window, r_status, u_status;
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
if (tmp->display_size != tmp->old_size)
resize_window_display(tmp);
if (tmp->update) {
fast_window = tmp->update & REDRAW_DISPLAY_FAST;
full_window = tmp->update & REDRAW_DISPLAY_FULL;
r_status = tmp->update & REDRAW_STATUS;
u_status = tmp->update & UPDATE_STATUS;
if (full_window || fast_window)
repaint_window(tmp, 0, -1);
if (r_status)
update_window_status(tmp, 1);
else if (u_status)
update_window_status(tmp, 0);
}
tmp->update = 0;
}
for (tmp = invisible_list; tmp; tmp = tmp->next) {
if (tmp->display_size != tmp->old_size)
resize_window_display(tmp);
tmp->update = 0;
}
update_input(UPDATE_JUST_CURSOR);
term_flush();
}
/*
* set_current_window: This sets the "current" window to window. It also
* keeps track of the last_current_screen->current_window by setting it to the
* previous current window. This assures you that the new current window is
* visible.
* If not, a new current window is chosen from the window list
*/
void set_current_window(Window * window)
{
Window *tmp;
unsigned int refnum;
refnum = current_screen->last_window_refnum;
if (curr_scr_win) {
curr_scr_win->update |= UPDATE_STATUS;
current_screen->last_window_refnum = curr_scr_win->refnum;
}
if ((window == NULL) || (!window->visible)) {
if ((tmp = get_window_by_refnum(refnum)) && (tmp->visible))
curr_scr_win = tmp;
else
curr_scr_win = get_next_window();
} else
curr_scr_win = window;
curr_scr_win->update |= UPDATE_STATUS;
set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0);
update_input(UPDATE_ALL);
}
/*
* goto_window: This will switch the current window to the window numbered
* "which", where which is 0 through the number of visible windows on the
* screen. The which has nothing to do with the windows refnum.
*/
static void goto_window(int which)
{
Window *tmp;
int i;
if (which == 0)
return;
if ((which < 0) || (which > current_screen->visible_windows)) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("GOTO: Illegal value");
return;
}
tmp = current_screen->window_list;
for (i = 1; tmp && (i != which); tmp = tmp->next, i++) ;
set_current_window(tmp);
}
/*
* hide_window: sets the given window to invisible and recalculates remaing
* windows to fill the entire screen
*/
void hide_window(Window * window)
{
if (current_screen->visible_windows == 1) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("You can't hide the last window.");
return;
}
if (window->visible) {
remove_from_window_list(window);
add_to_invisible_list(window);
/* window->display_size = LI - 2 - window->double_status; */
window->top = 0;
window->bottom = window->display_size;
set_current_window(NULL);
}
}
/*
* swap_last_window: This swaps the current window with the last window
* that was hidden.
*/
void swap_last_window(char key, char *ptr)
{
if (invisible_list == NULL) {
/* say("There are no hidden windows"); */
/* Not sure if we need to warn - phone. */
return;
}
swap_window(curr_scr_win, invisible_list);
message_from(NULL, LOG_CRAP);
update_all_windows();
cursor_to_input();
}
/*
* swap_next_window: This swaps the current window with the next hidden
* window.
*/
void swap_next_window(char key, char *ptr)
{
Window *tmp = NULL;
Window *next = NULL;
Window *smallest = NULL;
if (invisible_list == NULL) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("There are no hidden windows");
return;
}
smallest = curr_scr_win;
while (traverse_all_windows(&tmp)) {
if (!tmp->visible) {
if (tmp->refnum < smallest->refnum)
smallest = tmp;
if ((tmp->refnum > curr_scr_win->refnum)
&& (!next || tmp->refnum < next->refnum))
next = tmp;
}
}
if (!next)
next = smallest;
swap_window(curr_scr_win, next);
message_from(NULL, LOG_CRAP);
update_all_windows();
update_all_status(curr_scr_win, NULL, 0);
cursor_to_input();
}
/*
* swap_previous_window: This swaps the current window with the next
* hidden window.
*/
void swap_previous_window(char key, char *ptr)
{
Window *tmp;
int previous = 0;
int largest;
if (invisible_list == NULL) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("There are no hidden windows");
return;
}
tmp = NULL;
largest = curr_scr_win->refnum;
while (traverse_all_windows(&tmp)) {
if (!tmp->visible) {
if (tmp->refnum > largest)
largest = tmp->refnum;
if ((tmp->refnum < curr_scr_win->refnum)
&& (previous < tmp->refnum))
previous = tmp->refnum;
}
}
if (previous)
tmp = get_window_by_refnum(previous);
else
tmp = get_window_by_refnum(largest);
swap_window(curr_scr_win, tmp);
message_from(NULL, LOG_CRAP);
update_all_windows();
update_all_status(curr_scr_win, NULL, 0);
cursor_to_input();
}
/* show_window: This makes the given window visible. */
int show_window(Window * window)
{
if (window->visible) {
set_current_window(window);
return 0;
}
remove_from_invisible_list(window);
if (add_to_window_list(window)) {
set_current_window(window);
return 0;
} else {
add_to_invisible_list(window);
}
return 1;
}
/*
* get_window_by_refnum: Given a reference number to a window, this returns a
* pointer to that window if a window exists with that refnum, null is
* returned otherwise. The "safe" way to reference a window is throught the
* refnum, since a window might be delete behind your back and and Window
* pointers might become invalid.
*/
Window *get_window_by_refnum(unsigned int refnum)
{
Window *tmp = NULL;
if (refnum) {
while (traverse_all_windows(&tmp)) {
if (tmp->refnum == refnum)
return tmp;
}
} else
return curr_scr_win;
return NULL;
}
/*
* get_window: this parses out any window (visible or not) and returns a
* pointer to it
*/
int get_visible_by_refnum(char *args)
{
char *arg;
Window *tmp;
if ((arg = next_arg(args, &args)) != NULL) {
if (is_number(arg)) {
if ((tmp = get_window_by_refnum(my_atol(arg))) != NULL)
return tmp->visible;
}
if ((tmp = get_window_by_name(arg)) != NULL)
return tmp->visible;
return -1;
}
return -1;
}
/*
* get_window_by_name: returns a pointer to a window with a matching logical
* name or null if no window matches
*/
Window *get_window_by_name(char *name)
{
Window *tmp = NULL;
while (traverse_all_windows(&tmp)) {
if (tmp->name && (my_stricmp(tmp->name, name) == 0))
return tmp;
}
return NULL;
}
/*
* get_next_window: This returns a pointer to the next *visible* window in
* the window list. It automatically wraps at the end of the list back to
* the beginning of the list
*/
static Window *get_next_window(void)
{
Window *last = curr_scr_win;
Window *new = curr_scr_win;
do {
if (new->next)
new = new->next;
else
new = current_screen->window_list;
}
while (new->skip && new != last);
return new;
}
/*
* get_previous_window: this returns the previous *visible* window in the
* window list. This automatically wraps to the last window in the window
* list
*/
static Window *get_previous_window(void)
{
Window *last = curr_scr_win;
Window *new = curr_scr_win;
do {
if (new->prev)
new = new->prev;
else
new = current_screen->window_list_end;
}
while (new->skip && new != last);
return new;
}
/*
* next_window: This switches the current window to the next visible window
*/
void next_window(char key, char *ptr)
{
if (current_screen->visible_windows == 1)
return;
set_current_window(get_next_window());
update_all_windows();
set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0);
}
/*
* previous_window: This switches the current window to the previous visible
* window
*/
void previous_window(char key, char *ptr)
{
if (current_screen->visible_windows == 1)
return;
set_current_window(get_previous_window());
update_all_windows();
set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0);
}
/*
* update_window_status: This updates the status line for the given window.
* If the refresh flag is true, the entire status line is redrawn. If not,
* only some of the changed portions are redrawn
*/
void update_window_status(Window * window, int refresh)
{
if ((!window->visible) || !status_update_flag || never_connected)
return;
if (window == NULL)
window = curr_scr_win;
if (refresh) {
new_free(&(window->status_line[0]));
new_free(&(window->status_line[1]));
}
make_status(window);
}
/*
* update_all_status: This updates all of the status lines for all of the
* windows. By updating, it only draws from changed portions of the status
* line to the right edge of the screen
*/
void update_all_status(Window * win, char *unused, int unused1)
{
Window *window;
Screen *screen;
if (!status_update_flag || never_connected)
return;
for (screen = screen_list; screen; screen = screen->next) {
if (!screen->alive)
continue;
for (window = screen->window_list; window; window = window->next)
if (window->visible)
make_status(window);
}
update_input(UPDATE_JUST_CURSOR);
term_flush();
}
/*
* status_update: sets the status_update_flag to whatever flag is. This also
* calls update_all_status(), which will update the status line if the flag
* was true, otherwise it's just ignored
*/
void status_update(int flag)
{
status_update_flag = flag;
update_all_status(curr_scr_win, NULL, 0);
cursor_to_input();
}
/*
* set_prompt_by_refnum: changes the prompt for the given window. A window
* prompt will be used as the target in place of the query user or current
* channel if it is set
*/
void set_prompt_by_refnum(unsigned int refnum, char *prompt)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
malloc_strcpy(&(tmp->prompt), prompt);
}
/* get_prompt_by_refnum: returns the prompt for the given window refnum */
char *get_prompt_by_refnum(unsigned int refnum)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
if (tmp->prompt)
return (tmp->prompt);
else
return (empty_str);
}
/* query_nick: Returns the query nick for the current channel */
char *query_nick(void)
{
return (curr_scr_win->query_nick);
}
/*
* get_target_by_refnum: returns the target for the window with the given
* refnum (or for the current window). The target is either the query nick
* or current channel for the window
*/
char *get_target_by_refnum(unsigned int refnum)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
if (tmp->query_nick)
return (tmp->query_nick);
else if (tmp->current_channel)
return (tmp->current_channel);
else
return (NULL);
}
char *get_target_cmd_by_refnum(unsigned int refnum)
{
Window *tmp;
if (!(tmp = get_window_by_refnum(refnum)))
tmp = curr_scr_win;
if (tmp->query_cmd)
return (tmp->query_cmd);
return NULL;
}
/* set_query_nick: sets the query nick for the current channel to nick */
void set_query_nick(char *nick, char *host, char *cmd)
{
char *ptr;
struct nick_list *tmp;
if (!nick && !host && cmd) {
curr_scr_win->query_cmd = m_strdup(cmd);
return;
}
if (curr_scr_win->query_nick) {
char *lnik = curr_scr_win->query_nick;
/* next_in_comma_list() */
while (lnik) {
if (!curr_scr_win->nicks)
continue;
if ((ptr = (char *) strchr(lnik, ',')) != NULL)
*(ptr++) = 0;
if ((tmp = (struct nick_list *) remove_from_list((struct list **) &(curr_scr_win->nicks), lnik)) != NULL) {
new_free(&tmp->nick);
new_free(&tmp->host); /* CDE why was this not done */
new_free((char **) &tmp);
}
lnik = ptr;
}
new_free(&curr_scr_win->query_nick);
new_free(&curr_scr_win->query_host);
new_free(&curr_scr_win->query_cmd);
}
if (nick) {
malloc_strcpy(&(curr_scr_win->query_nick), nick);
malloc_strcpy(&(curr_scr_win->query_host), host);
if (cmd)
malloc_strcpy(&(curr_scr_win->query_cmd), cmd);
curr_scr_win->update |= UPDATE_STATUS;
while (nick) {
if ((ptr = (char *) strchr(nick, ',')) != NULL)
*(ptr++) = 0;
tmp = (struct nick_list *) new_malloc(sizeof(struct nick_list));
tmp->nick = NULL;
malloc_strcpy(&tmp->nick, nick);
malloc_strcpy(&tmp->host, host);
add_to_list((struct list **) &(curr_scr_win->nicks), (struct list *) tmp);
nick = ptr;
}
}
update_window_status(curr_scr_win, 0);
}
/*
* is_current_channel: Returns true is channel is a current channel for any
* window. If the delete flag is not 0, then unset channel as the current
* channel and attempt to replace it by a non-current channel or the
* current_channel of window specified by value of delete
*/
int is_current_channel(char *channel, int server, int delete)
{
Window *tmp = NULL;
int found = 0;
while (traverse_all_windows(&tmp)) {
if (tmp->current_channel && !my_stricmp(channel, tmp->current_channel) && (tmp->server == from_server)) {
found = 1;
if (delete) {
new_free(&(tmp->current_channel));
tmp->update |= UPDATE_STATUS;
}
}
}
return found;
}
/*
* set_current_channel_by_refnum: This sets the current channel for the current
* window. It returns the current channel as it's value. If channel is null,
* the * current channel is not changed, but simply reported by the function
* result. This treats as a special case setting the current channel to
* channel "0". This frees the current_channel for the
* current_screen->current_window, * setting it to null
*/
char *set_current_channel_by_refnum(unsigned int refnum, char *channel)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
if (channel)
if (strcmp(channel, zero_str) == 0)
channel = NULL;
malloc_strcpy(&tmp->current_channel, channel);
new_free(&tmp->waiting_channel);
tmp->update |= UPDATE_STATUS;
set_channel_window(tmp, channel, tmp->server);
return (channel);
}
/* get_current_channel_by_refnum: returns the current channel for window refnum */
char *get_current_channel_by_refnum(unsigned int refnum)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
return (tmp->current_channel);
}
char *get_refnum_by_window(const Window * w)
{
return ltoa(w->refnum);
}
int is_bound_to_window(const Window * window, const char *channel)
{
return (window->bind_channel ? !my_stricmp(window->bind_channel, channel) : 0);
}
Window *get_window_bound_channel(const char *channel)
{
Window *tmp = NULL;
while (traverse_all_windows(&tmp))
if (tmp->bind_channel && !my_stricmp(tmp->bind_channel, channel))
return tmp;
return NULL;
}
int is_bound_anywhere(const char *channel)
{
Window *tmp = NULL;
while (traverse_all_windows(&tmp))
if (tmp->bind_channel && !my_stricmp(tmp->bind_channel, channel))
return 1;
return 0;
}
int is_bound(const char *channel, int server)
{
Window *tmp = NULL;
while (traverse_all_windows(&tmp))
if (tmp->server == server && tmp->bind_channel && !my_stricmp(tmp->bind_channel, channel))
return 1;
return 0;
}
void unbind_channel(const char *channel, int server)
{
Window *tmp = NULL;
while (traverse_all_windows(&tmp))
if (tmp->server == server && tmp->bind_channel && !my_stricmp(tmp->bind_channel, channel)) {
new_free(&tmp->bind_channel);
/* ARGH! COREDUMPS! */
tmp->bind_channel = NULL;
return;
}
}
char *get_bound_channel(Window * window)
{
Window *tmp = NULL;
while (traverse_all_windows(&tmp))
if (tmp == window)
return tmp->bind_channel;
return empty_str;
}
/*
* get_window_server: returns the server index for the window with the given
* refnum
*/
int get_window_server(unsigned int refnum)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
return (tmp->server);
}
/*
* set_window_server: This sets the server of the given window to server.
* If refnum is -1 then we are setting the primary server and all windows
* that are set to the current primary server are changed to server. The misc
* flag is ignored in this case. If refnum is not -1, then that window is
* set to the given server. If the misc flag is set as well, then all windows
* with the same server as renum are set to the new server as well
* if refnum == -2, then, we are setting the server group passed in the misc
* variable to the server.
*/
void set_window_server(int refnum, int server, int misc)
{
Window *tmp, *window;
int old;
if (refnum == -1) {
tmp = NULL;
while (traverse_all_windows(&tmp)) {
if (tmp->server == primary_server)
tmp->server = server;
}
window_check_servers();
primary_server = server;
} else {
if ((window = get_window_by_refnum(refnum)) == NULL)
window = curr_scr_win;
old = window->server;
if (misc) {
tmp = NULL;
while (traverse_all_windows(&tmp)) {
if (tmp->server == old)
tmp->server = server;
}
} else
window->server = server;
window_check_servers();
}
}
/*
* window_check_servers: this checks the validity of the open servers vs the
* current window list. Every open server must have at least one window
* associated with it. If a window is associated with a server that's no
* longer open, that window's server is set to the primary server. If an
* open server has no assicatiate windows, that server is closed. If the
* primary server is no more, a new primary server is picked from the open
* servers
*/
void window_check_servers(void)
{
Window *tmp;
int cnt, max, i, not_connected, prime = -1;
connected_to_server = 0;
max = number_of_servers;
for (i = 0; i < max; i++) {
not_connected = !is_server_open(i);
cnt = 0;
tmp = NULL;
while (traverse_all_windows(&tmp)) {
if (tmp->server == i) {
if (not_connected)
tmp->server = primary_server;
else {
prime = tmp->server;
cnt++;
}
}
}
if (cnt == 0) {
close_server(i, empty_str);
/* add_timer("", 10, timed_server, m_sprintf("%d", i), NULL); */
} else
connected_to_server++;
}
if (!is_server_open(primary_server)) {
tmp = NULL;
while (traverse_all_windows(&tmp))
if (tmp->server == primary_server)
tmp->server = prime;
primary_server = prime;
}
update_all_status(curr_scr_win, NULL, 0);
cursor_to_input();
}
/*
* set_level_by_refnum: This sets the window level given a refnum. It
* revamps the windows levels as well using revamp_window_levels()
*/
void set_level_by_refnum(unsigned int refnum, int level)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
tmp->window_level = level;
revamp_window_levels(tmp);
}
/*
* revamp_window_levels: Given a level setting for the current window, this
* makes sure that that level setting is unused by any other window. Thus
* only one window in the system can be set to a given level. This only
* revamps levels for windows with servers matching the given window
* it also makes sure that only one window has the level `DCC', as this is
* not dependant on a server.
*/
void revamp_window_levels(Window * window)
{
Window *tmp;
int got_dcc;
got_dcc = (LOG_DCC & window->window_level) ? 1 : 0;
tmp = NULL;
while (traverse_all_windows(&tmp)) {
if (tmp == window)
continue;
if (LOG_DCC & tmp->window_level) {
if (0 != got_dcc)
tmp->window_level &= ~LOG_DCC;
got_dcc = 1;
}
if (window->server == tmp->server)
tmp->window_level ^= (tmp->window_level & window->window_level);
}
}
/*
* message_to: This allows you to specify a window (by refnum) as a
* destination for messages. Used by EXEC routines quite nicely
*/
void message_to(unsigned int refnum)
{
to_window = (refnum) ? get_window_by_refnum(refnum) : NULL;
}
/*
* save_message_from: this is used to save (for later restoration) the
* who_from variable. This comes in handy very often when a routine might
* call another routine that might change who_from.
*/
void save_message_from(char **saved_who_from, int *saved_who_level)
{
*saved_who_from = who_from;
*saved_who_level = who_level;
}
/* restore_message_from: restores a previously saved who_from variable */
void restore_message_from(char *saved_who_from, int saved_who_level)
{
who_from = saved_who_from;
who_level = saved_who_level;
}
/*
* message_from: With this you can the who_from variable and the who_level
* variable, used by the display routines to decide which window messages
* should go to.
*/
void message_from(char *who, int level)
{
#if 0
malloc_strcpy(&who_from, who);
#endif
who_from = who;
who_level = level;
}
/*
* message_from_level: Like set_lastlog_msg_level, except for message_from.
* this is needed by XECHO, because we could want to output things in more
* than one level.
*/
int message_from_level(int level)
{
int temp;
temp = who_level;
who_level = level;
return temp;
}
/*
* clear_window: This clears the display list for the given window, or
* current window if null is given.
*/
void clear_window(Window * window)
{
if (window == NULL)
window = curr_scr_win;
if (window->lines_held || window->scrollback_point)
return;
window->top_of_display = window->display_ip;
window->cursor = 0;
window->held_displayed = 0;
repaint_window(window, 0, -1);
update_window_status(window, 1);
}
/* clear_all_windows: This clears all *visible* windows */
void clear_all_windows(int unhold)
{
Window *tmp;
for (tmp = current_screen->window_list; tmp; tmp = tmp->next) {
if (unhold)
hold_mode(tmp, OFF, 1);
clear_window(tmp);
}
}
/*
* clear_window_by_refnum: just like clear_window(), but it uses a refnum. If
* the refnum is invalid, the current window is cleared.
*/
void clear_window_by_refnum(unsigned int refnum)
{
Window *tmp;
if ((tmp = get_window_by_refnum(refnum)) == NULL)
tmp = curr_scr_win;
clear_window(tmp);
}
/*
* set_scroll_lines: called by /SET SCROLL_LINES to check the scroll lines
* value
*/
void set_scroll_lines(Window * win, char *unused, int size)
{
if (size == 0) {
set_int_var(SCROLL_VAR, 0);
if (curr_scr_win)
curr_scr_win->scroll = 0;
} else if (size > curr_scr_win->display_size) {
say("Maximum lines that may be scrolled is %d", curr_scr_win->display_size);
set_int_var(SCROLL_LINES_VAR, curr_scr_win->display_size);
}
}
/*
* set_scroll: called by /SET SCROLL to make sure the SCROLL_LINES variable
* is set correctly
*/
void set_scroll(Window * win, char *unused, int value)
{
int old_value;
if (value && (get_int_var(SCROLL_LINES_VAR) == 0)) {
put_it("You must set SCROLL_LINES to a positive value first!");
if (curr_scr_win)
curr_scr_win->scroll = 0;
} else {
if (curr_scr_win) {
old_value = curr_scr_win->scroll;
curr_scr_win->scroll = value;
if (old_value && !value)
scroll_window(curr_scr_win);
}
}
}
/*
* set_continued_lines: checks the value of CONTINUED_LINE for validity,
* altering it if its no good
*/
void set_continued_lines(Window * win, char *value, int unused)
{
if (value && ((int) strlen(value) > (term_cols / 2)))
value[term_cols / 2] = '\0';
}
/* current_refnum: returns the reference number for the current window */
unsigned int current_refnum(void)
{
return (curr_scr_win->refnum);
}
int number_of_windows(void)
{
return (current_screen->visible_windows);
}
/*
* is_window_name_unique: checks the given name vs the names of all the
* windows and returns true if the given name is unique, false otherwise
*/
int is_window_name_unique(char *name)
{
Window *tmp = NULL;
if (name) {
while (traverse_all_windows(&tmp)) {
if (tmp->name && (my_stricmp(tmp->name, name) == 0))
return (0);
}
}
return (1);
}
#define WIN_FORM "%-4s %*.*s %*.*s %*.*s %-9.9s %-10.10s %s%s"
static void list_a_window(Window * window, int len)
{
int cnw = get_int_var(CHANNEL_NAME_WIDTH_VAR);
say(WIN_FORM, ltoa(window->refnum),
12, 12, get_server_nickname(window->server),
len, len, window->name ? window->name : "<None>",
cnw, cnw, window->current_channel ? window->current_channel : "<None>",
window->query_nick ? window->query_nick : "<None>",
get_server_itsname(window->server), bits_to_lastlog_level(window->window_level), window->visible ? empty_str : " Hidden");
}
/* below is stuff used for parsing of WINDOW command */
/*
* get_window: this parses out any window (visible or not) and returns a
* pointer to it
*/
static Window *get_window(char *name, char **args)
{
char *arg;
Window *tmp;
if ((arg = next_arg(*args, args)) != NULL) {
if (is_number(arg)) {
if ((tmp = get_window_by_refnum(my_atol(arg))) != NULL)
return (tmp);
}
if ((tmp = get_window_by_name(arg)) != NULL)
return (tmp);
if (!get_int_var(WINDOW_QUIET_VAR))
say("%s: No such window: %s", name, arg);
} else
say("%s: Please specify a window refnum or name", name);
return (NULL);
}
/*
* get_invisible_window: parses out an invisible window by reference number.
* Returns the pointer to the window, or null. The args can also be "LAST"
* indicating the top of the invisible window list (and thus the last window
* made invisible)
*/
static Window *get_invisible_window(char *name, char **args)
{
char *arg;
Window *tmp;
if ((arg = next_arg(*args, args)) != NULL) {
if (my_strnicmp(arg, "LAST", strlen(arg)) == 0) {
if (invisible_list == NULL) {
if (!get_int_var(WINDOW_QUIET_VAR))
say("%s: There are no hidden windows", name);
}
return (invisible_list);
}
if ((tmp = get_window(name, &arg)) != NULL) {
if (!tmp->visible)
return (tmp);
else if (!get_int_var(WINDOW_QUIET_VAR)) {
if (tmp->name)
say("%s: Window %s is not hidden!", name, tmp->name);
else
say("%s: Window %d is not hidden!", name, tmp->refnum);
}
}
} else
say("%s: Please specify a window refnum or LAST", name);
return (NULL);
}
/* get_number: parses out an integer number and returns it */
static int get_number(char *name, char **args, char *msg)
{
char *arg;
if ((arg = next_arg(*args, args)) != NULL)
return (my_atol(arg));
else {
if (msg)
say("%s: %s", name, msg);
else
say("%s: You must specify the number of lines", name);
}
return (0);
}
/*
* get_boolean: parses either ON, OFF, or TOGGLE and sets the var
* accordingly. Returns 0 if all went well, -1 if a bogus or missing value
* was specified
*/
static int get_boolean(char *name, char **args, int *var)
{
char *arg;
if (((arg = next_arg(*args, args)) == NULL) || do_boolean(arg, var)) {
say("Value for %s must be ON, OFF, or TOGGLE", name);
return (-1);
} else {
say("Window %s is %s", name, var_settings[*var]);
return (0);
}
}
/*
* /WINDOW ADD nick<,nick>
* Adds a list of one or more nicknames to the current list of usupred
* targets for the current window. These are matched up with the nick
* argument for message_from().
*/
static Window *window_add(Window * window, char **args, char *usage)
{
char *ptr;
struct nick_list *new;
char *arg = next_arg(*args, args);
if (!arg)
say("ADD: Add nicknames to be redirected to this window");
else
while (arg) {
if ((ptr = strchr(arg, ',')))
*ptr++ = 0;
if (!find_in_list((struct list **) &window->nicks, arg, !USE_WILDCARDS)) {
say("Added %s to window name list", arg);
new = (struct nick_list *) new_malloc(sizeof(struct nick_list));
new->nick = m_strdup(arg);
add_to_list((struct list **) &(window->nicks), (struct list *) new);
} else
say("%s already on window name list", arg);
arg = ptr;
}
return window;
}
/*
* /WINDOW BACK
* Changes the current window pointer to the window that was most previously
* the current window. If that window is now hidden, then it is swapped with
* the current window.
*/
static Window *window_back(Window * window, char **args, char *usage)
{
Window *tmp;
tmp = get_window_by_refnum(current_screen->last_window_refnum);
if (tmp->visible)
set_current_window(tmp);
else {
swap_window(curr_scr_win, tmp);
message_from(NULL, LOG_CRAP);
update_all_windows();
update_all_status(curr_scr_win, NULL, 0);
cursor_to_input();
}
return window;
}
/*
* /WINDOW BALANCE
* Causes all of the windows on the current screen to be adjusted so that
* the largest window on the screen is no more than one line larger than
* the smallest window on the screen.
*/
static Window *window_balance(Window * window, char **args, char *usage)
{
rebalance_windows();
return window;
}
/*
* /WINDOW BEEP_ALWAYS ON|OFF
* Indicates that when this window is HIDDEN (sorry, thats not what it seems
* like it should do, but that is what it does), beeps to this window should
* not be suppressed like they normally are for hidden windows. The beep
* occurs EVEN IF /set beep is OFF.
*/
static Window *window_beep_always(Window * window, char **args, char *usage)
{
if (get_boolean("BEEP_ALWAYS", args, &window->beep_always))
return NULL;
return window;
}
/*
* /WINDOW BIND <#channel>
* Indicates that the window should be "bound" to the specified channel.
* "binding" a channel to a window means that the channel will always
* belong to this window, no matter what. For example, if a channel is
* bound to a window, you can do a /join #channel in any window, and it
* will always "join" in this window. This is especially useful when
* you are disconnected from a server, because when you reconnect, the client
* often loses track of which channel went to which window. Binding your
* channels gives the client a hint where channels belong.
*
* You can rebind a channel to a new window, even after it has already
* been bound elsewhere.
*/
static Window *window_bind(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args))) {
if (!is_channel(arg))
say("BIND: %s is not a valid channel name", arg);
else {
if (is_bound(arg, from_server) && is_current_channel(arg, from_server, 1))
unbind_channel(arg, from_server);
malloc_strcpy(&window->bind_channel, arg);
if (is_on_channel(arg, from_server, get_server_nickname(window->server)))
set_current_channel_by_refnum(0, arg);
say("Window is bound to channel %s", arg);
}
} else if ((arg = get_bound_channel(window)))
say("Window is bound to channel %s", arg);
else
say("Window is not bound to any channel");
return window;
}
/*
* /WINDOW CHANNEL <#channel>
* Directs the client to make a specified channel the current channel for
* the window -- it will JOIN the channel if you are not already on it.
* If the channel you wish to activate is bound to a different window, you
* will be notified. If you are already on the channel in another window,
* then the channel's window will be switched. If you do not specify a
* channel, or if you specify the channel "0", then the window will drop its
* connection to whatever channel it is in.
*/
static Window *window_channel(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args))) {
if (is_bound(arg, from_server))
say("Channel %s is already bound elsewhere", arg);
else if (is_current_channel(arg, from_server, 1) || is_on_channel(arg, from_server, get_server_nickname(window->server))) {
say("You are now talking to channel %s", arg);
set_current_channel_by_refnum(0, arg);
} else if (arg[0] == '0' && arg[1] == 0)
set_current_channel_by_refnum(0, NULL);
else {
int server = from_server;
from_server = window->server;
send_to_server(SERVER(from_server), "JOIN %s", arg);
malloc_strcpy(&window->waiting_channel, arg);
from_server = server;
}
} else
set_current_channel_by_refnum(0, zero_str);
return window;
}
/*
* /WINDOW DESCRIBE
* Directs the client to tell you a bit about the current window.
* This is the 'default' argument to the /window command.
*/
static Window *window_describe(Window * window, char **args, char *usage)
{
if (window->name)
say("Window %s (%u)", window->name, window->refnum);
else
say("Window %u", window->refnum);
say("\tServer: %s", window->server == -1 ? get_server_name(window->server) : "<None>");
say("\tGeometry Info: [%d %d %d %d %d %d]",
window->top, window->bottom, window->held_displayed, window->display_size, window->cursor, window->distance_from_display);
say("\tCO, LI are [%d %d]", term_cols, term_rows);
say("\tCurrent channel: %s", window->current_channel ? window->current_channel : "<None>");
if (window->waiting_channel)
say("\tWaiting channel: %s", window->waiting_channel);
if (window->bind_channel)
say("\tBound channel: %s", window->bind_channel);
say("\tQuery User: %s", window->query_nick ? window->query_nick : "<None>");
say("\tPrompt: %s", window->prompt ? window->prompt : "<None>");
say("\tNumber of status lines: %d", window->w_status_size);
say("\tScrolling is %s", var_settings[window->scroll]);
say("\tLogging is %s", var_settings[window->log]);
if (window->logfile)
say("\tLogfile is %s", window->logfile);
else
say("\tNo logfile given");
say("\tNotification is %s", var_settings[window->miscflags & WINDOW_NOTIFY]);
say("\tHold mode is %s", var_settings[window->hold_mode]);
say("\tWindow level is %s", bits_to_lastlog_level(window->window_level));
say("\tLastlog level is %s", bits_to_lastlog_level(window->lastlog_level));
say("\tNotify level is %s", bits_to_lastlog_level(window->notify_level));
if (window->nicks) {
struct nick_list *tmp;
say("\tName list:");
for (tmp = window->nicks; tmp; tmp = tmp->next)
say("\t %s", tmp->nick);
}
return window;
}
/*
* /WINDOW FIXED (ON|OFF)
*
* When this is ON, then this window will never be used as the implicit
* partner for a window resize. That is to say, if you /window grow another
* window, this window will not be considered for the corresponding shrink.
* You may /window grow a fixed window, but if you do not have other nonfixed
* windows, the grow will fail.
*/
static Window *window_fixed(Window * window, char **args, char *usage)
{
if (get_boolean("FIXED", args, &window->absolute_size))
return NULL;
return window;
}
/*
* /WINDOW GOTO refnum
* This switches the current window selection to the window as specified
* by the numbered refnum.
*/
static Window *window_goto(Window * window, char **args, char *usage)
{
goto_window(get_number("GOTO", args, NULL));
from_server = get_window_server(0);
return curr_scr_win;
}
/*
* /WINDOW GROW lines
* This directs the client to expand the specified window by the specified
* number of lines. The number of lines should be a positive integer, and
* the window's growth must not cause another window to be smaller than
* the minimum of 3 lines.
*/
static Window *window_grow(Window * window, char **args, char *usage)
{
resize_window(RESIZE_REL, window, get_number("GROW", args, NULL));
return window;
}
/*
* /WINDOW HIDE
* This directs the client to remove the specified window from the current
* (visible) screen and place the window on the client's invisible list.
* A hidden window has no "screen", and so can not be seen, and does not
* have a size. It can be unhidden onto any screen.
*/
static Window *window_hide(Window * window, char **args, char *usage)
{
hide_window(window);
return curr_scr_win;
}
/*
* /WINDOW HIDE_OTHERS
* This directs the client to place *all* windows on the current screen,
* except for the current window, onto the invisible list.
*/
static Window *window_hide_others(Window * window, char **args, char *usage)
{
Window *tmp, *cur, *next;
cur = curr_scr_win;
tmp = current_screen->window_list;
while (tmp) {
next = tmp->next;
if (tmp != cur)
hide_window(tmp);
tmp = next;
}
return curr_scr_win;
}
/*
* /WINDOW HOLD_MODE
* This arranges for the window to "hold" any output bound for it once
* a full page of output has been completed. Setting the global value of
* HOLD_MODE is truly bogus and should be changed. XXXX
*/
static Window *window_hold_mode(Window * window, char **args, char *usage)
{
if (get_boolean("HOLD_MODE", args, &window->hold_mode))
return NULL;
set_int_var(HOLD_MODE_VAR, window->hold_mode);
return window;
}
/*
* /WINDOW KILL
* This arranges for the current window to be destroyed. Once a window
* is killed, it cannot be recovered. Because every server must have at
* least one window "connected" to it, if you kill the last window for a
* server, the client will drop your connection to that server automatically.
*/
static Window *window_kill(Window * window, char **args, char *usage)
{
delete_window(window);
return curr_scr_win;
}
/*
* /WINDOW KILL_OTHERS
* This arranges for all windows on the current screen, other than the
* current window to be destroyed. Obviously, the current window will be
* the only window left on the screen. Connections to servers other than
* the server for the current window will be implicitly closed.
*/
static Window *window_kill_others(Window * window, char **args, char *usage)
{
Window *tmp, *cur, *next;
cur = curr_scr_win;
tmp = current_screen->window_list;
while (tmp) {
next = tmp->next;
if (tmp != cur)
delete_window(tmp);
tmp = next;
}
return curr_scr_win;
}
/*
* /WINDOW KILLSWAP
* This arranges for the current window to be replaced by the last window
* to be hidden, and also destroys the current window.
*/
static Window *window_killswap(Window * window, char **args, char *usage)
{
if (invisible_list) {
swap_last_window(0, NULL);
delete_window(get_window_by_refnum(current_screen->last_window_refnum));
} else
say("There are no hidden windows!");
return curr_scr_win;
}
/*
* /WINDOW LAST
* This changes the current window focus to the window that was most recently
* the current window *but only if that window is still visible*. If the
* window is no longer visible (having been HIDDEN), then the next window
* following the current window will be made the current window.
*/
static Window *window_last(Window * window, char **args, char *usage)
{
set_current_window(NULL);
return curr_scr_win;
}
/*
* /WINDOW LASTLOG <size>
* This changes the size of the window's lastlog buffer. The default value
* for a window's lastlog is the value of /set LASTLOG, but each window may
* be independantly tweaked with this command.
*/
static Window *window_lastlog(Window * window, char **args, char *usage)
{
char *arg = next_arg(*args, args);
if (arg) {
int size = my_atol(arg);
if (window->lastlog_size > size) {
int i, diff;
diff = window->lastlog_size - size;
for (i = 0; i < diff; i++)
remove_from_lastlog(window);
}
window->lastlog_max = size;
}
say("Lastlog size is %d", window->lastlog_max);
return window;
}
/*
* /WINDOW LASTLOG_LEVEL <level-description>
* This changes the types of lines that will be placed into this window's
* lastlog. It is useful to note that the window's lastlog will contain
* a subset (possibly a complete subset) of the lines that have appeared
* in the window. This setting allows you to control which lines are
* "thrown away" by the window.
*/
static Window *window_lastlog_level(Window * window, char **args, char *usage)
{
char *arg = next_arg(*args, args);;
if (arg)
window->lastlog_level = parse_lastlog_level(arg);
say("Lastlog level is %s", bits_to_lastlog_level(window->lastlog_level));
return window;
}
/*
* /WINDOW LEVEL <level-description>
* This changes the types of output that will appear in the specified window.
* Note that for the given set of windows connected to a server, each level
* may only appear once in that set. When you add a level to a given window,
* then it will be removed from whatever window currently holds it. The
* exception to this is the "DCC" level, which may only be set to one window
* for the entire client.
*/
static Window *window_level(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args))) {
window->window_level = parse_lastlog_level(arg);
revamp_window_levels(window);
}
say("Window level is %s", bits_to_lastlog_level(window->window_level));
return window;
}
/*
* /WINDOW LIST
* This lists all of the windows known to the client, and a breif summary
* of their current state.
*/
Window *window_list(Window * window, char **args, char *usage)
{
Window *tmp = NULL;
int len = 6;
int cnw = get_int_var(CHANNEL_NAME_WIDTH_VAR);
while (traverse_all_windows(&tmp)) {
if (tmp->name && (strlen(tmp->name) > len))
len = strlen(tmp->name);
}
say(WIN_FORM, "Ref", 12, 12, "Nick", len, len, "Name", cnw, cnw, "Channel", "Query", "Server", "Level", empty_str);
tmp = NULL;
while (traverse_all_windows(&tmp))
list_a_window(tmp, len);
return window;
}
/*
* /WINDOW LOG ON|OFF
* This sets the current state of the logfile for the given window. When the
* logfile is on, then any lines that appear on the window are written to the
* logfile 'as-is'. The name of the logfile can be controlled with
* /WINDOW LOGFILE. The default logfile name is <windowname>.<target|refnum>
*/
static Window *window_log(Window * window, char **args, char *usage)
{
char *logfile;
int add_ext = 1;
char buffer[BIG_BUFFER_SIZE + 1];
if (get_boolean("LOG", args, &window->log))
return NULL;
if ((logfile = window->logfile))
add_ext = 0;
else if (!(logfile = get_string_var(LOGFILE_VAR)))
logfile = empty_str;
strmcpy(buffer, logfile, BIG_BUFFER_SIZE);
if (add_ext) {
char *title = empty_str;
strmcat(buffer, ".", BIG_BUFFER_SIZE);
if ((title = window->current_channel))
strmcat(buffer, title, BIG_BUFFER_SIZE);
else if ((title = window->query_nick))
strmcat(buffer, title, BIG_BUFFER_SIZE);
else {
strmcat(buffer, "Window_", BIG_BUFFER_SIZE);
strmcat(buffer, ltoa(window->refnum), BIG_BUFFER_SIZE);
}
}
do_log(window->log, buffer, &window->log_fp);
if (!window->log_fp)
window->log = 0;
return window;
}
/*
* /WINDOW LOGFILE <filename>
* This sets the current value of the log filename for the given window.
* When you activate the log (with /WINDOW LOG ON), then any output to the
* window also be written to the filename specified.
*/
static Window *window_logfile(Window * window, char **args, char *usage)
{
char *arg = next_arg(*args, args);
if (arg) {
malloc_strcpy(&window->logfile, arg);
say("Window LOGFILE set to %s", arg);
} else if (window->logfile)
say("Window LOGFILE is %s", window->logfile);
else
say("Window LOGFILE is not set.");
return window;
}
static Window *window_move(Window * window, char **args, char *usage)
{
move_window(window, get_number("MOVE", args, NULL));
return window;
}
static Window *window_name(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args))) {
if (is_window_name_unique(arg)) {
malloc_strcpy(&window->name, arg);
window->update |= UPDATE_STATUS;
} else
say("%s is not unique!", arg);
} else
say("You must specify a name for the window!");
return window;
}
static Window *window_new(Window * window, char **args, char *usage)
{
Window *tmp;
if ((tmp = new_window()))
window = tmp;
return window;
}
static Window *window_next(Window * window, char **args, char *usage)
{
swap_next_window(0, NULL);
return window;
}
static Window *window_notify(Window * window, char **args, char *usage)
{
window->miscflags ^= WINDOW_NOTIFY;
say("Notification when hidden set to %s", window->miscflags & WINDOW_NOTIFY ? on_str : off_str);
return window;
}
static Window *window_notify_level(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args)))
window->notify_level = parse_lastlog_level(arg);
say("Window notify level is %s", bits_to_lastlog_level(window->notify_level));
return window;
}
static Window *window_number(Window * window, char **args, char *usage)
{
Window *tmp;
char *arg;
int i;
if ((arg = next_arg(*args, args))) {
if ((i = my_atol(arg)) > 0) {
if ((tmp = get_window_by_refnum(i)))
tmp->refnum = window->refnum;
window->refnum = i;
update_all_status(curr_scr_win, NULL, 0);
} else
say("Window number must be greater than 0");
} else
say("Window number missing");
return window;
}
static Window *window_previous(Window * window, char **args, char *usage)
{
swap_previous_window(0, NULL);
return window;
}
static Window *window_prompt(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args))) {
malloc_strcpy(&window->prompt, arg);
window->update |= UPDATE_STATUS;
} else
say("You must specify a prompt for the window!");
return window;
}
static Window *window_refnum(Window * window, char **args, char *usage)
{
Window *tmp;
if ((tmp = get_window("REFNUM", args))) {
if (tmp->screen && tmp->screen != window->screen)
say("Window is in another screen!");
else if (tmp->visible) {
set_current_window(tmp);
window = tmp;
} else
say("Window is not visible!");
} else {
say("No such window!");
window = NULL;
}
return window;
}
static Window *window_remove(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args))) {
char *ptr;
struct nick_list *new;
while (arg) {
if ((ptr = strchr(arg, ',')) != NULL)
*ptr++ = 0;
if ((new = (struct nick_list *) remove_from_list((struct list **) &(window->nicks), arg))) {
say("Removed %s from window name list", new->nick);
new_free(&new->nick);
new_free((char **) &new);
} else
say("%s is not on the list for this window!", arg);
arg = ptr;
}
} else
say("REMOVE: Do something! Geez!");
return window;
}
static Window *window_server(Window * window, char **args, char *usage)
{
char *arg;
#ifdef HAVE_SSL
int with_ssl = 0;
#endif
if ((arg = next_arg(*args, args))) {
#ifdef HAVE_SSL
if (!my_stricmp(arg, "-SSL")) {
with_ssl = 1;
arg = next_arg(*args, args);
}
#endif
if (arg) {
int i = find_server_refnum(arg, NULL);
#ifdef HAVE_SSL
set_server_ssl(i, with_ssl);
#endif
if (!connect_to_server_by_refnum(i, -1)) {
set_window_server(window->refnum, from_server, 0);
window->window_level = LOG_ALL;
if (window->current_channel)
new_free(&window->current_channel);
update_all_status(window, NULL, 0);
}
}
} else {
say("SERVER: You must specify a server");
}
return window;
}
static Window *window_show(Window * window, char **args, char *usage)
{
Window *tmp;
if ((tmp = get_window("SHOW", args))) {
show_window(tmp);
window = curr_scr_win;
}
return window;
}
static Window *window_skip(Window * window, char **args, char *usage)
{
if (get_boolean("SKIP", args, &window->skip))
return NULL;
return window;
}
static Window *window_show_all(Window * window, char **args, char *usage)
{
while (invisible_list)
if (show_window(invisible_list))
break;
return window;
}
static Window *window_shrink(Window * window, char **args, char *usage)
{
resize_window(RESIZE_REL, window, -get_number("SHRINK", args, NULL));
return window;
}
static Window *window_size(Window * window, char **args, char *usage)
{
resize_window(RESIZE_ABS, window, get_number("SIZE", args, NULL));
return window;
}
static Window *window_swap(Window * window, char **args, char *usage)
{
Window *tmp;
if ((tmp = get_invisible_window("SWAP", args)))
swap_window(window, tmp);
return window;
}
static Window *window_unbind(Window * window, char **args, char *usage)
{
char *arg;
if ((arg = next_arg(*args, args))) {
if (is_bound(arg, from_server)) {
say("Channel %s is no longer bound", arg);
unbind_channel(arg, from_server);
} else
say("Channel %s is not bound", arg);
} else {
say("Channel %s is no longer bound", window->bind_channel);
new_free(&window->bind_channel);
}
return window;
}
static Window *window_query(Window * window, char **args, char *usage)
{
char *arg;
arg = next_arg(*args, args);
t_parse_command("QUERY", arg);
return window;
}
typedef Window *(*window_func) (Window *, char **args, char *usage);
typedef struct window_ops_T {
char *command;
window_func func;
char *usage;
} window_ops;
static Window *window_help(Window *, char **, char *);
static window_ops options[] = {
{"ADD", window_add, NULL},
{"BACK", window_back, NULL},
{"BALANCE", window_balance, NULL},
{"BEEP_ALWAYS", window_beep_always, NULL},
{"BIND", window_bind, NULL},
{"CHANNEL", window_channel, NULL},
{"DESCRIBE", window_describe, NULL},
{"FIXED", window_fixed, NULL},
{"GOTO", window_goto, NULL},
{"GROW", window_grow, NULL},
{"HELP", window_help, NULL},
{"HIDE", window_hide, NULL},
{"HIDE_OTHERS", window_hide_others, NULL},
{"HOLD_MODE", window_hold_mode, NULL},
{"KILL", window_kill, NULL},
{"KILL_OTHERS", window_kill_others, NULL},
{"KILLSWAP", window_killswap, NULL},
{"LAST", window_last, NULL},
{"LASTLOG", window_lastlog, NULL},
{"LASTLOG_LEVEL", window_lastlog_level, NULL},
{"LEVEL", window_level, NULL},
{"LIST", window_list, NULL},
{"LOG", window_log, NULL},
{"LOGFILE", window_logfile, NULL},
{"MOVE", window_move, NULL},
{"NAME", window_name, NULL},
{"NEW", window_new, NULL},
{"NEXT", window_next, NULL},
{"NOTIFY", window_notify, NULL},
{"NOTIFY_LEVEL", window_notify_level, NULL},
{"NUMBER", window_number, NULL},
{"PREVIOUS", window_previous, NULL},
{"PROMPT", window_prompt, NULL},
{"QUERY", window_query, NULL},
{"REFNUM", window_refnum, NULL},
{"REMOVE", window_remove, NULL},
{"SERVER", window_server, NULL},
{"SHOW", window_show, NULL},
{"SHOW_ALL", window_show_all, NULL},
{"SHRINK", window_shrink, NULL},
{"SIZE", window_size, NULL},
{"SKIP", window_skip, NULL},
{"SWAP", window_swap, NULL},
{"UNBIND", window_unbind, NULL},
{NULL, NULL, NULL}
};
static Window *window_help(Window * window, char **args, char *usage)
{
int i, c = 0;
char buffer[BIG_BUFFER_SIZE + 1];
char *arg = NULL;
*buffer = 0;
if (!(arg = next_arg(*args, args))) {
for (i = 0; options[i].command; i++) {
strmcat(buffer, options[i].command, BIG_BUFFER_SIZE);
strmcat(buffer, " ", BIG_BUFFER_SIZE);
if (++c == 5) {
put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer));
*buffer = 0;
c = 0;
}
}
if (c)
put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer));
userage("window help", "%R[%ncommand%R]%n to get help on specific commands");
}
return window;
}
void cmd_window(struct command *cmd, char *args)
{
char *arg;
int nargs = 0;
Window *window;
in_window_command = 1;
message_from(NULL, LOG_CURRENT);
window = curr_scr_win;
while ((arg = next_arg(args, &args))) {
int i;
int len = strlen(arg);
for (i = 0; options[i].func; i++) {
if (!my_strnicmp(arg, options[i].command, len)) {
window = options[i].func(window, &args, options[i].usage);
nargs++;
if (!window)
args = NULL;
break;
}
}
if (!options[i].func)
yell("WINDOW: Invalid option: [%s]", arg);
}
if (!nargs)
window_describe(curr_scr_win, NULL, NULL);
in_window_command = 0;
message_from(NULL, LOG_CRAP);
build_status(window, NULL, 0);
update_all_windows();
cursor_to_input();
}
/* * * * * * * * * * * SCROLLBACK BUFFER * * * * * * * * * * * * * * */
/*
* XXXX Dont you DARE touch this XXXX
*
* Most of the time, a delete_display_line() is followed somewhat
* immediately by a new_display_line(). So most of the time we just
* cache that one item and re-use it. That saves us thousands of
* malloc()s. In the cases where its not, then we just do things the
* normal way.
*/
static Display *recycle = NULL;
void delete_display_line(Display * stuff)
{
if (recycle == stuff)
ircpanic("error in delete_display_line");
if (recycle)
new_free((char **) &recycle);
recycle = stuff;
new_free(&stuff->line);
}
Display *new_display_line(Display * prev)
{
Display *stuff;
if (recycle) {
stuff = recycle;
recycle = NULL;
} else
stuff = (Display *) new_malloc(sizeof(Display));
stuff->line = NULL;
stuff->prev = prev;
stuff->next = NULL;
return stuff;
}
/* * * * * * * * * * * Scrollback functionality * * * * * * * * * * */
void scrollback_backwards_lines(int lines)
{
Window *window = curr_scr_win;
Display *new_top = window->top_of_display;
int new_lines;
if (new_top == window->top_of_scrollback) {
term_beep();
return;
}
if (!window->scrollback_point)
window->scrollback_point = window->top_of_display;
for (new_lines = 0; new_lines < lines; new_lines++) {
if (new_top == window->top_of_scrollback)
break;
new_top = new_top->prev;
}
window->top_of_display = new_top;
window->lines_scrolled_back += new_lines;
recalculate_window_cursor(window);
repaint_window(window, 0, -1);
cursor_not_in_display();
update_input(UPDATE_JUST_CURSOR);
}
void scrollback_forwards_lines(int lines)
{
Window *window = curr_scr_win;
Display *new_top = window->top_of_display;
int new_lines = 0;
if (new_top == window->display_ip || !window->scrollback_point) {
term_beep();
return;
}
for (new_lines = 0; new_lines < lines; new_lines++) {
if (new_top == window->display_ip)
break;
new_top = new_top->next;
}
window->top_of_display = new_top;
window->lines_scrolled_back -= new_lines;
recalculate_window_cursor(window);
repaint_window(window, 0, -1);
cursor_not_in_display();
update_input(UPDATE_JUST_CURSOR);
if (window->lines_scrolled_back <= 0)
scrollback_end(0, NULL);
}
void scrollback_forwards(char dumb, char *dumber)
{
scrollback_forwards_lines(curr_scr_win->display_size / 2);
}
void scrollback_backwards(char dumb, char *dumber)
{
scrollback_backwards_lines(curr_scr_win->display_size / 2);
}
void scrollback_end(char dumb, char *dumber)
{
Window *window = curr_scr_win;
if (!window->scrollback_point) {
term_beep();
return;
}
/* Adjust the top of window only if we would move forward. */
if (window->lines_scrolled_back > 0)
window->top_of_display = window->scrollback_point;
window->lines_scrolled_back = 0;
window->scrollback_point = NULL;
repaint_window(window, 0, -1);
cursor_not_in_display();
update_input(UPDATE_JUST_CURSOR);
while (window->holding_something)
unhold_a_window(window);
}
void scrollback_start(char dumb, char *dumber)
{
Window *window = curr_scr_win;
if (window->display_buffer_size <= window->display_size) {
term_beep();
return;
}
if (!window->scrollback_point)
window->scrollback_point = window->top_of_display;
while (window->top_of_display != window->top_of_scrollback) {
window->top_of_display = window->top_of_display->prev;
window->lines_scrolled_back++;
}
repaint_window(window, 0, -1);
cursor_not_in_display();
update_input(UPDATE_JUST_CURSOR);
}
/* HOLD MODE STUFF */
/*
* hold_mode: sets the "hold mode". Really. If the update flag is true,
* this will also update the status line, if needed, to display the hold mode
* state. If update is false, only the internal flag is set.
*/
void hold_mode(Window * window, int flag, int update)
{
if (window == NULL)
window = curr_scr_win;
if (flag != ON && window->scrollback_point)
return;
if (flag == TOGGLE) {
if (window->hold_mode == OFF)
window->hold_mode = ON;
else
window->hold_mode = OFF;
} else
window->hold_mode = flag;
if (update) {
if (window->lines_held != window->last_lines_held) {
window->last_lines_held = window->lines_held;
update_window_status(window, 0);
if (window->update | UPDATE_STATUS)
window->update -= UPDATE_STATUS;
cursor_in_display();
update_input(NO_UPDATE);
}
} else
window->last_lines_held = -1;
}
void unstop_all_windows(char dumb, char *dumber)
{
Window *tmp;
for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
hold_mode(tmp, OFF, 1);
}
/*
* reset_line_cnt: called by /SET HOLD_MODE to reset the line counter so we
* always get a held screen after the proper number of lines
*/
void reset_line_cnt(Window * win, char *unused, int value)
{
curr_scr_win->hold_mode = value;
curr_scr_win->held_displayed = 0;
}
/* toggle_stop_screen: the BIND function TOGGLE_STOP_SCREEN */
void toggle_stop_screen(char unused, char *not_used)
{
hold_mode((Window *) 0, TOGGLE, 1);
update_all_windows();
}
/*
* If "scrollback_point" is set, then anything below the bottom of the screen
* at that point gets nuked.
* If "scrollback_point" is not set, anything below the current position of
* the screen gets nuked.
*/
void flush_everything_being_held(Window * window)
{
Display *ptr;
int count;
if (!window)
window = curr_scr_win;
count = window->display_size;
if (window->scrollback_point)
ptr = window->scrollback_point;
else
ptr = window->top_of_display;
while (count--) {
ptr = ptr->next;
if (ptr == window->display_ip)
return; /* Nothing to flush */
}
ptr->next = window->display_ip;
window->display_ip->prev = ptr;
while (ptr != window->display_ip) {
Display *next = ptr->next;
delete_display_line(ptr);
window->lines_held--;
ptr = next;
}
if (window->lines_held != 0)
ircpanic("erf. fix this.");
window->holding_something = 0;
hold_mode(window, OFF, 1);
}
/*
* This adjusts the viewport up one full screen. This calls rite()
* indirectly, because repaint_window() uses rite() to do the work.
* This belongs somewhere else.
*/
void unhold_a_window(Window * window)
{
int amount = window->display_size;
if (window->holding_something && (window->distance_from_display < window->display_size)) {
window->holding_something = 0;
window->lines_held = 0;
}
if (!window->lines_held || window->scrollback_point)
return; /* Right. */
if (window->lines_held < amount)
amount = window->lines_held;
window->lines_held -= amount;
window->held_displayed = 0;
if (!window->lines_held)
window->holding_something = 0;
if (!amount)
return; /* Whatever */
while (amount--)
window->top_of_display = window->top_of_display->next;
repaint_window(window, 0, -1);
}
void recalculate_window_cursor(Window * window)
{
Display *tmp;
window->cursor = window->distance_from_display = 0;
for (tmp = window->top_of_display; tmp != window->display_ip; tmp = tmp->next)
window->cursor++, window->distance_from_display++;
if (window->cursor > window->display_size)
window->cursor = window->display_size;
}
syntax highlighted by Code2HTML, v. 0.9.1