📄 winio.c
字号:
/* Copyright (c) 2000 Kevin Sullivan <nite@gis.net> * * Please refer to the COPYRIGHT file for more information. *//* this file contains procedures related to the main window: drawing, redrawing, scrolling, user input, etc. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#define _GNU_SOURCE /* needed for stdio.h:vasprintf */#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <termios.h>#include <ncurses.h>#include <string.h>#include <sys/ioctl.h>#include <netdb.h>#include <time.h>#include "defines.h"#include "codes.h"#include "nap.h"#include "colors.h"#include "winio.h"#include "alias.h"#include "irc.h"#include "lists.h"#include "scheck.h"#include "sscr.h"#include "dlul_screen.h"#include "missing.h"#ifdef MEMWATCH #include "memwatch.h"#endifextern info_t info;extern int ircmode, wmode;extern chans_t *curchan; /* current channel, if any */extern upload_t *up; /* download task list */extern download_t *down; /* download task list */extern scount_t scount; /* libraries, songs, gigs */extern char *mnick;extern int noprint;extern int ircsock;extern alias_t *alhead; /* alias list */extern out_nap_cmd_t out[]; /* list of builtin commands */extern WINDOW *swin;/* the new model for managing input screens is as follows: *//* the number of the currently active screen. Currently three values are possible: MAIN_SCREEN, RESULT_SCREEN, and DLUL_SCREEN. However, further screens may be added in the future (such as: resume screen, configuration screen) */int screen;/* Each screen has its own curses windows, and its own global state (such as: scroll buffer, command history, and input state for main screen, search item under cursor, displayed information categories, etc, for search screen). When switching screens, it is equally important to switch the input focus. In the new model, there is only one "input" connection which remains active at all times, but its "func" component is set to a different handler for different screens. Its "d" component is not used. It is imperative to update the "screen" variable and this handler at the same time, or else the user input will be directed to an invisible screen. *//* individual screens may choose to delete their curses windows when they are not switched on (the search result screen does this), or to retain them (the main screen does it this way). *//* each screen should provide a procedure for switching it on (initializing its state, windows, and input handler) and for switching it off (deleting any part of the state that is not needed). The function switchscreen(n) switches to screen number n, setting "screen" as appropriate, and calling the individual screen's off and on routines. *//* curses windows and global state for main screen */WINDOW *wchan=NULL, *winput, *sep, *whead;int tind = 0; /* indentation of the title (channel topic) */chans_t *recent = NULL; /* most recent channel; (always NULL) */scroll_t *mscroll = NULL; /* top of the main scroll */scroll_t *mscrollend = NULL; /* bottom of the main scroll */scroll_t *scur = NULL; /* last line now displayed, or NULL for end */int mscrollsize = 0; /* length of the main scroll */int lastlogflag = 0; /* set to 1 during output of "lastlog" command - this causes these lines to be marked and ignored in future "lastlog" commands. *//* the command history */cmds_t *cmdl, *cmdlend = NULL; /* A doubly linked list of lines, possibly empty. This is read-only, except that new lines can be appended at the end, and the total length of the list is bounded by BACKLOG. */int cmdlsize = 0; /* length of the command history */cmds_t *ccmd = NULL; /* a pointer to the line in cmdl which the current edit is based on, or NULL if the current edit is from scratch */unsigned char cbuf[512]; /* the line currently being edited */unsigned char cscratch[512]; /* a place where the current "from scratch" line is saved if ccmd != NULL */int curr = 0; /* first char of cbuf displayed on screen */int curx = 0; /* cursor position in cbuf *//* global state for search screen is defined in sscr.c */colortab_t colortab[] = { { RED, CPR, 1 }, { GREEN, CPG, 1 }, { WHITE, CPW, 1 }, { BLUE, CPB, 1 }, { YELLOW, CPY, 1 }, { MAGENTA, CPM, 1 }, { CYAN, CPC, 1, }, { BOLD, A_BOLD, 0 }, { DARK, A_DIM, 0 }, { BLINK, A_BLINK, 0 }, { UNDERLINE, A_UNDERLINE, 0 }, { NULL, -1, 0 }};/* switch to screen number n (which should be MAIN_SCREEN, RESULT_SCREEN, or DLUL_SCREEN). Returns 0 if we already were on that screen (without redrawing it), 1 if there was a real switch, and -1 on error. */int switchtoscreen(int n) { if (n==screen) { return 0; } /* check that screen selected is valid */ switch (n) { case MAIN_SCREEN: case RESULT_SCREEN: case DLUL_SCREEN: break; default: return(-1); } /* turn off old screen */ switch (screen) { case MAIN_SCREEN: /* nothing to do */ break; case RESULT_SCREEN: endsearchscr(); break; case DLUL_SCREEN: enddlulscr(); break; default: return(-1); break; } screen = n; /* turn on new screen */ switch (n) { case MAIN_SCREEN: mainscr(); break; case RESULT_SCREEN: searchscr(); break; case DLUL_SCREEN: dlulscr(); break; default: /* not reachable */ return(-1); break; } return(1);}/* switch to the next available screen */int nextscreen(void) { switch(screen) { case MAIN_SCREEN: switchtoscreen(RESULT_SCREEN); break; case RESULT_SCREEN: switchtoscreen(DLUL_SCREEN); break; case DLUL_SCREEN: default: switchtoscreen(MAIN_SCREEN); break; } return(1);}/* switch to main screen */void mainscr(void) { sock_t *sk; sk = findsock("input"); if (sk) { sk->func = input; } dscr(wchan); drw(wchan); dstatus(); indraw();}void resize(){ sock_t *t; struct winsize ws; memset(&ws, 0, sizeof(ws)); ioctl(fileno(stdin), TIOCGWINSZ, &ws); resizeterm(ws.ws_row, ws.ws_col); winput->_begy = LINES-1; winput->_begx = 0; sep->_begy = LINES-2; sep->_begx = 0; if (info.notop) wresize(wchan, LINES-2, COLS); else wresize(wchan, LINES-3, COLS); wresize(winput, 1, COLS); if (!info.notop) wresize(whead, 1, COLS); wresize(sep, 1, COLS); drw(wchan); drw(sep); dstatus(); /* redraw input screen */ werase(winput); t = findsock("input"); if (t) { indraw(); } dscr(wchan); drw(wchan); drw(winput); if (screen==RESULT_SCREEN) { plist(); } else if (screen == DLUL_SCREEN) { dlul_refresh(); } return;}void wstats(WINDOW *win){ wp(win, "stdscr to %i - %i\n", stdscr->_maxy, stdscr->_maxx); wp(win, "winput to %i - %i\n", winput->_maxy, winput->_maxx); wp(win, "sep to %i - %i\n", sep->_maxy, sep->_maxx); wp(win, "wchan to %i - %i\n", wchan->_maxy, wchan->_maxx); wp(win, "LINES/COLS to %i - %i\n", LINES, COLS); drw(win);}void drw(WINDOW *win){ if (info.daemon || !win) return; if (screen==RESULT_SCREEN && win == swin) wrefresh(win); else if (screen==DLUL_SCREEN && win == dlul_win) wrefresh(win); else if (screen==MAIN_SCREEN) wrefresh(win);}void dstatus(){ int j, lg; char *t = NULL; user_t *cur; int nu, nd, ndq; download_t *dtask; upload_t *utask; list_count(down, nd, dtask, ACTIVE(dtask->state) && dtask->state!=RRQUEUED); list_count(down, ndq, dtask, dtask->state == QUEUED || dtask->state == RQUEUED || dtask->state == RRQUEUED); list_count(up, nu, utask, !STOPPED(utask->state)); if (info.daemon) { return; } werase(sep); if (!info.notop) werase(whead); for (j=0;j<COLS;j++) { waddch(sep, ' '); if (!info.notop) waddch(whead, ' '); } if ((!ircmode && !curchan) || (curchan && (!curchan->q || curchan->q == 1))) { msprintf(&t, "[U/%i D/%i Q/%i]", nu, nd, ndq); mvwprintw(sep, 0, COLS-(strlen(t)+1), t); free(t); mvwprintw(sep, 0, 0, cloaked ? " (%s)" : " [%s]", info.user); wprintw(sep, scount.songs == 1 ? " [%lu song" : " [%lu songs", scount.songs); wprintw(sep, scount.libraries == 1 ? " in %lu library" : " in %lu libraries", scount.libraries); wprintw(sep, scount.gigs == 1 ? " (%lu gig)]" : " (%lu gigs)]", scount.gigs); } else { if (!curchan || !curchan->users) mvwprintw(sep, 0, 0, " [%s]", mnick); else if (curchan->flag) { t = strdup(curchan->nm); if (strlen(curchan->nm) > COLS/4) t[COLS/4] = 0; cur = finduser(curchan, mnick); if (cur->flag & NAP_OP) mvwprintw(sep, 0, 0, " [@%s] [%s +", mnick, t); else if (cur->flag & NAP_VOICE) mvwprintw(sep, 0, 0, " [+%s] [%s +", mnick, t); else mvwprintw(sep, 0, 0, " [%s] [%s +", mnick, t); if (curchan->flag & NAP_I) waddch(sep, 'i'); if (curchan->flag & NAP_S) waddch(sep, 's'); if (curchan->flag & NAP_P) waddch(sep, 'p'); if (curchan->flag & NAP_T) waddch(sep, 't'); if (curchan->flag & NAP_M) waddch(sep, 'm'); if (curchan->flag & NAP_N) waddch(sep, 'n'); if (curchan->flag & NAP_K) waddch(sep, 'k'); if (curchan->flag & NAP_L) waddch(sep, 'l'); if (curchan->flag & NAP_K || curchan->flag & NAP_L) waddch(sep, ' '); if (curchan->flag & NAP_K) wprintw(sep, "%s", curchan->key); if (curchan->flag & NAP_K && curchan->flag & NAP_L) waddch(sep, ' '); if (curchan->flag & NAP_L) wprintw(sep, "%i", (unsigned int)curchan->l); waddch(sep, ']'); free(t); t = NULL; } else { t = strdup(curchan->nm); if (strlen(curchan->nm) > COLS/4) t[COLS/4] = 0; cur = finduser(curchan, mnick); if (cur->flag & NAP_OP) mvwprintw(sep, 0, 0, " [@%s] [%s]", mnick, t); else if (cur->flag & NAP_VOICE) mvwprintw(sep, 0, 0, " [+%s] [%s]", mnick, t); else mvwprintw(sep, 0, 0, " [%s] [%s]", mnick, t); free(t); t = NULL; } } if (!info.notop) { lg = COLS-(strlen(VERSION)+8)-4; if (lg >= 0) { mvwprintw(whead, 0, COLS-(strlen(VERSION)+8), "[nap v%s]", VERSION); if (curchan && curchan->q != 1 && curchan->topic) { t = (char *)malloc(lg+1); memset(t, 0, lg+1); if (strlen(curchan->topic) < lg + tind) { /* drw(wchan); */ /* why here? */ tind = strlen(curchan->topic)-lg; } if (tind < 0) tind = 0; if (tind + lg < strlen(curchan->topic)) { strncpy(t, curchan->topic+tind, lg-3); mvwprintw(whead, 0, 0, " [%s...]", t); } else { strncpy(t, curchan->topic+tind, lg); mvwprintw(whead, 0, 0, " [%s]", t); } free(t); } else if (curchan && curchan->q == 1) mvwprintw(whead, 0, 0, " [Query (%s)]", curchan->nm); if (screen == MAIN_SCREEN) wnoutrefresh(whead); } } if (screen == MAIN_SCREEN) { wnoutrefresh(sep); doupdate(); }}/* add the string STR to the given LOGFILE. If RP is set, replace escape sequences */void addlog(char *logfile, char *str, int rp){ FILE *f; int i, k; static int bol = 1; /* are we at the beginning of a line? */ time_t ct; struct tm *r; /* note: some extra care is taken to print the date and time just before a line is printed, and not just after one is printed, although that would have been easier. */ ct = time(NULL); r = localtime(&ct); f = fopen(logfile, "a"); if (!f) { return; } if (!rp) { fputs(str, f); return; } for (i=0;str[i];i++) { if (bol) { fprintf(f, "[%02i/%02i %i:%02i] ", r->tm_mon+1, r->tm_mday, r->tm_hour, r->tm_min); bol = 0; } if (str[i] == '\e') { for (k=0; str[i] && str[i]!='m' && k<6; k++, i++) ; continue; } fputc(str[i], f); if (str[i] == '\n') { bol = 1; } } fclose(f);}int wp(WINDOW *win, const char *fmt, ...){ va_list args; char *str; int i; if (noprint == 2) return(0); str = NULL; va_start(args, fmt); vasprintf(&str, fmt, args); va_end(args); if (info.logallfile) addlog(info.logallfile, str, 1); if (win && !info.daemon) { addscroll(win, str); if (nvar_default("noscroll", 0)==0) { scur = NULL; /* be sure to scroll to bottom on output */ } dscr(win); } if (!win && info.daemon!=2) { printf("%s", str); fflush(stdout); /* flushing here helps OpenBSD, which will otherwise not flush automatically before reading password. -PS */ } i = strlen(str); free(str); return(i);}/* examines string s for escape sequences and returns a (statically allocated) string which represents the escape sequences (color, boldface) in effect at the end of string s. If end!=NULL, s is considered to end there. */char *esc_getcolor(char *s, char *end) { static char out[11] = BOLD;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -