/* * dselect - Debian package maintenance user interface * baselist.cc - list of somethings * * Copyright © 1994,1995 Ian Jackson * Copyright © 2001 Wichert Akkerman * Copyright © 2007-2013 Guillem Jover * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dselect.h" #include "bindings.h" void mywerase(WINDOW *win) { int my,mx,y,x; getmaxyx(win,my,mx); for (y=0; yenddisplay(); endwin(); initscr(); if (ioctl(fileno(stdout), TIOCGWINSZ, &size) != 0) ohshite(_("ioctl(TIOCGWINSZ) failed")); resizeterm(size.ws_row, size.ws_col); wrefresh(curscr); p->startdisplay(); if (doupdate() == ERR) ohshite(_("doupdate in SIGWINCH handler failed")); errno = save_errno; } static void cu_sigwinch(int, void **argv) { struct sigaction *osigactp= (struct sigaction*)argv[0]; sigset_t *oblockedp= (sigset_t*)argv[1]; if (sigaction(SIGWINCH, osigactp, nullptr)) ohshite(_("failed to restore old SIGWINCH sigact")); delete osigactp; if (sigprocmask(SIG_SETMASK, oblockedp, nullptr)) ohshite(_("failed to restore old signal mask")); delete oblockedp; } void baselist::sigwinch_mask(int how) { sigset_t sigwinchset; sigemptyset(&sigwinchset); sigaddset(&sigwinchset,SIGWINCH); int rc = sigprocmask(how, &sigwinchset, nullptr); if (rc < 0) { if (how == SIG_UNBLOCK) ohshite(_("failed to unblock SIGWINCH")); else ohshite(_("failed to block SIGWINCH")); } } void baselist::setupsigwinch() { struct sigaction *osigactp = new(struct sigaction); sigset_t *oblockedp = new(sigset_t); if (sigprocmask(0, nullptr, oblockedp)) ohshite(_("failed to get old signal mask")); if (sigaction(SIGWINCH, nullptr, osigactp)) ohshite(_("failed to get old SIGWINCH sigact")); push_cleanup(cu_sigwinch, ~0, 2, osigactp, oblockedp); sigwinch_mask(SIG_BLOCK); struct sigaction nsigact; memset(&nsigact,0,sizeof(nsigact)); nsigact.sa_handler= sigwinchhandler; sigemptyset(&nsigact.sa_mask); //nsigact.sa_flags= SA_INTERRUPT; if (sigaction(SIGWINCH, &nsigact, nullptr)) ohshite(_("failed to set new SIGWINCH sigact")); } void baselist::add_column(column &col, const char *title, int width) { col.title = title; col.x = col_cur_x; col.width = width; col_cur_x += col.width + gap_width; } void baselist::end_column(column &col, const char *title) { col.title = title; col.x = col_cur_x; col.width = total_width - col.x; col_cur_x += col.width + gap_width; } void baselist::draw_column_head(column &col) { mvwaddnstr(colheadspad, 0, col.x, col.title, col.width); } void baselist::draw_column_sep(column &col, int y) { mvwaddch(listpad, y, col.x - 1, ' '); } void baselist::draw_column_item(column &col, int y, const char *item) { mvwprintw(listpad, y, col.x, "%-*.*s", col.width, col.width, item); } void baselist::setheights() { int y= ymax - (title_height + colheads_height + thisstate_height); if (y < 1) internerr("widget y=%d < 1", y); if (showinfo==2 && y>=7) { list_height= 5; whatinfo_height= 1; info_height= y-6; } else if (showinfo==1 && y>=10) { list_height= y/2; info_height= (y-1)/2; whatinfo_height= 1; } else { list_height= y; info_height= 0; whatinfo_height= 0; } colheads_row= title_height; list_row= colheads_row + colheads_height; thisstate_row= list_row + list_height; info_row= thisstate_row + thisstate_height; whatinfo_row= ymax - 1; } void baselist::startdisplay() { debug(dbg_general, "baselist[%p]::startdisplay()", this); cbreak(); noecho(); nonl(); keypad(stdscr,TRUE); clear(); wnoutrefresh(stdscr); // find attributes if (has_colors() && start_color()==OK && COLOR_PAIRS >= numscreenparts) { int i; printf("allocing\n"); for (i = 1; i < numscreenparts; i++) { if (init_pair(i, color[i].fore, color[i].back) != OK) ohshite(_("failed to allocate colour pair")); part_attr[i] = COLOR_PAIR(i) | color[i].attr; } } else { /* User defined attributes for B&W mode are not currently supported. */ part_attr[title] = A_REVERSE; part_attr[thisstate] = A_STANDOUT; part_attr[list] = 0; part_attr[listsel] = A_STANDOUT; part_attr[selstate] = A_BOLD; part_attr[selstatesel] = A_STANDOUT; part_attr[colheads]= A_BOLD; part_attr[query] = part_attr[title]; part_attr[info_body] = part_attr[list]; part_attr[info_head] = A_BOLD; part_attr[whatinfo] = part_attr[thisstate]; part_attr[helpscreen] = A_NORMAL; } // set up windows and pads, based on screen size getmaxyx(stdscr,ymax,xmax); title_height= ymax>=6; colheads_height= ymax>=5; thisstate_height= ymax>=3; setheights(); setwidths(); titlewin= newwin(1,xmax, 0,0); if (!titlewin) ohshite(_("failed to create title window")); wattrset(titlewin, part_attr[title]); whatinfowin= newwin(1,xmax, whatinfo_row,0); if (!whatinfowin) ohshite(_("failed to create whatinfo window")); wattrset(whatinfowin, part_attr[whatinfo]); listpad = newpad(ymax, total_width); if (!listpad) ohshite(_("failed to create baselist pad")); colheadspad= newpad(1, total_width); if (!colheadspad) ohshite(_("failed to create heading pad")); wattrset(colheadspad, part_attr[colheads]); thisstatepad= newpad(1, total_width); if (!thisstatepad) ohshite(_("failed to create thisstate pad")); wattrset(thisstatepad, part_attr[thisstate]); infopad= newpad(MAX_DISPLAY_INFO, total_width); if (!infopad) ohshite(_("failed to create info pad")); wattrset(infopad, part_attr[info_body]); wbkgdset(infopad, ' ' | part_attr[info_body]); querywin= newwin(1,xmax,ymax-1,0); if (!querywin) ohshite(_("failed to create query window")); wbkgdset(querywin, ' ' | part_attr[query]); if (cursorline >= topofscreen + list_height) topofscreen= cursorline; if (topofscreen > nitems - list_height) topofscreen= nitems - list_height; if (topofscreen < 0) topofscreen= 0; infotopofscreen= 0; leftofscreen= 0; redrawall(); debug(dbg_general, "baselist::startdisplay() done ...\n\n" " xmax=%d, ymax=%d;\n\n" " title_height=%d, colheads_height=%d, list_height=%d;\n" " thisstate_height=%d, info_height=%d, whatinfo_height=%d;\n\n" " colheads_row=%d, thisstate_row=%d, info_row=%d;\n" " whatinfo_row=%d, list_row=%d;\n\n", xmax, ymax, title_height, colheads_height, list_height, thisstate_height, info_height, whatinfo_height, colheads_row, thisstate_row, info_row, whatinfo_row, list_row); } void baselist::enddisplay() { delwin(titlewin); delwin(whatinfowin); delwin(listpad); delwin(colheadspad); delwin(thisstatepad); delwin(infopad); wmove(stdscr,ymax,0); wclrtoeol(stdscr); listpad = nullptr; col_cur_x = 0; } void baselist::redrawall() { redrawtitle(); redrawcolheads(); wattrset(listpad, part_attr[list]); mywerase(listpad); ldrawnstart= ldrawnend= -1; // start is first drawn; end is first undrawn; -1=none refreshlist(); redrawthisstate(); redrawinfo(); } void baselist::redraw1item(int index) { redraw1itemsel(index, index == cursorline); } baselist::baselist(keybindings *kb) { debug(dbg_general, "baselist[%p]::baselist()", this); bindings= kb; nitems= 0; col_cur_x = 0; gap_width = 1; total_width = max(TOTAL_LIST_WIDTH, COLS); xmax= -1; ymax = -1; list_height = 0; info_height = 0; title_height = 0; whatinfo_height = 0; colheads_height = 0; thisstate_height = 0; list_row = 0; info_row = 0; whatinfo_row = 0; colheads_row = 0; thisstate_row = 0; topofscreen = 0; leftofscreen = 0; infotopofscreen = 0; infolines = 0; listpad = nullptr; infopad = nullptr; colheadspad = nullptr; thisstatepad = nullptr; titlewin = nullptr; querywin = nullptr; whatinfowin = nullptr; cursorline = -1; ldrawnstart = 0; ldrawnend = 0; showinfo= 1; searchstring[0]= 0; } void baselist::itd_keys() { whatinfovb(_("Keybindings")); const int givek= xmax/3; bindings->describestart(); const char **ta; while ((ta = bindings->describenext()) != nullptr) { const char **tap= ta+1; for (;;) { waddstr(infopad, gettext(*tap)); tap++; if (!*tap) break; waddstr(infopad, ", "); } int y,x; getyx(infopad,y,x); if (x >= givek) y++; mvwaddstr(infopad, y,givek, ta[0]); waddch(infopad,'\n'); delete [] ta; } } void baselist::dosearch() { int offset, index; debug(dbg_general, "baselist[%p]::dosearch(); searchstring='%s'", this, searchstring); for (offset = 1, index = max(topofscreen, cursorline + 1); offset= nitems) index -= nitems; if (matchsearch(index)) { topofscreen= index-1; if (topofscreen > nitems - list_height) topofscreen= nitems-list_height; if (topofscreen < 0) topofscreen= 0; setcursor(index); return; } } beep(); } void baselist::refreshinfo() { pnoutrefresh(infopad, infotopofscreen,leftofscreen, info_row,0, min(info_row + info_height - 1, info_row + MAX_DISPLAY_INFO - 1), min(total_width - leftofscreen - 1, xmax - 1)); if (whatinfo_height) { mywerase(whatinfowin); mvwaddstr(whatinfowin,0,0, whatinfovb.string()); if (infolines > info_height) { wprintw(whatinfowin,_(" -- %d%%, press "), (int)((infotopofscreen + info_height) * 100.0 / infolines)); if (infotopofscreen + info_height < infolines) { wprintw(whatinfowin,_("%s for more"), bindings->find("iscrollon")); if (infotopofscreen) waddstr(whatinfowin, ", "); } if (infotopofscreen) wprintw(whatinfowin, _("%s to go back"),bindings->find("iscrollback")); waddch(whatinfowin,'.'); } wnoutrefresh(whatinfowin); } } void baselist::wordwrapinfo(int offset, const char *m) { int usemax= xmax-5; debug(dbg_general, "baselist[%p]::wordwrapinfo(%d, '%s')", this, offset, m); bool wrapping = false; for (;;) { int offleft=offset; while (*m == ' ' && offleft>0) { m++; offleft--; } const char *p = strchrnul(m, '\n'); int l = (int)(p - m); while (l && c_isspace(m[l - 1])) l--; if (!l || (*m == '.' && l == 1)) { if (wrapping) waddch(infopad,'\n'); waddch(infopad, '\n'); wrapping = false; } else if (*m == ' ' || usemax < 10) { if (wrapping) waddch(infopad,'\n'); waddnstr(infopad, m, l); waddch(infopad, '\n'); wrapping = false; } else { int x, y DPKG_ATTR_UNUSED; if (wrapping) { getyx(infopad, y,x); if (x+1 >= usemax) { waddch(infopad,'\n'); } else { waddch(infopad,' '); } } for (;;) { getyx(infopad, y,x); int dosend= usemax-x; if (l <= dosend) { dosend=l; } else { int i=dosend; while (i > 0 && m[i] != ' ') i--; if (i > 0 || x > 0) dosend=i; } if (dosend) waddnstr(infopad, m, dosend); while (dosend < l && m[dosend] == ' ') dosend++; l-= dosend; m+= dosend; if (l <= 0) break; waddch(infopad,'\n'); } wrapping = true; } if (*p == '\0') break; if (getcury(infopad) == (MAX_DISPLAY_INFO - 1)) { waddstr(infopad, "[The package description is too long and has been truncated...]"); break; } m= ++p; } debug(dbg_general, "baselist[%p]::wordwrapinfo() done", this); } baselist::~baselist() { }