2 * fbpad - a small framebuffer virtual terminal
4 * Copyright (C) 2009-2015 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the Modified BSD license.
15 #include <sys/ioctl.h>
24 #define CTRLKEY(x) ((x) - 96)
25 #define POLLFLAGS (POLLIN | POLLHUP | POLLERR | POLLNVAL)
26 #define NTAGS (sizeof(tags) - 1)
27 #define NTERMS (NTAGS * 2)
28 #define TERMOPEN(i) (terms[i].fd)
29 #define TERMSNAP(i) (strchr(TAGS_SAVED, tags[(i) % NTAGS]))
31 static char tags
[] = TAGS
;
32 static struct term terms
[NTERMS
];
33 static int tops
[NTAGS
]; /* top terms of tags */
34 static int ctag
; /* current tag */
35 static int ltag
; /* the last tag */
37 static int hidden
; /* do not touch the framebuffer */
39 static int taglock
; /* disable tag switching */
40 static char pass
[1024];
42 static int cmdmode
; /* execute a command and exit */
43 static int altfont
; /* using alternative font set */
45 static int readchar(void)
48 if (read(0, &b
, 1) > 0)
49 return (unsigned char) b
;
53 static int cterm(void)
55 return tops
[ctag
] * NTAGS
+ ctag
;
58 static int altterm(int n
)
60 return n
< NTAGS
? n
+ NTAGS
: n
- NTAGS
;
63 static int nextterm(void)
65 int n
= (cterm() + 1) % NTERMS
;
66 while (n
!= cterm()) {
74 static struct term
*mainterm(void)
76 return TERMOPEN(cterm()) ? &terms
[cterm()] : NULL
;
79 static void switchterm(int oidx
, int nidx
, int show
, int save
, int load
)
81 if (save
&& TERMOPEN(oidx
) && TERMSNAP(oidx
))
83 term_save(&terms
[oidx
]);
84 term_load(&terms
[nidx
], show
);
86 term_redraw(load
&& (!TERMOPEN(nidx
) || !TERMSNAP(nidx
) ||
90 static void showterm(int n
)
92 if (cterm() == n
|| cmdmode
)
94 if (taglock
&& ctag
!= n
% NTAGS
)
96 if (ctag
!= n
% NTAGS
)
98 switchterm(cterm(), n
, !hidden
, !hidden
, !hidden
);
100 tops
[ctag
] = n
/ NTAGS
;
103 static void showtag(int n
)
105 showterm(tops
[n
] * NTAGS
+ n
);
108 static void execterm(char **args
)
114 static void listtags(void)
116 int c
= pad_cols() - 1;
119 for (i
= 0; i
< NTAGS
; i
++) {
120 int fg
= 8, fglow
= TERMSNAP(i
) ? 218 : 150;
121 int bg
= i
== ctag
? 193 : 225;
122 int t1
= tops
[i
] * NTAGS
+ i
;
123 int t2
= (1 - tops
[i
]) * NTAGS
+ i
;
124 pad_put(tags
[i
], r
+ i
, c
- 1, (TERMOPEN(t1
) ? fg
: fglow
) | FN_B
, bg
);
125 pad_put(tags
[i
], r
+ i
, c
, (TERMOPEN(t2
) ? fg
: bg
) | FN_B
, bg
);
129 static void directkey(void)
131 char *shell
[32] = SHELL
;
132 char *mail
[32] = MAIL
;
133 char *editor
[32] = EDITOR
;
135 if (PASS
&& locked
) {
137 pass
[passlen
] = '\0';
138 if (!strcmp(PASS
, pass
))
143 if (isprint(c
) && passlen
+ 1 < sizeof(pass
))
148 switch ((c
= readchar())) {
160 showterm(altterm(cterm()));
169 if (nextterm() != cterm())
170 showterm(nextterm());
182 altfont
= 1 - altfont
;
184 pad_font(FR0
, FI0
, FB0
);
186 pad_font(FR
, FI
, FB
);
194 taglock
= 1 - taglock
;
197 term_scrl(pad_rows() / 2);
200 term_scrl(-pad_rows() / 2);
203 if (strchr(tags
, c
)) {
204 showtag(strchr(tags
, c
) - tags
);
211 if (c
!= -1 && mainterm())
215 static void peepterm(int termid
)
217 if (termid
!= cterm())
218 switchterm(cterm(), termid
, 0, 0, 0);
221 static void peepback(int termid
)
223 if (termid
!= cterm())
224 switchterm(termid
, cterm(), !hidden
, 0, 0);
227 static int pollterms(void)
229 struct pollfd ufds
[NTERMS
+ 1];
230 int term_idx
[NTERMS
+ 1];
234 ufds
[0].events
= POLLIN
;
235 for (i
= 0; i
< NTERMS
; i
++) {
237 ufds
[n
].fd
= terms
[i
].fd
;
238 ufds
[n
].events
= POLLIN
;
242 if (poll(ufds
, n
, 1000) < 1)
244 if (ufds
[0].revents
& (POLLFLAGS
& ~POLLIN
))
246 if (ufds
[0].revents
& POLLIN
)
248 for (i
= 1; i
< n
; i
++) {
249 if (!(ufds
[i
].revents
& POLLFLAGS
))
251 peepterm(term_idx
[i
]);
252 if (ufds
[i
].revents
& POLLIN
) {
255 scr_free(term_idx
[i
]);
260 peepback(term_idx
[i
]);
265 static void mainloop(char **args
)
267 struct termios oldtermios
, termios
;
268 tcgetattr(0, &termios
);
269 oldtermios
= termios
;
271 tcsetattr(0, TCSAFLUSH
, &termios
);
272 term_load(&terms
[cterm()], 1);
281 tcsetattr(0, 0, &oldtermios
);
284 static void signalreceived(int n
);
285 static void signalregister(void)
287 signal(SIGUSR1
, signalreceived
);
288 signal(SIGUSR2
, signalreceived
);
289 signal(SIGCHLD
, signalreceived
);
292 static void signalreceived(int n
)
296 /* racy, new signals may arrive before re-registeration */
301 switchterm(cterm(), cterm(), 0, 1, 0);
302 ioctl(0, VT_RELDISP
, 1);
307 switchterm(cterm(), cterm(), 1, 0, 1);
310 while (waitpid(-1, NULL
, WNOHANG
) > 0)
316 static void signalsetup(void)
319 vtm
.mode
= VT_PROCESS
;
321 vtm
.relsig
= SIGUSR1
;
322 vtm
.acqsig
= SIGUSR2
;
325 ioctl(0, VT_SETMODE
, &vtm
);
328 int main(int argc
, char **argv
)
330 char *hide
= "\x1b[2J\x1b[H\x1b[?25l";
331 char *show
= "\x1b[?25h";
332 char **args
= argv
+ 1;
333 if (fb_init(FBDEV
)) {
334 fprintf(stderr
, "fbpad: failed to initialize the framebuffer\n");
337 if (sizeof(fbval_t
) != FBM_BPP(fb_mode())) {
338 fprintf(stderr
, "fbpad: fbval_t does not match framebuffer depth\n");
342 fprintf(stderr
, "fbpad: cannot find fonts\n");
345 write(1, hide
, strlen(hide
));
347 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
) | O_NONBLOCK
);
348 while (args
[0] && args
[0][0] == '-')
350 mainloop(args
[0] ? args
: NULL
);
351 write(1, show
, strlen(show
));