2 * FBPAD FRAMEBUFFER VIRTUAL TERMINAL
4 * Copyright (C) 2009-2021 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 split
[NTAGS
]; /* terms are shown together */
45 static int ctag
; /* current tag */
46 static int ltag
; /* the last tag */
48 static int hidden
; /* do not touch the framebuffer */
50 static int taglock
; /* disable tag switching */
51 static char pass
[1024];
53 static int cmdmode
; /* execute a command and exit */
55 static int readchar(void)
58 if (read(0, &b
, 1) > 0)
59 return (unsigned char) b
;
63 /* the current terminal */
64 static int cterm(void)
66 return tops
[ctag
] * NTAGS
+ ctag
;
69 /* the other terminal in the same tag */
70 static int aterm(int n
)
72 return n
< NTAGS
? n
+ NTAGS
: n
- NTAGS
;
75 /* the next terminal */
76 static int nterm(void)
78 int n
= (cterm() + 1) % NTERMS
;
79 while (n
!= cterm()) {
87 static struct term
*fterm_main(void)
89 return TERMOPEN(cterm()) ? &terms
[cterm()] : NULL
;
92 static void fterm_conf(int idx
)
94 int hrows
= (fb_rows() - 4) / 2;
95 int hcols
= (fb_cols() - 4) / 2;
96 int tag
= idx
% NTAGS
;
97 int top
= idx
< NTAGS
;
99 pad_conf(0, 0, fb_rows(), fb_cols());
101 pad_conf(top
? 1 : hrows
+ 3, 1, hrows
, fb_cols() - 2);
103 pad_conf(1, top
? 1 : hcols
+ 3, fb_rows() - 2, hcols
);
106 static void fterm_switch(int oidx
, int nidx
, int show
, int save
, int load
)
108 int otag
= oidx
% NTAGS
;
109 int ntag
= nidx
% NTAGS
;
110 int bothvisible
= otag
== ntag
&& split
[otag
];
111 if (save
&& TERMOPEN(oidx
) && TERMSNAP(oidx
) && !bothvisible
)
112 scr_snap(split
[otag
] ? otag
: oidx
);
113 term_save(&terms
[oidx
]);
114 if (show
&& split
[otag
] && otag
== ntag
)
117 term_load(&terms
[nidx
], show
);
119 term_redraw(load
&& (load
< 0 || !TERMOPEN(nidx
) || !TERMSNAP(nidx
) ||
120 (!bothvisible
&& scr_load(split
[ntag
] ? ntag
: nidx
))));
121 if (show
&& split
[ntag
])
122 pad_border(0xff0000);
125 static void fterm_show(int n
)
127 if (cterm() == n
|| cmdmode
)
129 if (taglock
&& ctag
!= n
% NTAGS
)
131 if (ctag
!= n
% NTAGS
)
133 if (ctag
== n
% NTAGS
) {
134 if (split
[n
% NTAGS
])
135 fterm_switch(cterm(), n
, !hidden
, 0, 0);
137 fterm_switch(cterm(), n
, !hidden
, !hidden
, !hidden
);
139 fterm_switch(cterm(), n
, !hidden
, !hidden
, !hidden
);
140 if (split
[n
% NTAGS
]) {
141 fterm_switch(n
, aterm(n
), !hidden
, 0, !hidden
);
142 fterm_switch(aterm(n
), n
, !hidden
, 0, 0);
146 tops
[ctag
] = n
/ NTAGS
;
149 static void tag_split(int n
)
152 fterm_switch(cterm(), aterm(cterm()), !hidden
, 0, -!hidden
);
153 fterm_switch(aterm(cterm()), cterm(), !hidden
, !hidden
, -!hidden
);
156 static void tag_show(int n
)
158 fterm_show(tops
[n
] * NTAGS
+ n
);
161 static void fterm_exec(char **args
)
167 static void tag_list(void)
169 /* colors for tags based on their number of terminals */
170 int colors
[] = {COLOR7
, FGCOLOR
, FGCOLOR
| FN_B
};
172 int r
= pad_rows() - 1;
174 pad_put('T', r
, c
++, FGCOLOR
, BGCOLOR
);
175 pad_put('A', r
, c
++, FGCOLOR
, BGCOLOR
);
176 pad_put('G', r
, c
++, FGCOLOR
, BGCOLOR
);
177 pad_put('S', r
, c
++, FGCOLOR
, BGCOLOR
);
178 pad_put(':', r
, c
++, FGCOLOR
, BGCOLOR
);
179 pad_put(' ', r
, c
++, FGCOLOR
, BGCOLOR
);
180 for (i
= 0; i
< NTAGS
&& c
+ 2 < pad_cols(); i
++) {
184 if (TERMOPEN(aterm(i
)))
186 pad_put(i
== ctag
? '(' : ' ', r
, c
++, FGCOLOR
, BGCOLOR
);
188 pad_put(tags
[i
], r
, c
++, !nt
? BGCOLOR
: colors
[nt
], colors
[0]);
190 pad_put(tags
[i
], r
, c
++, colors
[nt
], BGCOLOR
);
191 pad_put(i
== ctag
? ')' : ' ', r
, c
++, FGCOLOR
, BGCOLOR
);
195 static void directkey(void)
197 char *shell
[32] = SHELL
;
198 char *mail
[32] = MAIL
;
199 char *editor
[32] = EDITOR
;
201 if (PASS
&& locked
) {
203 pass
[passlen
] = '\0';
204 if (!strcmp(PASS
, pass
))
209 if (isprint(c
) && passlen
+ 1 < sizeof(pass
))
214 switch ((c
= readchar())) {
226 fterm_show(aterm(cterm()));
235 if (nterm() != cterm())
252 taglock
= 1 - taglock
;
255 term_scrl(pad_rows() / 2);
258 term_scrl(-pad_rows() / 2);
261 tag_split(split
[ctag
] == 1 ? 2 : 1);
267 if (strchr(tags
, c
)) {
268 tag_show(strchr(tags
, c
) - tags
);
275 if (c
!= -1 && fterm_main())
279 static void peepterm(int termid
)
281 int visible
= !hidden
&& ctag
== (termid
% NTAGS
) && split
[ctag
];
282 if (termid
!= cterm())
283 fterm_switch(cterm(), termid
, visible
, 0, 0);
286 static void peepback(int termid
)
288 if (termid
!= cterm())
289 fterm_switch(termid
, cterm(), !hidden
, 0, 0);
292 static int pollterms(void)
294 struct pollfd ufds
[NTERMS
+ 1];
295 int term_idx
[NTERMS
+ 1];
299 ufds
[0].events
= POLLIN
;
300 for (i
= 0; i
< NTERMS
; i
++) {
302 ufds
[n
].fd
= terms
[i
].fd
;
303 ufds
[n
].events
= POLLIN
;
307 if (poll(ufds
, n
, 1000) < 1)
309 if (ufds
[0].revents
& (POLLFLAGS
& ~POLLIN
))
311 if (ufds
[0].revents
& POLLIN
)
313 for (i
= 1; i
< n
; i
++) {
314 if (!(ufds
[i
].revents
& POLLFLAGS
))
316 peepterm(term_idx
[i
]);
317 if (ufds
[i
].revents
& POLLIN
) {
320 scr_free(term_idx
[i
]);
325 peepback(term_idx
[i
]);
330 static void mainloop(char **args
)
332 struct termios oldtermios
, termios
;
333 tcgetattr(0, &termios
);
334 oldtermios
= termios
;
336 tcsetattr(0, TCSAFLUSH
, &termios
);
337 term_load(&terms
[cterm()], 1);
346 tcsetattr(0, 0, &oldtermios
);
349 static void signalreceived(int n
)
356 fterm_switch(cterm(), cterm(), 0, 1, 0);
357 ioctl(0, VT_RELDISP
, 1);
362 fterm_switch(cterm(), cterm(), 1, 0, 1);
365 while (waitpid(-1, NULL
, WNOHANG
) > 0)
371 static void signalsetup(void)
374 vtm
.mode
= VT_PROCESS
;
376 vtm
.relsig
= SIGUSR1
;
377 vtm
.acqsig
= SIGUSR2
;
379 signal(SIGUSR1
, signalreceived
);
380 signal(SIGUSR2
, signalreceived
);
381 signal(SIGCHLD
, signalreceived
);
382 ioctl(0, VT_SETMODE
, &vtm
);
385 int main(int argc
, char **argv
)
387 char *hide
= "\x1b[2J\x1b[H\x1b[?25l";
388 char *show
= "\x1b[?25h";
389 char **args
= argv
+ 1;
390 if (fb_init(FBDEV
)) {
391 fprintf(stderr
, "fbpad: failed to initialize the framebuffer\n");
395 fprintf(stderr
, "fbpad: cannot find fonts\n");
398 write(1, hide
, strlen(hide
));
400 fcntl(0, F_SETFL
, fcntl(0, F_GETFL
) | O_NONBLOCK
);
401 while (args
[0] && args
[0][0] == '-')
403 mainloop(args
[0] ? args
: NULL
);
404 write(1, show
, strlen(show
));