catpoint

Catpoint simple presenting software.
git clone git://r-36.net/catpoint
Log | Files | Refs | README | 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 }