2 * dselect - Debian package maintenance user interface
3 * baselist.cc - list of somethings
5 * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2001 Wichert Akkerman <wakkerma@debian.org>
7 * Copyright © 2007-2013 Guillem Jover <guillem@debian.org>
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26 #include <sys/ioctl.h>
35 #include <dpkg/i18n.h>
36 #include <dpkg/c-ctype.h>
37 #include <dpkg/dpkg.h>
38 #include <dpkg/dpkg-db.h>
43 void mywerase(WINDOW
*win
) {
46 for (y
=0; y
<my
; y
++) {
47 wmove(win
,y
,0); for (x
=0; x
<mx
; x
++) waddch(win
,' ');
52 baselist
*baselist::signallist
= nullptr;
53 void baselist::sigwinchhandler(int) {
54 int save_errno
= errno
;
56 debug(dbg_general
, "baselist::sigwinchhandler(), signallist=%p", signallist
);
57 baselist
*p
= signallist
;
60 if (ioctl(fileno(stdout
), TIOCGWINSZ
, &size
) != 0) ohshite(_("ioctl(TIOCGWINSZ) failed"));
61 resizeterm(size
.ws_row
, size
.ws_col
); wrefresh(curscr
);
63 if (doupdate() == ERR
) ohshite(_("doupdate in SIGWINCH handler failed"));
67 static void cu_sigwinch(int, void **argv
) {
68 struct sigaction
*osigactp
= (struct sigaction
*)argv
[0];
69 sigset_t
*oblockedp
= (sigset_t
*)argv
[1];
71 if (sigaction(SIGWINCH
, osigactp
, nullptr))
72 ohshite(_("failed to restore old SIGWINCH sigact"));
74 if (sigprocmask(SIG_SETMASK
, oblockedp
, nullptr))
75 ohshite(_("failed to restore old signal mask"));
80 baselist::sigwinch_mask(int how
)
83 sigemptyset(&sigwinchset
);
84 sigaddset(&sigwinchset
,SIGWINCH
);
86 int rc
= sigprocmask(how
, &sigwinchset
, nullptr);
88 if (how
== SIG_UNBLOCK
)
89 ohshite(_("failed to unblock SIGWINCH"));
91 ohshite(_("failed to block SIGWINCH"));
96 baselist::setupsigwinch()
98 struct sigaction
*osigactp
= new(struct sigaction
);
99 sigset_t
*oblockedp
= new(sigset_t
);
100 if (sigprocmask(0, nullptr, oblockedp
))
101 ohshite(_("failed to get old signal mask"));
102 if (sigaction(SIGWINCH
, nullptr, osigactp
))
103 ohshite(_("failed to get old SIGWINCH sigact"));
105 push_cleanup(cu_sigwinch
, ~0, nullptr, 0, 2, osigactp
, oblockedp
);
107 sigwinch_mask(SIG_BLOCK
);
109 struct sigaction nsigact
;
110 memset(&nsigact
,0,sizeof(nsigact
));
111 nsigact
.sa_handler
= sigwinchhandler
;
112 sigemptyset(&nsigact
.sa_mask
);
113 //nsigact.sa_flags= SA_INTERRUPT;
114 if (sigaction(SIGWINCH
, &nsigact
, nullptr))
115 ohshite(_("failed to set new SIGWINCH sigact"));
119 baselist::add_column(column
&col
, const char *title
, int width
)
125 col_cur_x
+= col
.width
+ gap_width
;
129 baselist::end_column(column
&col
, const char *title
)
133 col
.width
= total_width
- col
.x
;
135 col_cur_x
+= col
.width
+ gap_width
;
139 baselist::draw_column_head(column
&col
)
141 mvwaddnstr(colheadspad
, 0, col
.x
, col
.title
, col
.width
);
145 baselist::draw_column_sep(column
&col
, int y
)
147 mvwaddch(listpad
, y
, col
.x
- 1, ' ');
151 baselist::draw_column_item(column
&col
, int y
, const char *item
)
153 mvwprintw(listpad
, y
, col
.x
, "%-*.*s", col
.width
, col
.width
, item
);
156 void baselist::setheights() {
157 int y
= ymax
- (title_height
+ colheads_height
+ thisstate_height
);
159 if (showinfo
==2 && y
>=7) {
163 } else if (showinfo
==1 && y
>=10) {
165 info_height
= (y
-1)/2;
172 colheads_row
= title_height
;
173 list_row
= colheads_row
+ colheads_height
;
174 thisstate_row
= list_row
+ list_height
;
175 info_row
= thisstate_row
+ thisstate_height
;
176 whatinfo_row
= ymax
- 1;
179 void baselist::startdisplay() {
180 debug(dbg_general
, "baselist[%p]::startdisplay()", this);
181 cbreak(); noecho(); nonl(); keypad(stdscr
,TRUE
);
182 clear(); wnoutrefresh(stdscr
);
185 if (has_colors() && start_color()==OK
&& COLOR_PAIRS
>= numscreenparts
) {
187 printf("allocing\n");
188 for (i
= 1; i
< numscreenparts
; i
++) {
189 if (init_pair(i
, color
[i
].fore
, color
[i
].back
) != OK
)
190 ohshite(_("failed to allocate colour pair"));
191 part_attr
[i
] = COLOR_PAIR(i
) | color
[i
].attr
;
194 /* User defined attributes for B&W mode are not currently supported. */
195 part_attr
[title
] = A_REVERSE
;
196 part_attr
[thisstate
] = A_STANDOUT
;
198 part_attr
[listsel
] = A_STANDOUT
;
199 part_attr
[selstate
] = A_BOLD
;
200 part_attr
[selstatesel
] = A_STANDOUT
;
201 part_attr
[colheads
]= A_BOLD
;
202 part_attr
[query
] = part_attr
[title
];
203 part_attr
[info_body
] = part_attr
[list
];
204 part_attr
[info_head
] = A_BOLD
;
205 part_attr
[whatinfo
] = part_attr
[thisstate
];
206 part_attr
[helpscreen
] = A_NORMAL
;
209 // set up windows and pads, based on screen size
210 getmaxyx(stdscr
,ymax
,xmax
);
211 title_height
= ymax
>=6;
212 colheads_height
= ymax
>=5;
213 thisstate_height
= ymax
>=3;
218 titlewin
= newwin(1,xmax
, 0,0);
219 if (!titlewin
) ohshite(_("failed to create title window"));
220 wattrset(titlewin
, part_attr
[title
]);
222 whatinfowin
= newwin(1,xmax
, whatinfo_row
,0);
223 if (!whatinfowin
) ohshite(_("failed to create whatinfo window"));
224 wattrset(whatinfowin
, part_attr
[whatinfo
]);
226 listpad
= newpad(ymax
, total_width
);
227 if (!listpad
) ohshite(_("failed to create baselist pad"));
229 colheadspad
= newpad(1, total_width
);
230 if (!colheadspad
) ohshite(_("failed to create heading pad"));
231 wattrset(colheadspad
, part_attr
[colheads
]);
233 thisstatepad
= newpad(1, total_width
);
234 if (!thisstatepad
) ohshite(_("failed to create thisstate pad"));
235 wattrset(thisstatepad
, part_attr
[thisstate
]);
237 infopad
= newpad(MAX_DISPLAY_INFO
, total_width
);
238 if (!infopad
) ohshite(_("failed to create info pad"));
239 wattrset(infopad
, part_attr
[info_body
]);
240 wbkgdset(infopad
, ' ' | part_attr
[info_body
]);
242 querywin
= newwin(1,xmax
,ymax
-1,0);
243 if (!querywin
) ohshite(_("failed to create query window"));
244 wbkgdset(querywin
, ' ' | part_attr
[query
]);
246 if (cursorline
>= topofscreen
+ list_height
) topofscreen
= cursorline
;
247 if (topofscreen
> nitems
- list_height
) topofscreen
= nitems
- list_height
;
248 if (topofscreen
< 0) topofscreen
= 0;
250 infotopofscreen
= 0; leftofscreen
= 0;
255 "baselist::startdisplay() done ...\n\n"
256 " xmax=%d, ymax=%d;\n\n"
257 " title_height=%d, colheads_height=%d, list_height=%d;\n"
258 " thisstate_height=%d, info_height=%d, whatinfo_height=%d;\n\n"
259 " colheads_row=%d, thisstate_row=%d, info_row=%d;\n"
260 " whatinfo_row=%d, list_row=%d;\n\n",
261 xmax
, ymax
, title_height
, colheads_height
, list_height
,
262 thisstate_height
, info_height
, whatinfo_height
,
263 colheads_row
, thisstate_row
, info_row
, whatinfo_row
, list_row
);
266 void baselist::enddisplay() {
271 delwin(thisstatepad
);
273 wmove(stdscr
,ymax
,0); wclrtoeol(stdscr
);
278 void baselist::redrawall() {
281 wattrset(listpad
, part_attr
[list
]);
283 ldrawnstart
= ldrawnend
= -1; // start is first drawn; end is first undrawn; -1=none
289 void baselist::redraw1item(int index
) {
290 redraw1itemsel(index
, index
== cursorline
);
293 baselist::baselist(keybindings
*kb
) {
294 debug(dbg_general
, "baselist[%p]::baselist()", this);
301 total_width
= max(TOTAL_LIST_WIDTH
, COLS
);
311 thisstate_height
= 0;
326 colheadspad
= nullptr;
327 thisstatepad
= nullptr;
330 whatinfowin
= nullptr;
340 void baselist::itd_keys() {
341 whatinfovb(_("Keybindings"));
343 const int givek
= xmax
/3;
344 bindings
->describestart();
346 while ((ta
= bindings
->describenext()) != nullptr) {
347 const char **tap
= ta
+1;
349 waddstr(infopad
, gettext(*tap
));
350 tap
++; if (!*tap
) break;
351 waddstr(infopad
, ", ");
356 mvwaddstr(infopad
, y
,givek
, ta
[0]);
357 waddch(infopad
,'\n');
362 void baselist::dosearch() {
364 debug(dbg_general
, "baselist[%p]::dosearch(); searchstring='%s'",
366 for (offset
= 1, index
= max(topofscreen
, cursorline
+ 1);
369 if (index
>= nitems
) index
-= nitems
;
370 if (matchsearch(index
)) {
371 topofscreen
= index
-1;
372 if (topofscreen
> nitems
- list_height
) topofscreen
= nitems
-list_height
;
373 if (topofscreen
< 0) topofscreen
= 0;
381 void baselist::refreshinfo() {
382 pnoutrefresh(infopad
, infotopofscreen
,leftofscreen
, info_row
,0,
383 min(info_row
+ info_height
- 1, info_row
+ MAX_DISPLAY_INFO
- 1),
384 min(total_width
- leftofscreen
- 1, xmax
- 1));
386 if (whatinfo_height
) {
387 mywerase(whatinfowin
);
388 mvwaddstr(whatinfowin
,0,0, whatinfovb
.string());
389 if (infolines
> info_height
) {
390 wprintw(whatinfowin
,_(" -- %d%%, press "),
391 (int)((infotopofscreen
+ info_height
) * 100.0 / infolines
));
392 if (infotopofscreen
+ info_height
< infolines
) {
393 wprintw(whatinfowin
,_("%s for more"), bindings
->find("iscrollon"));
394 if (infotopofscreen
) waddstr(whatinfowin
, ", ");
397 wprintw(whatinfowin
, _("%s to go back"),bindings
->find("iscrollback"));
398 waddch(whatinfowin
,'.');
400 wnoutrefresh(whatinfowin
);
404 void baselist::wordwrapinfo(int offset
, const char *m
) {
406 debug(dbg_general
, "baselist[%p]::wordwrapinfo(%d, '%s')", this, offset
, m
);
407 bool wrapping
= false;
410 int offleft
=offset
; while (*m
== ' ' && offleft
>0) { m
++; offleft
--; }
411 const char *p
= strchr(m
,'\n');
412 int l
= p
? (int)(p
-m
) : strlen(m
);
413 while (l
&& c_isspace(m
[l
- 1]))
415 if (!l
|| (*m
== '.' && l
== 1)) {
416 if (wrapping
) waddch(infopad
,'\n');
417 waddch(infopad
, '\n');
419 } else if (*m
== ' ' || usemax
< 10) {
420 if (wrapping
) waddch(infopad
,'\n');
421 waddnstr(infopad
, m
, l
);
422 waddch(infopad
, '\n');
425 int x
, y DPKG_ATTR_UNUSED
;
430 waddch(infopad
,'\n');
437 int dosend
= usemax
-x
;
442 while (i
> 0 && m
[i
] != ' ') i
--;
443 if (i
> 0 || x
> 0) dosend
=i
;
445 if (dosend
) waddnstr(infopad
, m
, dosend
);
446 while (dosend
< l
&& m
[dosend
] == ' ') dosend
++;
447 l
-= dosend
; m
+= dosend
;
449 waddch(infopad
,'\n');
454 if (getcury(infopad
) == (MAX_DISPLAY_INFO
- 1)) {
456 "[The package description is too long and has been truncated...]");
461 debug(dbg_general
, "baselist[%p]::wordwrapinfo() done", this);
464 baselist::~baselist() { }