2 * FBPAD FRAMEBUFFER VIRTUAL TERMINAL
4 * Copyright (C) 2009-2018 Ali Gholami Rudi <ali at rudi dot ir>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include <sys/ioctl.h>
34 #define CTRLKEY(x) ((x) - 96)
35 #define POLLFLAGS (POLLIN | POLLHUP | POLLERR | POLLNVAL)
36 #define NTAGS (sizeof(tags) - 1)
37 #define NTERMS (NTAGS * 2)
38 #define TERMOPEN(i) (terms[i].fd)
39 #define TERMSNAP(i) (strchr(TAGS_SAVED, tags[(i) % NTAGS]))
41 static char tags
[] = TAGS
;
42 static struct term terms
[NTERMS
];
43 static int tops
[NTAGS
]; /* top terms of tags */
44 static int ctag
; /* current tag */
45 static int ltag
; /* the last tag */
47 static int hidden
; /* do not touch the framebuffer */
49 static int taglock
; /* disable tag switching */
50 static char pass
[1024];
52 static int cmdmode
; /* execute a command and exit */
54 static int readchar(void)
57 if (read(0, &b
, 1) > 0)
58 return (unsigned char) b
;
62 static int cterm(void)
64 return tops
[ctag
] * NTAGS
+ ctag
;
67 static int altterm(int n
)
69 return n
< NTAGS
? n
+ NTAGS
: n
- NTAGS
;
72 static int nextterm(void)
74 int n
= (cterm() + 1) % NTERMS
;
75 while (n
!= cterm()) {
83 static struct term
*mainterm(void)
85 return TERMOPEN(cterm()) ? &terms
[cterm()] : NULL
;
88 static void switchterm(int oidx
, int nidx
, int show
, int save
, int load
)
90 if (save
&& TERMOPEN(oidx
) && TERMSNAP(oidx
))
92 term_save(&terms
[oidx
]);
93 term_load(&terms
[nidx
], show
);
95 term_redraw(load
&& (!TERMOPEN(nidx
) || !TERMSNAP(nidx
) ||
99 static void showterm(int n
)
101 if (cterm() == n
|| cmdmode
)
103 if (taglock
&& ctag
!= n
% NTAGS
)
105 if (ctag
!= n
% NTAGS
)
107 switchterm(cterm(), n
, !hidden
, !hidden
, !hidden
);
109 tops
[ctag
] = n
/ NTAGS
;
112 static void showtag(int n
)
114 showterm(tops
[n
] * NTAGS
+ n
);
117 static void execterm(char **args
)
123 static void listtags(void)
125 /* colors for tags based on their number of terminals */
126 int colors
[] = {COLOR7
, FGCOLOR
, FGCOLOR
| FN_B
};
128 int r
= pad_rows() - 1;
130 pad_put('T', r
, c
++, FGCOLOR
, BGCOLOR
);
131 pad_put('A', r
, c
++, FGCOLOR
, BGCOLOR
);
132 pad_put('G', r
, c
++, FGCOLOR
, BGCOLOR
);
133 pad_put('S', r
, c
++, FGCOLOR
, BGCOLOR
);
134 pad_put(':', r
, c
++, FGCOLOR
, BGCOLOR
);
135 pad_put(' ', r
, c
++, FGCOLOR
, BGCOLOR
);
136 for (i
= 0; i
< NTAGS
; i
++) {
140 if (TERMOPEN(altterm(i
)))
142 pad_put(i
== ctag
? '(' : ' ', r
, c
++, FGCOLOR
, BGCOLOR
);
144 pad_put(tags
[i
], r
, c
++, !nt
? BGCOLOR
: colors
[nt
], colors
[0]);
146 pad_put(tags
[i
], r
, c
++, colors
[nt
], BGCOLOR
);
147 pad_put(i
== ctag
? ')' : ' ', r
, c
++, FGCOLOR
, BGCOLOR
);
151 static void directkey(void)
153 char *shell
[32] = SHELL
;
154 char *mail
[32] = MAIL
;
155 char *editor
[32] = EDITOR
;
157 if (PASS
&& locked
) {
159 pass
[passlen
] = '\0';
160 if (!strcmp(PASS
, pass
))
165 if (isprint(c
) && passlen
+ 1 < sizeof(pass
))
170 switch ((c
= readchar())) {
182 showterm(altterm(cterm()));
191 if (nextterm() != cterm())
192 showterm(nextterm());
208 taglock
= 1 - taglock
;
211 term_scrl(pad_rows() / 2);
214 term_scrl(-pad_rows() / 2);
217 if (strchr(tags
, c
)) {
218 showtag(strchr(tags
, c
) - tags
);
225 if (c
!= -1 && mainterm())
229 static void peepterm(int termid
)
231 if (termid
!= cterm())
232 switchterm(cterm(), termid
, 0, 0, 0);
235 static void peepback(int termid
)
237 if (termid
!= cterm())
238 switchterm(termid
, cterm(), !hidden
, 0, 0);
241 static int pollterms(void)
243 struct pollfd ufds
[NTERMS
+ 1];
244 int term_idx
[NTERMS
+ 1];
248 ufds
[0].events
= POLLIN
;
249 for (i
= 0; i
< NTERMS
; i
++) {
251 ufds
[n
].fd
= terms
[i
].fd
;
252 ufds
[n
].events
= POLLIN
;
256 if (poll(ufds
, n
, 1000) < 1)
258 if (ufds
[0].revents
& (POLLFLAGS
& ~POLLIN
))
260 if (ufds
[0].revents
& POLLIN
)
262 for (i
= 1; i
< n
; i
++) {
263 if (!(ufds
[i
].revents
& POLLFLAGS
))
265 peepterm(term_idx
[i
]);
266 if (ufds
[i
].revents
& POLLIN
) {
269 scr_free(term_idx
[i
]);
274 peepback(term_idx
[i
]);
279 static void mainloop(char **args
)
281 struct termios oldtermios
, termios
;
282 tcgetattr(0, &termios
);
283 oldtermios
= termios
;
285 tcsetattr(0, TCSAFLUSH
, &termios
);
286 term_load(&terms
[cterm()], 1);
295 tcsetattr(0, 0, &oldtermios
);
298 static void signalreceived(int n
)
305 switchterm(cterm(), cterm(), 0, 1, 0);
306 ioctl(0, VT_RELDISP
, 1);
311 switchterm(cterm(), cterm(), 1, 0, 1);
314 while (waitpid(-1, NULL
, WNOHANG
) > 0)
320 static void signalsetup(void)
323 vtm
.mode
= VT_PROCESS
;
325 vtm
.relsig
= SIGUSR1
;
326 vtm
.acqsig
= SIGUSR2
;
328 signal(SIGUSR1
, signalreceived
);
329 signal(SIGUSR2
, signalreceived
);
330 signal(SIGCHLD
, signalreceived
);
331 ioctl(0, VT_SETMODE
, &vtm
);
334 int main(int argc
, char **argv
)
336 char *hide
= "\x1b[2J\x1b[H\x1b[?25l";
337 char *show
= "\x1b[?25h";
338 char **args
= argv
+ 1;
339 if (fb_init(FBDEV
)) {
340 fprintf(stderr
, "fbpad: failed to initialize the framebuffer\n");
343 if (sizeof(fbval_t
) != FBM_BPP(fb_mode())) {
344 fprintf(stderr
, "fbpad: fbval_t does not match framebuffer depth\n");
348 fprintf(stderr
, "fbpad: cannot find fonts\n");
351 write(1, hide
, strlen(hide
));
353 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
) | O_NONBLOCK
);
354 while (args
[0] && args
[0][0] == '-')
356 mainloop(args
[0] ? args
: NULL
);
357 write(1, show
, strlen(show
));