2014-06-22 22:39:21 +00:00
|
|
|
/* See LICENSE for licence details. */
|
2015-11-18 10:41:02 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2014-06-22 22:39:21 +00:00
|
|
|
#include <errno.h>
|
2015-11-18 10:41:02 +00:00
|
|
|
#include <fcntl.h>
|
2014-06-22 22:39:21 +00:00
|
|
|
#include <math.h>
|
2015-11-18 10:41:02 +00:00
|
|
|
#include <regex.h>
|
2014-06-22 22:39:21 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
2014-06-29 21:43:01 +00:00
|
|
|
#include <stdint.h>
|
2014-06-22 22:39:21 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2015-11-18 10:41:02 +00:00
|
|
|
#include <unistd.h>
|
2014-06-22 22:39:21 +00:00
|
|
|
#include <X11/keysym.h>
|
|
|
|
#include <X11/XKBlib.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
2015-04-06 21:06:36 +00:00
|
|
|
#include <X11/Xft/Xft.h>
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
#include "arg.h"
|
2016-05-21 19:39:58 +00:00
|
|
|
#include "util.h"
|
2015-04-06 21:06:36 +00:00
|
|
|
#include "drw.h"
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
char *argv0;
|
|
|
|
|
|
|
|
/* macros */
|
2015-04-30 20:00:14 +00:00
|
|
|
#define LEN(a) (sizeof(a) / sizeof(a)[0])
|
|
|
|
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
|
|
|
|
#define MAXFONTSTRLEN 128
|
2014-06-22 22:39:21 +00:00
|
|
|
|
2014-06-29 21:43:01 +00:00
|
|
|
typedef enum {
|
|
|
|
NONE = 0,
|
2016-06-30 14:42:34 +00:00
|
|
|
SCALED = 1,
|
|
|
|
DRAWN = 2
|
2014-06-29 21:43:01 +00:00
|
|
|
} imgstate;
|
|
|
|
|
2015-05-01 19:34:52 +00:00
|
|
|
typedef struct {
|
2014-06-29 21:43:01 +00:00
|
|
|
unsigned char *buf;
|
|
|
|
unsigned int bufwidth, bufheight;
|
|
|
|
imgstate state;
|
|
|
|
XImage *ximg;
|
|
|
|
int numpasses;
|
2015-05-01 19:34:52 +00:00
|
|
|
} Image;
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2015-11-18 10:41:02 +00:00
|
|
|
typedef struct {
|
|
|
|
char *regex;
|
|
|
|
char *bin;
|
|
|
|
} Filter;
|
|
|
|
|
2014-06-22 22:39:21 +00:00
|
|
|
typedef struct {
|
2015-11-07 22:54:23 +00:00
|
|
|
unsigned int linecount;
|
|
|
|
char **lines;
|
2015-05-01 19:34:52 +00:00
|
|
|
Image *img;
|
2016-06-04 14:33:15 +00:00
|
|
|
char *embed;
|
2014-06-22 22:39:21 +00:00
|
|
|
} Slide;
|
|
|
|
|
|
|
|
/* Purely graphic info */
|
|
|
|
typedef struct {
|
|
|
|
Display *dpy;
|
|
|
|
Window win;
|
|
|
|
Atom wmdeletewin, netwmname;
|
|
|
|
Visual *vis;
|
|
|
|
XSetWindowAttributes attrs;
|
|
|
|
int scr;
|
|
|
|
int w, h;
|
2014-06-29 21:43:01 +00:00
|
|
|
int uw, uh; /* usable dimensions for drawing text and images */
|
2014-06-22 22:39:21 +00:00
|
|
|
} XWindow;
|
|
|
|
|
|
|
|
typedef union {
|
|
|
|
int i;
|
|
|
|
unsigned int ui;
|
|
|
|
float f;
|
|
|
|
const void *v;
|
|
|
|
} Arg;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
unsigned int b;
|
|
|
|
void (*func)(const Arg *);
|
|
|
|
const Arg arg;
|
|
|
|
} Mousekey;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
KeySym keysym;
|
|
|
|
void (*func)(const Arg *);
|
|
|
|
const Arg arg;
|
|
|
|
} Shortcut;
|
|
|
|
|
2015-11-18 10:41:02 +00:00
|
|
|
static void fffree(Image *img);
|
2016-06-30 14:42:34 +00:00
|
|
|
static void ffload(Slide *s);
|
2016-02-06 13:08:43 +00:00
|
|
|
static void ffprepare(Image *img);
|
2015-11-18 10:41:02 +00:00
|
|
|
static void ffscale(Image *img);
|
|
|
|
static void ffdraw(Image *img);
|
2014-06-22 22:39:21 +00:00
|
|
|
|
2015-11-07 22:54:23 +00:00
|
|
|
static void getfontsize(Slide *s, unsigned int *width, unsigned int *height);
|
2015-04-27 21:26:03 +00:00
|
|
|
static void cleanup();
|
2014-06-22 22:39:21 +00:00
|
|
|
static void load(FILE *fp);
|
|
|
|
static void advance(const Arg *arg);
|
|
|
|
static void quit(const Arg *arg);
|
2014-06-29 21:43:01 +00:00
|
|
|
static void resize(int width, int height);
|
2014-06-22 22:39:21 +00:00
|
|
|
static void run();
|
|
|
|
static void usage();
|
|
|
|
static void xdraw();
|
|
|
|
static void xhints();
|
|
|
|
static void xinit();
|
2015-10-31 17:10:47 +00:00
|
|
|
static void xloadfonts();
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
static void bpress(XEvent *);
|
|
|
|
static void cmessage(XEvent *);
|
|
|
|
static void expose(XEvent *);
|
|
|
|
static void kpress(XEvent *);
|
2014-06-29 21:43:01 +00:00
|
|
|
static void configure(XEvent *);
|
|
|
|
|
|
|
|
/* config.h for applying patches and the configuration. */
|
|
|
|
#include "config.h"
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
/* Globals */
|
|
|
|
static Slide *slides = NULL;
|
|
|
|
static int idx = 0;
|
|
|
|
static int slidecount = 0;
|
|
|
|
static XWindow xw;
|
2015-04-06 21:06:36 +00:00
|
|
|
static Drw *d = NULL;
|
2016-05-21 19:39:58 +00:00
|
|
|
static Clr *sc;
|
2015-04-20 20:20:16 +00:00
|
|
|
static Fnt *fonts[NUMFONTSCALES];
|
2014-06-22 22:39:21 +00:00
|
|
|
static int running = 1;
|
|
|
|
|
|
|
|
static void (*handler[LASTEvent])(XEvent *) = {
|
|
|
|
[ButtonPress] = bpress,
|
|
|
|
[ClientMessage] = cmessage,
|
2014-06-29 21:43:01 +00:00
|
|
|
[ConfigureNotify] = configure,
|
2014-06-22 22:39:21 +00:00
|
|
|
[Expose] = expose,
|
|
|
|
[KeyPress] = kpress,
|
|
|
|
};
|
|
|
|
|
2015-11-18 10:41:02 +00:00
|
|
|
int
|
|
|
|
filter(int fd, const char *cmd)
|
|
|
|
{
|
|
|
|
int fds[2];
|
|
|
|
|
|
|
|
if (pipe(fds) < 0)
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to create pipe:");
|
2015-11-18 10:41:02 +00:00
|
|
|
|
|
|
|
switch (fork()) {
|
|
|
|
case -1:
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to fork:");
|
2015-11-18 10:41:02 +00:00
|
|
|
case 0:
|
|
|
|
dup2(fd, 0);
|
|
|
|
dup2(fds[1], 1);
|
|
|
|
close(fds[0]);
|
|
|
|
close(fds[1]);
|
2015-12-10 04:56:07 +00:00
|
|
|
execlp("sh", "sh", "-c", cmd, (char *)0);
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: execlp sh -c '%s':", cmd);
|
2015-11-18 10:41:02 +00:00
|
|
|
}
|
|
|
|
close(fds[1]);
|
|
|
|
return fds[0];
|
|
|
|
}
|
|
|
|
|
load slide image on-demand
On Sat, Jun 04, 2016 at 05:28:31PM +0200, Markus Teich wrote:
> Hiltjo Posthuma wrote:
> > previously an image file would be opened but only ffread when advancing to
> > the slide, but when the slide was not used it gave an error:
> >
> > /usr/local/bin/2ff: failed to convert image/png
>
> Heyho Hiltjo,
>
> thanks for the patch. Unfortunately it does not work if the first slide contains
> an image (ffopen is only called in advance). I think it would be good to merge
> ffopen and ffread instead into a single function ffload. This makes the `LOADED`
> state clearer and also enforces that the fd is closed in the same function where
> it is opened. This ffload function should then be called in advance() replacing
> the ffread() calls if the image is not loaded yet and once in load() for the
> first slide if it is an image.
>
Ah yes, sorry for the oversight.
> If you want to take this new approach, go for it, otherwise I'll look into it
> myself.
>
I have attached a patch that does this, I hope you'll like it.
Also I'm not sure if we need the below code in advance(), I have removed it in
the patch:
if (slidecount > idx + 1 && slides[idx + 1].img)
ffread(slides[idx + 1].img);
if (0 < idx && slides[idx - 1].img)
ffread(slides[idx - 1].img);
That seems to preload the next and previous slide image right? A minor issue I
notice also is that images seem to flicker, it uses XPutImage directly to
xw.win. Maybe it can be replaced with a backbuffer then XCopyArea? What do you
think?
In advance() it should also not always be needed to rescale the image.
--
Kind regards,
Hiltjo
From 97bebdcab4003f9acdfdd4bdf424449299ffd61d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 4 Jun 2016 21:34:25 +0200
Subject: [PATCH] merge ffread and ffopen into one function
2016-06-04 19:47:39 +00:00
|
|
|
void
|
|
|
|
fffree(Image *img)
|
|
|
|
{
|
|
|
|
free(img->buf);
|
|
|
|
if (img->ximg)
|
|
|
|
XDestroyImage(img->ximg);
|
|
|
|
free(img);
|
|
|
|
}
|
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
void
|
|
|
|
ffload(Slide *s)
|
2014-06-29 21:43:01 +00:00
|
|
|
{
|
load slide image on-demand
On Sat, Jun 04, 2016 at 05:28:31PM +0200, Markus Teich wrote:
> Hiltjo Posthuma wrote:
> > previously an image file would be opened but only ffread when advancing to
> > the slide, but when the slide was not used it gave an error:
> >
> > /usr/local/bin/2ff: failed to convert image/png
>
> Heyho Hiltjo,
>
> thanks for the patch. Unfortunately it does not work if the first slide contains
> an image (ffopen is only called in advance). I think it would be good to merge
> ffopen and ffread instead into a single function ffload. This makes the `LOADED`
> state clearer and also enforces that the fd is closed in the same function where
> it is opened. This ffload function should then be called in advance() replacing
> the ffread() calls if the image is not loaded yet and once in load() for the
> first slide if it is an image.
>
Ah yes, sorry for the oversight.
> If you want to take this new approach, go for it, otherwise I'll look into it
> myself.
>
I have attached a patch that does this, I hope you'll like it.
Also I'm not sure if we need the below code in advance(), I have removed it in
the patch:
if (slidecount > idx + 1 && slides[idx + 1].img)
ffread(slides[idx + 1].img);
if (0 < idx && slides[idx - 1].img)
ffread(slides[idx - 1].img);
That seems to preload the next and previous slide image right? A minor issue I
notice also is that images seem to flicker, it uses XPutImage directly to
xw.win. Maybe it can be replaced with a backbuffer then XCopyArea? What do you
think?
In advance() it should also not always be needed to rescale the image.
--
Kind regards,
Hiltjo
From 97bebdcab4003f9acdfdd4bdf424449299ffd61d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 4 Jun 2016 21:34:25 +0200
Subject: [PATCH] merge ffread and ffopen into one function
2016-06-04 19:47:39 +00:00
|
|
|
uint32_t y, x;
|
|
|
|
uint16_t *row;
|
|
|
|
uint8_t opac, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
|
|
|
|
size_t rowlen, off, nbytes, i;
|
|
|
|
ssize_t count;
|
2015-11-18 10:41:02 +00:00
|
|
|
unsigned char hdr[16];
|
2015-12-08 23:50:05 +00:00
|
|
|
char *bin = NULL;
|
2016-06-30 14:42:34 +00:00
|
|
|
char *filename;
|
2015-11-18 10:41:02 +00:00
|
|
|
regex_t regex;
|
2016-06-30 14:42:34 +00:00
|
|
|
int fdin, fdout;
|
|
|
|
|
|
|
|
if (s->img || !(filename = s->embed) || !s->embed[0])
|
|
|
|
return; /* already done */
|
2015-11-18 10:41:02 +00:00
|
|
|
|
2015-12-08 23:50:05 +00:00
|
|
|
for (i = 0; i < LEN(filters); i++) {
|
2015-11-18 10:41:02 +00:00
|
|
|
if (regcomp(®ex, filters[i].regex,
|
|
|
|
REG_NOSUB | REG_EXTENDED | REG_ICASE))
|
|
|
|
continue;
|
|
|
|
if (!regexec(®ex, filename, 0, NULL, 0)) {
|
2015-12-08 23:52:39 +00:00
|
|
|
bin = filters[i].bin;
|
2015-11-18 10:41:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-12-08 23:50:05 +00:00
|
|
|
if (!bin)
|
2016-06-30 14:42:34 +00:00
|
|
|
die("sent: Unable to find matching filter for file %s", filename);
|
2015-12-08 23:50:05 +00:00
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
if ((fdin = open(filename, O_RDONLY)) < 0)
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to open file %s:", filename);
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
if ((fdout = filter(fdin, bin)) < 0)
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to filter %s:", filename);
|
2016-06-30 14:42:34 +00:00
|
|
|
close(fdin);
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
if (read(fdout, hdr, 16) != 16 || memcmp("farbfeld", hdr, 8))
|
|
|
|
die("sent: Unable to filter %s into a valid farbfeld file", filename);
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
s->img = calloc(1, sizeof(Image));
|
|
|
|
s->img->bufwidth = ntohl(*(uint32_t *)&hdr[8]);
|
|
|
|
s->img->bufheight = ntohl(*(uint32_t *)&hdr[12]);
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
if (s->img->buf)
|
|
|
|
free(s->img->buf);
|
2015-11-18 10:41:02 +00:00
|
|
|
/* internally the image is stored in 888 format */
|
2016-06-30 14:42:34 +00:00
|
|
|
if (!(s->img->buf = malloc(3 * s->img->bufwidth * s->img->bufheight)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to malloc buffer for image.\n");
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2015-11-18 10:41:02 +00:00
|
|
|
/* scratch buffer to read row by row */
|
2016-06-30 14:42:34 +00:00
|
|
|
rowlen = s->img->bufwidth * 2 * strlen("RGBA");
|
2015-11-18 10:41:02 +00:00
|
|
|
row = malloc(rowlen);
|
load slide image on-demand
On Sat, Jun 04, 2016 at 05:28:31PM +0200, Markus Teich wrote:
> Hiltjo Posthuma wrote:
> > previously an image file would be opened but only ffread when advancing to
> > the slide, but when the slide was not used it gave an error:
> >
> > /usr/local/bin/2ff: failed to convert image/png
>
> Heyho Hiltjo,
>
> thanks for the patch. Unfortunately it does not work if the first slide contains
> an image (ffopen is only called in advance). I think it would be good to merge
> ffopen and ffread instead into a single function ffload. This makes the `LOADED`
> state clearer and also enforces that the fd is closed in the same function where
> it is opened. This ffload function should then be called in advance() replacing
> the ffread() calls if the image is not loaded yet and once in load() for the
> first slide if it is an image.
>
Ah yes, sorry for the oversight.
> If you want to take this new approach, go for it, otherwise I'll look into it
> myself.
>
I have attached a patch that does this, I hope you'll like it.
Also I'm not sure if we need the below code in advance(), I have removed it in
the patch:
if (slidecount > idx + 1 && slides[idx + 1].img)
ffread(slides[idx + 1].img);
if (0 < idx && slides[idx - 1].img)
ffread(slides[idx - 1].img);
That seems to preload the next and previous slide image right? A minor issue I
notice also is that images seem to flicker, it uses XPutImage directly to
xw.win. Maybe it can be replaced with a backbuffer then XCopyArea? What do you
think?
In advance() it should also not always be needed to rescale the image.
--
Kind regards,
Hiltjo
From 97bebdcab4003f9acdfdd4bdf424449299ffd61d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 4 Jun 2016 21:34:25 +0200
Subject: [PATCH] merge ffread and ffopen into one function
2016-06-04 19:47:39 +00:00
|
|
|
if (!row)
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to malloc buffer for image row.\n");
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2015-12-08 20:46:18 +00:00
|
|
|
/* extract window background color channels for transparency */
|
2016-05-21 19:39:58 +00:00
|
|
|
bg_r = (sc[ColBg].pixel >> 16) % 256;
|
|
|
|
bg_g = (sc[ColBg].pixel >> 8) % 256;
|
|
|
|
bg_b = (sc[ColBg].pixel >> 0) % 256;
|
2015-12-08 20:46:18 +00:00
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
for (off = 0, y = 0; y < s->img->bufheight; y++) {
|
2015-11-18 10:41:02 +00:00
|
|
|
nbytes = 0;
|
|
|
|
while (nbytes < rowlen) {
|
2016-06-30 14:42:34 +00:00
|
|
|
count = read(fdout, (char *)row + nbytes, rowlen - nbytes);
|
2015-12-08 21:09:26 +00:00
|
|
|
if (count < 0)
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to read from pipe:");
|
2015-12-08 21:09:26 +00:00
|
|
|
nbytes += count;
|
2015-11-18 10:41:02 +00:00
|
|
|
}
|
|
|
|
for (x = 0; x < rowlen / 2; x += 4) {
|
2016-01-31 10:05:00 +00:00
|
|
|
fg_r = ntohs(row[x + 0]) / 257;
|
|
|
|
fg_g = ntohs(row[x + 1]) / 257;
|
|
|
|
fg_b = ntohs(row[x + 2]) / 257;
|
|
|
|
opac = ntohs(row[x + 3]) / 257;
|
2015-12-08 20:46:18 +00:00
|
|
|
/* blend opaque part of image data with window background color to
|
|
|
|
* emulate transparency */
|
2016-06-30 14:42:34 +00:00
|
|
|
s->img->buf[off++] = (fg_r * opac + bg_r * (255 - opac)) / 255;
|
|
|
|
s->img->buf[off++] = (fg_g * opac + bg_g * (255 - opac)) / 255;
|
|
|
|
s->img->buf[off++] = (fg_b * opac + bg_b * (255 - opac)) / 255;
|
2015-11-18 10:41:02 +00:00
|
|
|
}
|
2014-06-29 21:43:01 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 10:41:02 +00:00
|
|
|
free(row);
|
2016-06-30 14:42:34 +00:00
|
|
|
close(fdout);
|
2014-06-29 21:43:01 +00:00
|
|
|
}
|
|
|
|
|
2016-02-06 13:08:43 +00:00
|
|
|
void
|
2016-02-05 15:17:43 +00:00
|
|
|
ffprepare(Image *img)
|
2014-06-29 21:43:01 +00:00
|
|
|
{
|
|
|
|
int depth = DefaultDepth(xw.dpy, xw.scr);
|
|
|
|
int width = xw.uw;
|
|
|
|
int height = xw.uh;
|
|
|
|
|
|
|
|
if (xw.uw * img->bufheight > xw.uh * img->bufwidth)
|
|
|
|
width = img->bufwidth * xw.uh / img->bufheight;
|
|
|
|
else
|
|
|
|
height = img->bufheight * xw.uw / img->bufwidth;
|
|
|
|
|
2016-02-06 13:08:43 +00:00
|
|
|
if (depth < 24)
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Display depths <24 not supported.\n");
|
2014-06-29 21:43:01 +00:00
|
|
|
|
|
|
|
if (!(img->ximg = XCreateImage(xw.dpy, CopyFromParent, depth, ZPixmap, 0,
|
2016-02-06 13:08:43 +00:00
|
|
|
NULL, width, height, 32, 0)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to create XImage.\n");
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2016-02-06 13:08:43 +00:00
|
|
|
if (!(img->ximg->data = malloc(img->ximg->bytes_per_line * height)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to alloc data section for XImage.\n");
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2016-02-06 13:08:43 +00:00
|
|
|
if (!XInitImage(img->ximg))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to init XImage.\n");
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2015-11-18 10:41:02 +00:00
|
|
|
ffscale(img);
|
2014-06-29 21:43:01 +00:00
|
|
|
img->state |= SCALED;
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
ffscale(Image *img)
|
2014-06-29 21:43:01 +00:00
|
|
|
{
|
|
|
|
unsigned int x, y;
|
|
|
|
unsigned int width = img->ximg->width;
|
|
|
|
unsigned int height = img->ximg->height;
|
2015-10-31 15:25:02 +00:00
|
|
|
char* newBuf = img->ximg->data;
|
|
|
|
unsigned char* ibuf;
|
2014-06-29 21:43:01 +00:00
|
|
|
unsigned int jdy = img->ximg->bytes_per_line / 4 - width;
|
|
|
|
unsigned int dx = (img->bufwidth << 10) / width;
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++) {
|
|
|
|
unsigned int bufx = img->bufwidth / width;
|
|
|
|
ibuf = &img->buf[y * img->bufheight / height * img->bufwidth * 3];
|
|
|
|
|
|
|
|
for (x = 0; x < width; x++) {
|
|
|
|
*newBuf++ = (ibuf[(bufx >> 10)*3+2]);
|
|
|
|
*newBuf++ = (ibuf[(bufx >> 10)*3+1]);
|
|
|
|
*newBuf++ = (ibuf[(bufx >> 10)*3+0]);
|
|
|
|
newBuf++;
|
|
|
|
bufx += dx;
|
|
|
|
}
|
|
|
|
newBuf += jdy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
ffdraw(Image *img)
|
2014-06-29 21:43:01 +00:00
|
|
|
{
|
|
|
|
int xoffset = (xw.w - img->ximg->width) / 2;
|
|
|
|
int yoffset = (xw.h - img->ximg->height) / 2;
|
2015-04-09 17:23:31 +00:00
|
|
|
XPutImage(xw.dpy, xw.win, d->gc, img->ximg, 0, 0,
|
2015-12-08 21:09:26 +00:00
|
|
|
xoffset, yoffset, img->ximg->width, img->ximg->height);
|
2014-06-29 21:43:01 +00:00
|
|
|
XFlush(xw.dpy);
|
|
|
|
img->state |= DRAWN;
|
|
|
|
}
|
2014-06-22 22:39:21 +00:00
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
getfontsize(Slide *s, unsigned int *width, unsigned int *height)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
2015-11-16 23:19:39 +00:00
|
|
|
int i, j;
|
2015-12-08 23:52:39 +00:00
|
|
|
unsigned int curw, newmax;
|
2015-11-07 22:54:23 +00:00
|
|
|
float lfac = linespacing * (s->linecount - 1) + 1;
|
2014-06-22 22:39:21 +00:00
|
|
|
|
2015-11-07 22:54:23 +00:00
|
|
|
/* fit height */
|
|
|
|
for (j = NUMFONTSCALES - 1; j >= 0; j--)
|
|
|
|
if (fonts[j]->h * lfac <= xw.uh)
|
2014-06-22 22:39:21 +00:00
|
|
|
break;
|
2015-11-16 23:23:51 +00:00
|
|
|
LIMIT(j, 0, NUMFONTSCALES - 1);
|
|
|
|
drw_setfontset(d, fonts[j]);
|
2015-11-07 22:54:23 +00:00
|
|
|
|
|
|
|
/* fit width */
|
|
|
|
*width = 0;
|
|
|
|
for (i = 0; i < s->linecount; i++) {
|
|
|
|
curw = drw_fontset_getwidth(d, s->lines[i]);
|
2015-12-08 23:50:05 +00:00
|
|
|
newmax = (curw >= *width);
|
2015-11-16 23:19:39 +00:00
|
|
|
while (j > 0 && curw > xw.uw) {
|
2015-11-07 22:54:23 +00:00
|
|
|
drw_setfontset(d, fonts[--j]);
|
|
|
|
curw = drw_fontset_getwidth(d, s->lines[i]);
|
|
|
|
}
|
2015-12-08 23:50:05 +00:00
|
|
|
if (newmax)
|
2015-11-07 22:54:23 +00:00
|
|
|
*width = curw;
|
2015-04-20 20:20:16 +00:00
|
|
|
}
|
2015-11-07 22:54:23 +00:00
|
|
|
*height = fonts[j]->h * lfac;
|
2014-06-22 22:39:21 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
cleanup()
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
2015-11-07 22:54:23 +00:00
|
|
|
unsigned int i, j;
|
2015-11-11 17:49:57 +00:00
|
|
|
|
2015-11-11 18:00:54 +00:00
|
|
|
for (i = 0; i < NUMFONTSCALES; i++)
|
|
|
|
drw_fontset_free(fonts[i]);
|
2016-05-21 19:39:58 +00:00
|
|
|
free(sc);
|
2015-04-06 21:06:36 +00:00
|
|
|
drw_free(d);
|
|
|
|
|
2014-06-22 22:39:21 +00:00
|
|
|
XDestroyWindow(xw.dpy, xw.win);
|
|
|
|
XSync(xw.dpy, False);
|
|
|
|
XCloseDisplay(xw.dpy);
|
|
|
|
if (slides) {
|
2015-11-11 17:49:57 +00:00
|
|
|
for (i = 0; i < slidecount; i++) {
|
2015-11-07 22:54:23 +00:00
|
|
|
for (j = 0; j < slides[i].linecount; j++)
|
|
|
|
free(slides[i].lines[j]);
|
|
|
|
free(slides[i].lines);
|
2015-11-11 17:49:57 +00:00
|
|
|
if (slides[i].img)
|
2015-11-18 10:41:02 +00:00
|
|
|
fffree(slides[i].img);
|
2015-11-11 17:49:57 +00:00
|
|
|
}
|
2014-06-22 22:39:21 +00:00
|
|
|
free(slides);
|
|
|
|
slides = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
load(FILE *fp)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
static size_t size = 0;
|
2015-11-07 22:54:23 +00:00
|
|
|
size_t blen, maxlines;
|
2014-06-22 22:39:21 +00:00
|
|
|
char buf[BUFSIZ], *p;
|
2015-11-07 22:54:23 +00:00
|
|
|
Slide *s;
|
2014-06-22 22:39:21 +00:00
|
|
|
|
2015-11-04 00:40:50 +00:00
|
|
|
/* read each line from fp and add it to the item list */
|
2015-11-07 22:54:23 +00:00
|
|
|
while (1) {
|
|
|
|
/* eat consecutive empty lines */
|
|
|
|
while ((p = fgets(buf, sizeof(buf), fp)))
|
|
|
|
if (strcmp(buf, "\n") != 0 && buf[0] != '#')
|
|
|
|
break;
|
|
|
|
if (!p)
|
|
|
|
break;
|
|
|
|
|
2015-11-18 22:21:33 +00:00
|
|
|
if ((slidecount+1) * sizeof(*slides) >= size)
|
|
|
|
if (!(slides = realloc(slides, (size += BUFSIZ))))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to realloc %u bytes:", size);
|
2015-11-18 22:21:33 +00:00
|
|
|
|
2015-11-07 22:54:23 +00:00
|
|
|
/* read one slide */
|
|
|
|
maxlines = 0;
|
|
|
|
memset((s = &slides[slidecount]), 0, sizeof(Slide));
|
|
|
|
do {
|
|
|
|
if (buf[0] == '#')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* grow lines array */
|
|
|
|
if (s->linecount >= maxlines) {
|
|
|
|
maxlines = 2 * s->linecount + 1;
|
|
|
|
if (!(s->lines = realloc(s->lines, maxlines * sizeof(s->lines[0]))))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to realloc %u bytes:", maxlines * sizeof(s->lines[0]));
|
2015-11-07 22:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
blen = strlen(buf);
|
|
|
|
if (!(s->lines[s->linecount] = strdup(buf)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to strdup:");
|
2015-11-07 22:54:23 +00:00
|
|
|
if (s->lines[s->linecount][blen-1] == '\n')
|
|
|
|
s->lines[s->linecount][blen-1] = '\0';
|
|
|
|
|
2016-06-30 14:42:34 +00:00
|
|
|
/* mark as image slide if first line of a slide starts with @ */
|
|
|
|
if (s->linecount == 0 && s->lines[0][0] == '@')
|
|
|
|
s->embed = &s->lines[0][1];
|
2015-11-07 22:54:23 +00:00
|
|
|
|
|
|
|
if (s->lines[s->linecount][0] == '\\')
|
|
|
|
memmove(s->lines[s->linecount], &s->lines[s->linecount][1], blen);
|
|
|
|
s->linecount++;
|
|
|
|
} while ((p = fgets(buf, sizeof(buf), fp)) && strcmp(buf, "\n") != 0);
|
load slide image on-demand
On Sat, Jun 04, 2016 at 05:28:31PM +0200, Markus Teich wrote:
> Hiltjo Posthuma wrote:
> > previously an image file would be opened but only ffread when advancing to
> > the slide, but when the slide was not used it gave an error:
> >
> > /usr/local/bin/2ff: failed to convert image/png
>
> Heyho Hiltjo,
>
> thanks for the patch. Unfortunately it does not work if the first slide contains
> an image (ffopen is only called in advance). I think it would be good to merge
> ffopen and ffread instead into a single function ffload. This makes the `LOADED`
> state clearer and also enforces that the fd is closed in the same function where
> it is opened. This ffload function should then be called in advance() replacing
> the ffread() calls if the image is not loaded yet and once in load() for the
> first slide if it is an image.
>
Ah yes, sorry for the oversight.
> If you want to take this new approach, go for it, otherwise I'll look into it
> myself.
>
I have attached a patch that does this, I hope you'll like it.
Also I'm not sure if we need the below code in advance(), I have removed it in
the patch:
if (slidecount > idx + 1 && slides[idx + 1].img)
ffread(slides[idx + 1].img);
if (0 < idx && slides[idx - 1].img)
ffread(slides[idx - 1].img);
That seems to preload the next and previous slide image right? A minor issue I
notice also is that images seem to flicker, it uses XPutImage directly to
xw.win. Maybe it can be replaced with a backbuffer then XCopyArea? What do you
think?
In advance() it should also not always be needed to rescale the image.
--
Kind regards,
Hiltjo
From 97bebdcab4003f9acdfdd4bdf424449299ffd61d Mon Sep 17 00:00:00 2001
From: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat, 4 Jun 2016 21:34:25 +0200
Subject: [PATCH] merge ffread and ffopen into one function
2016-06-04 19:47:39 +00:00
|
|
|
|
2015-11-07 22:54:23 +00:00
|
|
|
slidecount++;
|
|
|
|
if (!p)
|
|
|
|
break;
|
2014-06-22 22:39:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
advance(const Arg *arg)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
int new_idx = idx + arg->i;
|
|
|
|
LIMIT(new_idx, 0, slidecount-1);
|
|
|
|
if (new_idx != idx) {
|
2014-06-29 21:43:01 +00:00
|
|
|
if (slides[idx].img)
|
|
|
|
slides[idx].img->state &= ~(DRAWN | SCALED);
|
2014-06-22 22:39:21 +00:00
|
|
|
idx = new_idx;
|
2016-06-30 14:57:31 +00:00
|
|
|
ffload(&slides[idx]);
|
2014-06-22 22:39:21 +00:00
|
|
|
xdraw();
|
2016-06-30 14:42:34 +00:00
|
|
|
if (slidecount > idx + 1)
|
|
|
|
ffload(&slides[idx + 1]);
|
|
|
|
if (0 < idx)
|
|
|
|
ffload(&slides[idx - 1]);
|
2014-06-22 22:39:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
quit(const Arg *arg)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
running = 0;
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
resize(int width, int height)
|
2014-06-29 21:43:01 +00:00
|
|
|
{
|
|
|
|
xw.w = width;
|
|
|
|
xw.h = height;
|
|
|
|
xw.uw = usablewidth * width;
|
|
|
|
xw.uh = usableheight * height;
|
2015-05-03 20:07:51 +00:00
|
|
|
drw_resize(d, width, height);
|
2014-06-29 21:43:01 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
run()
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
XEvent ev;
|
|
|
|
|
|
|
|
/* Waiting for window mapping */
|
|
|
|
while (1) {
|
|
|
|
XNextEvent(xw.dpy, &ev);
|
|
|
|
if (ev.type == ConfigureNotify) {
|
2014-06-29 21:43:01 +00:00
|
|
|
resize(ev.xconfigure.width, ev.xconfigure.height);
|
2014-06-22 22:39:21 +00:00
|
|
|
} else if (ev.type == MapNotify) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (running) {
|
|
|
|
XNextEvent(xw.dpy, &ev);
|
|
|
|
if (handler[ev.type])
|
|
|
|
(handler[ev.type])(&ev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
xdraw()
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
2015-11-07 22:54:23 +00:00
|
|
|
unsigned int height, width, i;
|
2016-06-30 14:42:34 +00:00
|
|
|
Image *im = slides[idx].img;
|
2014-06-22 22:39:21 +00:00
|
|
|
|
2015-11-07 22:54:23 +00:00
|
|
|
getfontsize(&slides[idx], &width, &height);
|
2014-06-22 22:39:21 +00:00
|
|
|
XClearWindow(xw.dpy, xw.win);
|
2014-06-29 21:43:01 +00:00
|
|
|
|
2015-04-07 20:03:02 +00:00
|
|
|
if (!im) {
|
2015-04-22 09:57:08 +00:00
|
|
|
drw_rect(d, 0, 0, xw.w, xw.h, 1, 1);
|
2015-11-07 22:54:23 +00:00
|
|
|
for (i = 0; i < slides[idx].linecount; i++)
|
|
|
|
drw_text(d,
|
|
|
|
(xw.w - width) / 2,
|
|
|
|
(xw.h - height) / 2 + i * linespacing * d->fonts->h,
|
|
|
|
width,
|
|
|
|
d->fonts->h,
|
2016-05-21 19:39:58 +00:00
|
|
|
0,
|
2015-11-07 22:54:23 +00:00
|
|
|
slides[idx].lines[i],
|
|
|
|
0);
|
2015-04-07 20:03:02 +00:00
|
|
|
drw_map(d, xw.win, 0, 0, xw.w, xw.h);
|
2016-02-06 13:08:43 +00:00
|
|
|
} else {
|
|
|
|
if (!(im->state & SCALED))
|
|
|
|
ffprepare(im);
|
|
|
|
if (!(im->state & DRAWN))
|
|
|
|
ffdraw(im);
|
2015-04-30 20:00:14 +00:00
|
|
|
}
|
2014-06-22 22:39:21 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
xhints()
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
XClassHint class = {.res_name = "sent", .res_class = "presenter"};
|
|
|
|
XWMHints wm = {.flags = InputHint, .input = True};
|
|
|
|
XSizeHints *sizeh = NULL;
|
|
|
|
|
|
|
|
if (!(sizeh = XAllocSizeHints()))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to alloc size hints.\n");
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
sizeh->flags = PSize;
|
|
|
|
sizeh->height = xw.h;
|
|
|
|
sizeh->width = xw.w;
|
|
|
|
|
|
|
|
XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, &class);
|
|
|
|
XFree(sizeh);
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
xinit()
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
XTextProperty prop;
|
|
|
|
|
|
|
|
if (!(xw.dpy = XOpenDisplay(NULL)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to open display.\n");
|
2014-06-22 22:39:21 +00:00
|
|
|
xw.scr = XDefaultScreen(xw.dpy);
|
|
|
|
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
2015-11-10 03:54:16 +00:00
|
|
|
resize(DisplayWidth(xw.dpy, xw.scr), DisplayHeight(xw.dpy, xw.scr));
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
xw.attrs.bit_gravity = CenterGravity;
|
2015-12-08 21:09:26 +00:00
|
|
|
xw.attrs.event_mask = KeyPressMask | ExposureMask | StructureNotifyMask |
|
|
|
|
ButtonMotionMask | ButtonPressMask;
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
xw.win = XCreateWindow(xw.dpy, XRootWindow(xw.dpy, xw.scr), 0, 0,
|
2015-12-08 21:09:26 +00:00
|
|
|
xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr),
|
|
|
|
InputOutput, xw.vis, CWBitGravity | CWEventMask,
|
|
|
|
&xw.attrs);
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
|
|
|
|
xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
|
|
|
|
XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
|
|
|
|
|
2015-04-19 15:36:18 +00:00
|
|
|
if (!(d = drw_create(xw.dpy, xw.scr, xw.win, xw.w, xw.h)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to create drawing context.\n");
|
|
|
|
sc = drw_scm_create(d, colors, 2);
|
2015-04-10 21:13:33 +00:00
|
|
|
drw_setscheme(d, sc);
|
2016-05-21 19:39:58 +00:00
|
|
|
XSetWindowBackground(xw.dpy, xw.win, sc[ColBg].pixel);
|
2015-04-06 21:06:36 +00:00
|
|
|
|
2015-10-31 17:10:47 +00:00
|
|
|
xloadfonts();
|
2016-06-30 14:42:34 +00:00
|
|
|
ffload(&slides[0]);
|
2014-06-22 22:39:21 +00:00
|
|
|
|
|
|
|
XStringListToTextProperty(&argv0, 1, &prop);
|
|
|
|
XSetWMName(xw.dpy, xw.win, &prop);
|
|
|
|
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
|
|
|
|
XFree(prop.value);
|
|
|
|
XMapWindow(xw.dpy, xw.win);
|
|
|
|
xhints();
|
|
|
|
XSync(xw.dpy, False);
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
xloadfonts()
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
2015-04-20 20:20:16 +00:00
|
|
|
int i, j;
|
|
|
|
char *fstrs[LEN(fontfallbacks)];
|
|
|
|
|
|
|
|
for (j = 0; j < LEN(fontfallbacks); j++) {
|
|
|
|
if (!(fstrs[j] = malloc(MAXFONTSTRLEN)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to malloc fstrs.\n");
|
2015-04-20 20:20:16 +00:00
|
|
|
}
|
2015-04-09 17:23:31 +00:00
|
|
|
|
2015-04-20 20:20:16 +00:00
|
|
|
for (i = 0; i < NUMFONTSCALES; i++) {
|
|
|
|
for (j = 0; j < LEN(fontfallbacks); j++) {
|
|
|
|
if (MAXFONTSTRLEN < snprintf(fstrs[j], MAXFONTSTRLEN, "%s:size=%d", fontfallbacks[j], FONTSZ(i)))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Font string too long.\n");
|
2015-04-20 20:20:16 +00:00
|
|
|
}
|
2015-11-17 23:41:38 +00:00
|
|
|
if (!(fonts[i] = drw_fontset_create(d, (const char**)fstrs, LEN(fstrs))))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to load any font for size %d.\n", FONTSZ(i));
|
2015-04-20 20:20:16 +00:00
|
|
|
}
|
2015-11-11 17:53:54 +00:00
|
|
|
|
|
|
|
for (j = 0; j < LEN(fontfallbacks); j++)
|
|
|
|
if (fstrs[j])
|
|
|
|
free(fstrs[j]);
|
2014-06-22 22:39:21 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
bpress(XEvent *e)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < LEN(mshortcuts); i++)
|
|
|
|
if (e->xbutton.button == mshortcuts[i].b && mshortcuts[i].func)
|
|
|
|
mshortcuts[i].func(&(mshortcuts[i].arg));
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
cmessage(XEvent *e)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
if (e->xclient.data.l[0] == xw.wmdeletewin)
|
|
|
|
running = 0;
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
expose(XEvent *e)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
if (0 == e->xexpose.count)
|
|
|
|
xdraw();
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
kpress(XEvent *e)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
KeySym sym;
|
|
|
|
|
|
|
|
sym = XkbKeycodeToKeysym(xw.dpy, (KeyCode)e->xkey.keycode, 0, 0);
|
|
|
|
for (i = 0; i < LEN(shortcuts); i++)
|
|
|
|
if (sym == shortcuts[i].keysym && shortcuts[i].func)
|
|
|
|
shortcuts[i].func(&(shortcuts[i].arg));
|
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
void
|
|
|
|
configure(XEvent *e)
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
2014-06-29 21:43:01 +00:00
|
|
|
resize(e->xconfigure.width, e->xconfigure.height);
|
|
|
|
if (slides[idx].img)
|
|
|
|
slides[idx].img->state &= ~(DRAWN | SCALED);
|
2014-06-22 22:39:21 +00:00
|
|
|
xdraw();
|
|
|
|
}
|
|
|
|
|
2016-02-06 13:08:43 +00:00
|
|
|
void
|
|
|
|
usage()
|
|
|
|
{
|
|
|
|
die("sent " VERSION " (c) 2014-2015 markus.teich@stusta.mhn.de\n" \
|
2016-05-21 19:39:58 +00:00
|
|
|
"usage: sent [FILE]\n", argv0);
|
2016-02-06 13:08:43 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 15:17:43 +00:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
2014-06-22 22:39:21 +00:00
|
|
|
{
|
|
|
|
FILE *fp = NULL;
|
|
|
|
|
|
|
|
ARGBEGIN {
|
|
|
|
case 'v':
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
} ARGEND;
|
|
|
|
|
2016-03-06 19:49:18 +00:00
|
|
|
if (!argv[0] || !strcmp(argv[0], "-"))
|
|
|
|
fp = stdin;
|
|
|
|
else if (!(fp = fopen(argv[0], "r")))
|
2016-05-21 19:39:58 +00:00
|
|
|
die("sent: Unable to open '%s' for reading:", argv[0]);
|
2016-03-06 19:49:18 +00:00
|
|
|
|
|
|
|
load(fp);
|
|
|
|
fclose(fp);
|
2014-06-22 22:39:21 +00:00
|
|
|
|
2015-11-18 22:24:53 +00:00
|
|
|
if (!slidecount)
|
2014-06-22 22:39:21 +00:00
|
|
|
usage();
|
|
|
|
|
|
|
|
xinit();
|
|
|
|
run();
|
|
|
|
|
2015-04-27 21:26:03 +00:00
|
|
|
cleanup();
|
2015-11-07 22:52:35 +00:00
|
|
|
return 0;
|
2014-06-22 22:39:21 +00:00
|
|
|
}
|