catpoint.c - catpoint - Catpoint simple presenting software.
(HTM) git clone git://r-36.net/catpoint
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
catpoint.c (4824B)
---
1 /* See LICENSE file for license details. */
2
3 #include <sys/mman.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7
8 #include <curses.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <locale.h>
12 #include <signal.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 void die(const char *, ...);
20
21 char *currentslidep, **slidefiles; /* the slides */
22 int nslides, currentslide, currentslidelen;
23
24 volatile sig_atomic_t slidechanged = 1;
25
26 void
27 unloadcurrentslide(void)
28 {
29 if (currentslidep == NULL)
30 return;
31
32 if (munmap(currentslidep, currentslidelen) < 0)
33 die("munmap: %s", slidefiles[currentslide]);
34 }
35
36 void
37 setupwin(void)
38 {
39 initscr();
40 cbreak();
41 noecho();
42 nonl();
43 intrflush(stdscr, FALSE);
44 keypad(stdscr, TRUE);
45 curs_set(FALSE); /* hide cursor */
46 }
47
48 void
49 cleanup(void)
50 {
51 unloadcurrentslide();
52
53 endwin(); /* restore terminal */
54 }
55
56 /* print to stderr, call cleanup() and _exit(). */
57 void
58 die(const char *fmt, ...)
59 {
60 va_list ap;
61 int saved_errno;
62
63 saved_errno = errno;
64 cleanup();
65
66 va_start(ap, fmt);
67 vfprintf(stderr, fmt, ap);
68 va_end(ap);
69
70 if (saved_errno)
71 fprintf(stderr, ": %s", strerror(saved_errno));
72 fflush(stderr);
73 (void)!write(2, "\n", 1);
74
75 _exit(1);
76 }
77
78 void
79 quit(int sig)
80 {
81 cleanup();
82 _exit(128 + sig);
83 }
84
85 void
86 executeslide(char **argv)
87 {
88 pid_t pid;
89
90 endwin();
91
92 fprintf(stderr, "\x1b[H\x1b[J");
93 fflush(stderr);
94
95 switch ((pid = fork())) {
96 case 0:
97 execvp(argv[0], argv);
98 case -1:
99 perror(argv[0]);
100 break;
101 default:
102 waitpid(pid, NULL, 0);
103 }
104
105 setupwin();
106 }
107
108 void
109 loadcurrentslide(char **argv, int slide)
110 {
111 struct stat statbuf;
112 int fd;
113
114 unloadcurrentslide();
115
116 fd = open(slidefiles[slide], O_RDONLY, 0);
117 if (fd < 0)
118 die("open: %s", slidefiles[slide]);
119 if (fstat(fd, &statbuf) < 0)
120 die("fstat: %s", slidefiles[slide]);
121 currentslidep = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
122 if (currentslidep == MAP_FAILED) {
123 currentslidep = NULL;
124 die("mmap: %s", slidefiles[slide]);
125 }
126 currentslidelen = statbuf.st_size;
127 close(fd);
128 }
129
130 void
131 reloadcurrentslide(int sig)
132 {
133 /*
134 * Keep this out of SIGHUP, in case this is used somewhere else.
135 */
136 slidechanged = 1;
137
138 if (sig == SIGHUP) {
139 /* Make ncurses redisplay slide. */
140 if (raise(SIGWINCH) < 0)
141 die("raise");
142 }
143 }
144
145 void
146 setsignal()
147 {
148 struct sigaction sa;
149
150 memset(&sa, 0, sizeof(sa));
151 sigemptyset(&sa.sa_mask);
152 sa.sa_flags = 0;
153
154 sa.sa_handler = quit;
155 sigaction(SIGINT, &sa, NULL);
156 sigaction(SIGQUIT, &sa, NULL);
157 sigaction(SIGTERM, &sa, NULL);
158
159 sa.sa_handler = reloadcurrentslide;
160 sigaction(SIGHUP, &sa, NULL);
161 }
162
163 int
164 main(int argc, char *argv[])
165 {
166 int c;
167
168 if (argc == 1) {
169 errno = 0;
170 die("usage: %s file ...", argv[0]);
171 }
172
173 slidefiles = ++argv;
174 nslides = --argc;
175
176 setsignal();
177 setlocale(LC_ALL, "");
178
179 /* start */
180 currentslide = 0;
181 currentslidep = NULL;
182 currentslidelen = 0;
183
184 /* init curses */
185 setupwin();
186
187 show:
188 /* display slide if changed */
189 if (slidechanged) {
190 slidechanged = 0;
191 loadcurrentslide(slidefiles, currentslide);
192 }
193 clear();
194 refresh();
195
196 if (access(slidefiles[currentslide], X_OK) == 0) {
197 executeslide(slidefiles + currentslide);
198 } else {
199 printw("%.*s", currentslidelen, currentslidep);
200 }
201
202 again:
203 c = getch();
204 switch (c) {
205 /* powerpoint remote presenter shortcuts */
206 case 4: /* ^D, EOT */
207 case 27:
208 case KEY_F(5):
209 /* end presentation */
210 case 'q':
211 break;
212 /* next without transition */
213 case 'J':
214 case 'L':
215 for (int i = currentslide + 1; i < nslides; i++) {
216 if (access(slidefiles[i], X_OK) && i != currentslide) {
217 currentslide = i;
218 slidechanged = 1;
219 goto show;
220 }
221 }
222 goto again;
223 /* next */
224 case ' ':
225 case 'l':
226 case 'j':
227 case KEY_RIGHT:
228 case KEY_DOWN:
229 case KEY_NPAGE:
230 if (currentslide < nslides - 1) {
231 slidechanged = 1;
232 currentslide++;
233 goto show;
234 }
235 goto again;
236 /* prev without transition */
237 case 'H':
238 case 'K':
239 for (int i = currentslide - 1; i >= 0; i--) {
240 if (access(slidefiles[i], X_OK) && i != currentslide) {
241 currentslide = i;
242 slidechanged = 1;
243 goto show;
244 }
245 }
246 goto again;
247 /* prev */
248 case 'h':
249 case 'k':
250 case KEY_LEFT:
251 case KEY_UP:
252 case KEY_PPAGE:
253 if (currentslide > 0) {
254 slidechanged = 1;
255 currentslide--;
256 goto show;
257 }
258 goto again;
259 /* shortcut from powerpoint. Needed for remote presenters. */
260 case '.':
261 /* first */
262 case 'u':
263 case KEY_BEG:
264 case KEY_HOME:
265 if (currentslide != 0)
266 slidechanged = 1;
267 currentslide = 0;
268 goto show;
269 /* last */
270 case 'i':
271 case KEY_END:
272 if (currentslide != (nslides - 1))
273 slidechanged = 1;
274 currentslide = nslides - 1;
275 goto show;
276 /* reload */
277 case 'r':
278 case 12: /* ^L, redraw */
279 case KEY_RESIZE: /* resize / SIGWINCH */
280 goto show;
281 default:
282 /* printf("key pressed = '%d'\n", c); */
283 goto again;
284 }
285
286 cleanup();
287
288 return 0;
289 }