429 lines
8 KiB
C
429 lines
8 KiB
C
/*
|
|
* plain.c
|
|
*
|
|
* libplain - a bad plain text renderer
|
|
*
|
|
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/*
|
|
* This sucks.
|
|
*/
|
|
|
|
#include "port_before.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#include <X11/Intrinsic.h>
|
|
|
|
#include "port_after.h"
|
|
|
|
#include "Chimera.h"
|
|
#include "ChimeraRender.h"
|
|
|
|
#define PLAIN_MARGIN 20
|
|
|
|
typedef struct
|
|
{
|
|
char *s;
|
|
size_t len;
|
|
int y;
|
|
unsigned int width;
|
|
} LineInfoP, *LineInfo;
|
|
|
|
typedef struct
|
|
{
|
|
MemPool mp;
|
|
GList lines;
|
|
size_t off;
|
|
size_t len;
|
|
byte *data;
|
|
|
|
XFontStruct *font;
|
|
Window win;
|
|
Widget w;
|
|
Display *dpy;
|
|
GC gc;
|
|
Pixel fg, bg;
|
|
|
|
ChimeraSink wp;
|
|
ChimeraResources cres;
|
|
ChimeraGUI wd;
|
|
|
|
/* Dimensions stuff */
|
|
unsigned int lineSpace;
|
|
unsigned int baseline;
|
|
unsigned int lineheight;
|
|
unsigned int width, height;
|
|
|
|
LineInfo searchline;
|
|
char *searchchar;
|
|
LineInfo searchcur;
|
|
char *searchstr;
|
|
size_t searchlen;
|
|
} PlainInfoP, *PlainInfo;
|
|
|
|
static LineInfo MakeLine _ArgProto((PlainInfo, char *, size_t));
|
|
static void ParsePlainData _ArgProto((PlainInfo));
|
|
static int PlainSearch _ArgProto((void *, char *, int));
|
|
|
|
static LineInfo
|
|
MakeLine(pi, s, len)
|
|
PlainInfo pi;
|
|
char *s;
|
|
size_t len;
|
|
{
|
|
LineInfo li;
|
|
|
|
li = (LineInfo)MPCGet(pi->mp, sizeof(LineInfoP));
|
|
li->s = s;
|
|
li->len = len;
|
|
li->y = pi->height;
|
|
pi->height += pi->lineheight;
|
|
|
|
li->width = XTextWidth(pi->font, s, len);
|
|
if (li->width > pi->width) pi->width = li->width + PLAIN_MARGIN * 2;
|
|
|
|
GUISetDimensions(pi->wd, pi->width, pi->height);
|
|
|
|
XSetFont(pi->dpy, pi->gc, pi->font->fid);
|
|
XSetForeground(pi->dpy, pi->gc, pi->fg);
|
|
|
|
XDrawString(pi->dpy, pi->win, pi->gc, PLAIN_MARGIN, li->y + pi->baseline,
|
|
li->s,
|
|
(int)li->len); /* what to do about this ? */
|
|
|
|
GListAddTail(pi->lines, li);
|
|
|
|
return(li);
|
|
}
|
|
|
|
static void
|
|
ParsePlainData(pi)
|
|
PlainInfo pi;
|
|
{
|
|
char *fcp, *cp, *lcp;
|
|
MIMEHeader mh;
|
|
|
|
SinkGetData(pi->wp, &(pi->data), &(pi->len), &mh);
|
|
|
|
fcp = (char *)(pi->data + pi->off);
|
|
lcp = (char *)(pi->data + pi->len);
|
|
for (cp = fcp; cp < lcp; cp++)
|
|
{
|
|
if (*cp == '\r')
|
|
{
|
|
MakeLine(pi, fcp, cp - fcp);
|
|
pi->off = (byte *)cp - pi->data + 1;
|
|
fcp = cp + 1;
|
|
if (fcp < lcp && *fcp == '\n')
|
|
{
|
|
fcp++;
|
|
pi->off++;
|
|
}
|
|
}
|
|
else if (*cp == '\n')
|
|
{
|
|
MakeLine(pi, fcp, cp - fcp);
|
|
pi->off = (byte *)cp - pi->data + 1;
|
|
fcp = cp + 1;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
PlainAdd(closure)
|
|
void *closure;
|
|
{
|
|
ParsePlainData((PlainInfo)closure);
|
|
return;
|
|
}
|
|
|
|
static void
|
|
PlainEnd(closure)
|
|
void *closure;
|
|
{
|
|
PlainInfo pi = (PlainInfo)closure;
|
|
|
|
ParsePlainData(pi);
|
|
|
|
if (pi->off < pi->len)
|
|
{
|
|
MakeLine(pi, (char *)(pi->data + pi->off), pi->len - pi->off);
|
|
}
|
|
|
|
pi->height += pi->lineheight;
|
|
GUISetDimensions(pi->wd, pi->width, pi->height);
|
|
|
|
return;
|
|
}
|
|
|
|
static bool
|
|
PlainExpose(closure, x, y, width, height)
|
|
void *closure;
|
|
int x, y;
|
|
unsigned int width, height;
|
|
{
|
|
LineInfo li;
|
|
PlainInfo pi = (PlainInfo)closure;
|
|
Dimension swidth;
|
|
|
|
XSetFont(pi->dpy, pi->gc, pi->font->fid);
|
|
XSetForeground(pi->dpy, pi->gc, pi->fg);
|
|
|
|
for (li = (LineInfo)GListGetHead(pi->lines); li != NULL;
|
|
li = (LineInfo)GListGetNext(pi->lines))
|
|
{
|
|
if (li == pi->searchcur)
|
|
{
|
|
XDrawString(pi->dpy, pi->win, pi->gc, PLAIN_MARGIN, li->y + pi->baseline,
|
|
li->s, pi->searchstr - li->s);
|
|
swidth = XTextWidth(pi->font, li->s, pi->searchstr - li->s);
|
|
|
|
XSetForeground(pi->dpy, pi->gc, pi->bg);
|
|
XSetBackground(pi->dpy, pi->gc, pi->fg);
|
|
|
|
XDrawString(pi->dpy, pi->win, pi->gc,
|
|
PLAIN_MARGIN + swidth, li->y + pi->baseline,
|
|
pi->searchstr, pi->searchlen);
|
|
|
|
XSetForeground(pi->dpy, pi->gc, pi->fg);
|
|
XSetBackground(pi->dpy, pi->gc, pi->bg);
|
|
|
|
swidth = XTextWidth(pi->font, pi->searchstr, pi->searchlen);
|
|
|
|
XDrawString(pi->dpy, pi->win, pi->gc,
|
|
PLAIN_MARGIN + swidth, li->y + pi->baseline,
|
|
pi->searchstr + pi->searchlen,
|
|
li->len - (pi->searchstr - li->s) - pi->searchlen);
|
|
|
|
}
|
|
else
|
|
{
|
|
XDrawString(pi->dpy, pi->win, pi->gc,
|
|
PLAIN_MARGIN, li->y + pi->baseline,
|
|
li->s, (int)li->len ); /* what to do about this ? */
|
|
}
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
static bool
|
|
PlainMouse(closure, x, y, action)
|
|
void *closure;
|
|
int x, y;
|
|
char *action;
|
|
{
|
|
return(true);
|
|
}
|
|
|
|
static bool
|
|
PlainMotion(closure, x, y)
|
|
void *closure;
|
|
int x, y;
|
|
{
|
|
return(true);
|
|
}
|
|
|
|
/*
|
|
* PlainQuery
|
|
*/
|
|
static byte *
|
|
PlainQuery(closure, key)
|
|
void *closure;
|
|
char *key;
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* PlainSearch
|
|
*/
|
|
static int
|
|
PlainSearch(closure, data, mode)
|
|
void *closure;
|
|
char *data;
|
|
int mode;
|
|
{
|
|
LineInfo li;
|
|
PlainInfo pi = (PlainInfo)closure;
|
|
char *cp, *lcp, *xcp, *dcp, *ldcp;
|
|
size_t dlen;
|
|
bool found;
|
|
|
|
dlen = strlen(data);
|
|
for (li = (LineInfo)GListGetHead(pi->lines); li != NULL;
|
|
li = (LineInfo)GListGetNext(pi->lines))
|
|
{
|
|
lcp = li->s + li->len;
|
|
for (cp = li->s; cp < lcp; cp++)
|
|
{
|
|
if (*cp == data[0])
|
|
{
|
|
dcp = data;
|
|
ldcp = data + dlen;
|
|
found = true;
|
|
for (xcp = cp; dcp < ldcp && xcp < lcp; dcp++, xcp++)
|
|
{
|
|
if (*xcp != *dcp)
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
}
|
|
if (found && dcp == ldcp)
|
|
{
|
|
GUISetScrollPosition(pi->wd, 0, -(li->y));
|
|
pi->searchcur = li;
|
|
pi->searchstr = cp;
|
|
pi->searchlen = dlen;
|
|
pi->searchline = li;
|
|
pi->searchchar = xcp;
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* PlainDestroy
|
|
*/
|
|
static void
|
|
PlainDestroy(closure)
|
|
void *closure;
|
|
{
|
|
PlainInfo pi = (PlainInfo)closure;
|
|
|
|
MPDestroy(pi->mp);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* PlainCancel
|
|
*/
|
|
static void
|
|
PlainCancel(closure)
|
|
void *closure;
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* PlainInit
|
|
*/
|
|
static void *
|
|
PlainInit(wn, closure, state)
|
|
ChimeraRender wn;
|
|
void *closure;
|
|
void *state;
|
|
{
|
|
PlainInfo pi;
|
|
MemPool mp;
|
|
char *name;
|
|
unsigned int width, height;
|
|
ChimeraSink wp;
|
|
ChimeraGUI wd;
|
|
|
|
wd = RenderToGUI(wn);
|
|
wp = RenderToSink(wn);
|
|
|
|
mp = MPCreate();
|
|
pi = (PlainInfo)MPCGet(mp, sizeof(PlainInfoP));
|
|
pi->mp = mp;
|
|
pi->wp = wp;
|
|
pi->lineheight = 40;
|
|
pi->lines = GListCreateX(mp);
|
|
pi->wd = wd;
|
|
pi->cres = RenderToResources(wn);
|
|
|
|
pi->dpy = GUIToDisplay(wd);
|
|
pi->win = GUIToWindow(wd);
|
|
pi->gc = DefaultGC(pi->dpy, DefaultScreen(pi->dpy));
|
|
|
|
pi->lineSpace = 2;
|
|
|
|
name = ResourceGetString(pi->cres, "plain.font");
|
|
if (name == NULL) name = "fixed";
|
|
if ((pi->font = XLoadQueryFont(pi->dpy, name)) == NULL)
|
|
{
|
|
fprintf (stderr, "Could not get default font.\n");
|
|
fflush(stderr);
|
|
return(NULL);
|
|
}
|
|
|
|
pi->baseline = pi->font->ascent + pi->lineSpace;
|
|
pi->lineheight = pi->font->ascent + pi->font->descent + pi->lineSpace;
|
|
|
|
pi->height = PLAIN_MARGIN;
|
|
|
|
GUIGetNamedColor(wd, "black", &(pi->fg));
|
|
pi->bg = GUIBackgroundPixel(wd);
|
|
|
|
XSetForeground(pi->dpy, pi->gc, pi->fg);
|
|
|
|
GUISetScrollBar(wd, true);
|
|
if (GUIGetDimensions(wd, &width, &height) == -1)
|
|
{
|
|
GUISetDimensions(wd, width, height);
|
|
/* Now grab the internal dimensions again */
|
|
if (GUIGetDimensions(wd, &width, &height) == -1)
|
|
{
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
return(pi);
|
|
}
|
|
|
|
/*
|
|
* InitModule_Plain
|
|
*/
|
|
int
|
|
InitModule_Plain(cres)
|
|
ChimeraResources cres;
|
|
{
|
|
ChimeraRenderHooks rh;
|
|
|
|
memset(&rh, 0, sizeof(rh));
|
|
rh.class_destroy = NULL;
|
|
rh.content = "text/plain";
|
|
rh.init = PlainInit;
|
|
rh.add = PlainAdd;
|
|
rh.end = PlainEnd;
|
|
rh.destroy = PlainDestroy;
|
|
rh.search = PlainSearch;
|
|
rh.query = PlainQuery;
|
|
rh.cancel = PlainCancel;
|
|
rh.expose = PlainExpose;
|
|
rh.select = PlainMouse;
|
|
rh.motion = PlainMotion;
|
|
RenderAddHooks(cres, &rh);
|
|
|
|
return(0);
|
|
}
|