summaryrefslogtreecommitdiff
path: root/dviware/mdvi/x11
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/mdvi/x11
Initial commit
Diffstat (limited to 'dviware/mdvi/x11')
-rw-r--r--dviware/mdvi/x11/Makefile.in60
-rw-r--r--dviware/mdvi/x11/dvi.c1008
-rw-r--r--dviware/mdvi/x11/dvidraw.c1510
-rw-r--r--dviware/mdvi/x11/x11.c750
-rw-r--r--dviware/mdvi/x11/x11.h118
5 files changed, 3446 insertions, 0 deletions
diff --git a/dviware/mdvi/x11/Makefile.in b/dviware/mdvi/x11/Makefile.in
new file mode 100644
index 0000000000..b53678361e
--- /dev/null
+++ b/dviware/mdvi/x11/Makefile.in
@@ -0,0 +1,60 @@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+-include ../config.mk
+
+OBJS = dvi.o dvidraw.o x11.o
+SOURCES = dvi.c dvidraw.c x11.c
+HEADERS = x11.h
+OTHERFILES = Makefile.in
+
+INCLUDES = -I$(srcdir) -I.. -I$(srcdir)/../include
+LOCAL_CFLAGS = $(INCLUDES) $(KPSE_CFLAGS) $(X_CFLAGS)
+ALL_CFLAGS = $(CFLAGS) $(ADDCFLAGS) $(CPPFLAGS) $(LOCAL_CFLAGS)
+
+ALL_LIBS = $(KPSE_LIBS) $(T1LIB_LIBS) $(FREETYPE_LIBS) \
+ $(X_LIBS) $(ADDLIBS) $(LIBS)
+
+DEPSOURCES = $(SOURCES)
+DEPCFLAGS = $(ALL_CFLAGS)
+DISTFILES = $(SOURCES) $(HEADERS) $(OTHERFILES)
+
+CLEANABLE += $(OBJS) $(PROGRAMS) core
+DISTCLEANABLE += Makefile
+
+MDVILIB = ../lib/mdvi.a
+PROGRAM = mdvi
+
+.PHONY: all
+all: $(PROGRAM)
+
+mdvi: $(MDVILIB) $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(MDVILIB) $(ALL_LIBS)
+
+.PHONY: install
+install:
+ $(MKINSTALLDIRS) $(bindir)
+ $(INSTALL) -m 755 $(PROGRAM) $(bindir)/$(PROGRAM)
+
+.PHONY: uninstall
+uninstall:
+ $(RM) $(bindir)/$(PROGRAM)
+
+.PHONY: $(MDVILIB)
+$(MDVILIB):
+ $(MAKE) -C ../lib
+
+../config.mk:
+ @echo "*** Error: Run \`configure' in the top source directory."
+ @exit 1
+
+.c.o:
+ $(CC) $(ALL_CFLAGS) -c $<
+
+dvi.o: dvi.c
+ $(CC) $(ALL_CFLAGS) $(T1LIB_CFLAGS) $(FREETYPE_CFLAGS) -DLOCALEDIR=\"$(localedir)\" -c $<
+
+include $(FRAGDIR)/dist.mk
+include $(FRAGDIR)/targets.mk
+include $(FRAGDIR)/depend.mk
diff --git a/dviware/mdvi/x11/dvi.c b/dviware/mdvi/x11/dvi.c
new file mode 100644
index 0000000000..e47b6e8de1
--- /dev/null
+++ b/dviware/mdvi/x11/dvi.c
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "mdvi.h"
+#include "private.h"
+#include "defaults.h"
+#include "version.h"
+
+#if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
+#include <locale.h>
+#endif
+
+int profiling = 0;
+int batch_mode = 0;
+int registered_fonts = 0;
+
+#if WITH_TYPE1_FONTS
+extern char *T1_GetLibIdent();
+#endif
+
+extern char *kpathsea_version_string;
+extern int init_x11(void);
+extern void view_page(DviContext *, int);
+extern int mdvi_create_window(DviContext *, const char *);
+extern Ulong get_color_byname __PROTO((const char *));
+
+/* font types */
+extern DviFontInfo pk_font_info;
+extern DviFontInfo pkn_font_info;
+extern DviFontInfo gf_font_info;
+extern DviFontInfo vf_font_info;
+#ifdef WITH_OMEGA
+extern DviFontInfo ovf_font_info;
+#endif
+#ifdef WITH_TRUETYPE_FONTS
+extern DviFontInfo tt_font_info;
+#endif
+#ifdef WITH_TYPE1_FONTS
+extern DviFontInfo t1_font_info;
+#endif
+#ifdef WITH_AFM_FILES
+extern DviFontInfo afm_font_info;
+#endif
+extern DviFontInfo tfm_font_info;
+#ifdef WITH_OMEGA
+extern DviFontInfo ofm_font_info;
+#endif
+
+static struct fontinfo {
+ DviFontInfo *info;
+ char *desc;
+ int klass;
+} known_fonts[] = {
+ {&vf_font_info, "Virtual fonts", 0},
+#ifdef WITH_OMEGA
+ {&ovf_font_info, "Omega's virtual fonts", 0},
+#endif
+#ifdef WITH_TRUETYPE_FONTS
+ {&tt_font_info, "TrueType fonts", 0},
+#endif
+#ifdef WITH_TYPE1_FONTS
+ {&t1_font_info, "Type1 PostScript fonts", 0},
+#endif
+ {&pk_font_info, "Packed bitmap (auto-generated)", 1},
+ {&pkn_font_info, "Packed bitmap", -2},
+ {&gf_font_info, "Metafont's generic font format", 1},
+#ifdef WITH_OMEGA
+ {&ofm_font_info, "Omega font metrics", -1},
+#endif
+ {&tfm_font_info, "TeX font metrics", -1},
+#ifdef WITH_AFM_FILES
+ {&afm_font_info, "Adobe font metrics", -1},
+#endif
+ {0, 0}
+};
+
+static int print_info_only = 0;
+char *logfile;
+DviAppConfig *mdvi_app;
+char *program_name;
+
+static char mdvi_banner[] =
+"mdvi " MDVI_VERSION " -- A TeX DVI previewer for Unix\n"
+"Copyright (C) 2000 Matias Atria\n"
+"This program is free software; you can redistribute it and/or modify\n"
+"it under certain conditions. Try `mdvi --info' for details\n\n";
+
+static char mdvi_long_banner[] =
+"mdvi " MDVI_VERSION " -- A TeX DVI previewer for Unix\n"
+"Copyright (C) 2000 Matias Atria\n\n"
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 2 of the License, or\n"
+"(at your option) any later version.\n\n"
+"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
+"PARTICULAR PURPOSE.\n\n";
+
+static const char *orientstr[] = {
+ "tblr", "tbrl", "btlr", "btrl",
+ "rp90", "rm90", "irp90", "irm90"
+};
+
+static const char usage_help[] =
+"Usage: mdvi [OPTION] ... DVIFILE\n\n"
+"Options:\n"
+" -a, --font-types=FONTS\n"
+" specify which font types to use\n"
+" -A, --fonts-omitted[=FONTS]\n"
+" specify which font types not to use by default\n"
+" -b, --boxes\n"
+" see the world through TeX's eyes\n"
+" -B, --bg=COLOR\n"
+" set background color\n"
+" -d, --debug=MASK\n"
+" set debug mask (see --explain debug for more info)\n"
+" -D, --dpi=DPI\n"
+" set resolution to DPI pixels per inch\n"
+" -e, --explain=TOPIC\n"
+" give more detailed help on a particular topic, use topic `list' to\n"
+" see the list of known topics\n"
+" -f, --fallback-font=FONT-NAME\n"
+" font to use when one is missing\n"
+" -F, --fg=COLOR\n"
+" set foreground color\n"
+" -G, --gamma=NUMBER\n"
+" gamma correction for antialiased glyphs\n"
+" -h, --help[=TOPIC]\n"
+" display help on a command line option. TOPIC may be the long name of an\n"
+" option, or one of `papers' or `units'.\n"
+" -H, --horizontal-margin=UNIT\n"
+" size of horizontal margins\n"
+" -i, --info\n"
+" display licensing information and default settings\n"
+" -l, --log-file=[LEVEL:]FILE\n"
+" save all messages with priority at least LEVEL to FILE\n"
+" -m, --mf-mode=MODE\n"
+" Metafont mode to use when creating fonts\n"
+" -M, --magnification=NUMBER\n"
+" magnification factor (NUMBER = TeX's NUMBER/1000.0)\n"
+" -N, --mono\n"
+" to force monochrome configuration\n"
+" -o, --orientation=ORIENTATION\n"
+" set document on-screen orientation\n"
+" --orientation=help\n"
+" print option details and exit\n"
+" -p, --paper=NAME\n"
+" paper type to use\n"
+" --paper=list\n"
+" print known paper types and exit\n"
+" -P, --page=NUMBER\n"
+" start viewing page NUMBER\n"
+" -r, --page-range=RANGE\n"
+" specify which files should be read\n"
+" --page-range=help\n"
+" print option details and exit\n"
+" -s, --shrink=NUMBER\n"
+" shrinking factor for glyphs\n"
+" -S, --sort-pages[=TYPE]\n"
+" set page sorting type, where `TYPE' is one of up, down, random,\n"
+" dviup, dvidown or none. If `TYPE' is not specified, `up' is assumed\n"
+" -t, --pixel-density=NUMBER\n"
+" pixel density for antialiased glyphs (0 <= NUMBER <= 100)\n"
+" -T, --tex-page=NUMBER\n"
+" start viewing TeX's (i.e. document's) page NUMBER\n"
+" -V, --vertical-margin=UNIT\n"
+" size of vertical margins\n"
+" -x, --xdpi=DPI\n"
+" set horizontal resolution\n"
+" -y, --ydpi=DPI\n"
+" set vertical resolution\n"
+" -z, --batch\n"
+" run in batch mode (no UI)\n";
+
+static const char debug_help[] =
+"Debugging masks: -d MASK, --debug=MASK\n"
+" MASK is a numerical value, obtained by ORing the values given below\n"
+"or a series of mask names separated by commas or by `|'. The masks known\n"
+"to MDVI are:\n\n"
+" Name Value Description\n"
+"------------------------------------------------------------------------\n"
+" opcode 1 DVI opcodes and arguments in `dvitype' style\n"
+" fonts 2 messages related to the management of fonts\n"
+" files 4 file operations\n"
+" dvi 8 operations on DVI files\n"
+" params 16 manipulation of DVI parameters\n"
+" special 32 DVI specials\n"
+" device 64 device-specific messages\n"
+" glyphs 128 loading of glyphs (lots of output)\n"
+" paths 256 paths configuration in kpathsea\n"
+" search 512 file searches by kpathsea\n"
+" vars 1024 traces environment variables (MDVI and kpathsea)\n"
+" bitops 2048 bitmap operations (scaling, flipping, etc)\n"
+" bitdata 4096 bitmap bits (MASSIVE amounts of output)\n"
+" type1 8192 management of Type1 fonts\n"
+" tt 16384 management of TrueType fonts\n"
+" --- 32768 unused\n"
+" fontmaps 65536 things involving font maps and encodings\n";
+
+static const char orientation_help[] =
+"Orientation options: -o ORIENTATION, --orienation=ORIENTATION\n"
+" ORIENTATION is one of TBLR, TBRL, BTLR, BTRL, RP90, RM90, IRP90 or\n"
+"IRM90, where TB=top-to-bottom, LR=left-to-right, etc.,\n"
+"RP=rotate-positively (i.e. counter-clockwise), RM=rotate-negatively,\n"
+"and the last two are the same than these, after a reflection with\n"
+"respect to an imaginary vertical axis. The values Portrait, Landscape\n"
+"and Seascape are synonyms for TBLR, RM90 and RP90, respectively.\n";
+
+static const char range_help[] =
+"Page range selection options: -r RANGE-SPEC, --page-range=RANGE-SPEC\n"
+" RANGE-SPEC consists of up to 11 RANGE-LIST strings, separated by dots.\n"
+"If there is only one list, it is assumed to apply to DVI page numbers.\n"
+"Otherwise, each list applies to the corresponding TeX page \\counter (10 per\n"
+"page). A RANGE-LIST is either empty or a comma-separated list of ranges, at\n"
+"least one of which must contain the page counter in order for the page to be\n"
+"processed. A range has the form LOWER:UPPER:STEP, which specifies the\n"
+"sequence LOWER + STEP * n, for 0 <= n <= (UPPER - LOWER) / STEP. A\n"
+"RANGE-LIST may optionally be written inside braces, for clarity, but no\n"
+"white space is allowed anywhere in a RANGE-SPEC. Any part of a range (except\n"
+"for the `:') may be omitted, in which case LOWER, UPPER and STEP take the\n"
+"default values -INFINITY, +INFINITY and 1, respectively, except in two\n"
+"cases: (1) The form ::STEP specifies the sequence `STEP * n' for `n' an\n"
+"arbitrary integer, and (2) In the form :UPPER:STEP, LOWER is set to\n"
+"`PREV_UPPER + 1' if the preceding range had a finite upper bound, and to\n"
+"-INFINITY otherwise. An empty RANGE-LIST (written as `*') is equivalent\n"
+"to {::}.\n"
+" If the first RANGE-LIST begins with `D' or `d', it is assumed to apply to \n"
+"DVI page numbers, regardless of whether it is the only RANGE-LIST in the \n"
+"RANGE-SPEC.\n"
+"Examples:\n"
+" ::2 Matches all even DVI page numbers.\n"
+" 1::2 Matches all odd DVI page numbers.\n"
+" {1:4}.*.{1:11:2,:15}.*\n"
+" Matches \\counter0=1,2,3,4, and \\counter1=1,3,5,7,11,12,13,14,15\n"
+" D{::2}.{5:}.*\n"
+" Matches all even DVI page numbers AND \\counter0 >= 5.\n";
+
+static const char units_help[] =
+"Units:\n"
+" MDVI recognizes all TeX units, plus some more:\n"
+" Metric units: meters (mt), centimeters (cm), milimeters (mm)\n"
+" US units: yard (yd), feet (ft), inches (in)\n"
+" TeX units: points (pt), picas (pc), didot points (dd),\n"
+" ciceros (cc), scaled points (sp)\n"
+" Other units: big/PostScript points (bp), charspace (cs)\n";
+
+static const char log_help[] =
+"Logfile option: -l, --log-file=[LEVEL:]FILE\n"
+" Tells MDVI to save all messages with priority at least LEVEL to FILE.\n"
+"LEVEL is one of `info', `warn', `err' and `debug'. FILE can be the name\n"
+"of a file or the values 1 (standard output) or 2 (standard error). The\n"
+"name `-' is equivalent to `1'.\n";
+
+static const char font_type_help[] =
+"Font support option: -a, --font-types=FONTS\n"
+" Tells MDVI which font types should be supported. FONTS is a comma\n"
+"separated list of font `families' that MDVI is to recognize during this\n"
+"run. A type name can be preceded by a class ID, which will become the\n"
+"default class for all fonts in the FONTS specification after that ID.\n"
+"Examples:\n"
+" --font-types=0:vf,t1,tt,1:pk,m:tfm\n"
+"This entry means: put the font types vf (virtual fonts), t1 (Type1) and\n"
+"tt (TrueType) in class 0 (highest priority). In class 1, put type pk\n"
+"(packet bitmap format). Finally, put type tfm (TeX font metric format)\n"
+"in the metric class. Thus, MDVI will not lookup fonts other than these\n"
+"to resolve the font references in the DVI file.\n"
+"\n"
+"To see the list of all font types known to MDVI, and their default class,\n"
+"use `--font-types=list'. For a brief description of the font lookup\n"
+"mechanism, use `--explain=fonts'.\n";
+
+static struct {
+ const char *topic;
+ const char *desc;
+ const char *string;
+} topics[] = {
+ {"log", "log file options", log_help},
+ {"mdvi", "command line options", usage_help},
+ {"units", "units supported by MDVI and their syntax", units_help},
+ {"orientation", "syntax for specifying orientations", orientation_help},
+ {"ranges", "syntax for specifying page ranges", range_help},
+ {"debug", "debugging options", debug_help},
+ {"font-types", "font support selection", font_type_help},
+ {0, 0}
+};
+
+static void print_paper_specs(const char *title, DviPaperSpec *spec)
+{
+ int i;
+ char buf[256];
+ int len = 0;
+
+ printf("%s:\n", title);
+ for(i = 0; spec[i].name; i++) {
+ int n;
+
+ n = sprintf(buf, " %10s: %6s x %s",
+ spec[i].name,
+ spec[i].width,
+ spec[i].height);
+ while(n < 30)
+ buf[n++] = ' ';
+ buf[n] = 0;
+ printf("%s", buf);
+ if(len || n >= 78) {
+ fputc('\n', stdout);
+ len = 0;
+ } else
+ len = n;
+ }
+ if(len) fputc('\n', stdout);
+}
+
+static void print_fonts(void)
+{
+ struct fontinfo *fi;
+
+ printf("Known font formats:\n\n");
+ printf("%8s %-30s Class\n", "Name", "Description");
+ printf("-----------------------------------------------\n");
+ for(fi = known_fonts; fi->info; fi++) {
+ printf("%8s %-30s ", fi->info->name, fi->desc);
+ if(fi->klass == -1)
+ putchar('M');
+ else if(fi->klass < -1)
+ putchar('-');
+ else
+ printf("%d", fi->klass);
+ putchar('\n');
+ }
+ putchar('\n');
+ printf("Priority classes: 0 (highest) - %d (lowest), M (metric)\n",
+ mdvi_get_font_classes());
+}
+
+static void print_papers(void)
+{
+ DviPaperSpec *spec;
+
+ spec = mdvi_get_paper_specs(MDVI_PAPER_CLASS_ISO);
+ if(spec != NULL) {
+ print_paper_specs(_("ISO paper types"), spec);
+ mdvi_free_paper_specs(spec);
+ }
+ spec = mdvi_get_paper_specs(MDVI_PAPER_CLASS_US);
+ if(spec != NULL) {
+ print_paper_specs(_("US paper types"), spec);
+ mdvi_free_paper_specs(spec);
+ }
+ printf(
+"Custom paper types:\n"
+" <NUMBER>x<NUMBER><UNIT> (e.g., 210x292.7mm)\n"
+" <NUMBER><UNIT>,<NUMBER><UNIT> (e.g., 208.5mm,13in)\n");
+}
+
+static void usage(const char *string, int exit_code)
+{
+ const char *help = NULL;
+ int i;
+
+ if(string == NULL)
+ help = usage_help;
+ else for(i = 0; topics[i].topic; i++) {
+ if(STRCEQ(string, topics[i].topic)) {
+ help = topics[i].string;
+ break;
+ }
+ }
+
+ printf("%s", mdvi_banner);
+ if(help == NULL)
+ fprintf(stderr, _("%s: I don't know about that\n"), string);
+ else
+ printf("%s", help);
+ exit(exit_code);
+}
+
+
+void print_config(DviAppConfig *app)
+{
+ int i;
+
+ printf("%s", mdvi_long_banner);
+ printf(
+"Environment variables, and compiled defaults:\n"
+" MDVI_DPI resolution (in pixels per inch) %d\n"
+" MDVI_VDPI vertical resolution %d\n"
+" MDVI_MAGNIFICATION magnification (1.0 = normal) %.2f\n"
+" MDVI_SHRINKING shrinking factor %d\n"
+" MDVI_HSHRINK horizontal shrinking factor %d\n"
+" MDVI_VSHRINK vertical shrinking factor %d\n"
+" MDVI_HDRIFT horizontal drifting tolerance %d\n"
+" MDVI_VDRIFT vertical drifting tolerance %d\n"
+" MDVI_PIXEL_DENSITY pixel density %d\n"
+" MDVI_GAMMA gamma correction factor %.2f\n"
+" MDVI_PAPER paper name %s\n"
+" MDVI_HMARGIN horizontal margins around pages %s\n"
+" MDVI_VMARGIN vertical margins around pages %s\n"
+" MDVI_FALLBACK_FONT font to use when one is missing %s\n"
+" MDVI_MFMODE default metafont mode %s\n"
+" MDVI_HRUNITS units for horizontal rulers %s\n"
+" MDVI_VRUNITS units for vertical rulers %s\n"
+" MDVI_ORIENTATION page on-screen orientation %s\n"
+" MDVI_FONTSPEC default font configuration builtin\n"
+" MDVI_FONTOMIT fonts types omitted by default PKN\n"
+" MDVI_FOREGROUND foreground color %s\n"
+" MDVI_BACKGROUND background color %s\n"
+" MDVI_DEBUG debug mask\n",
+ MDVI_DPI,
+ MDVI_VDPI,
+ MDVI_MAGNIFICATION,
+ MDVI_DEFAULT_SHRINKING,
+ -1, /* HSHRINK */
+ -1, /* VSHRINK */
+ -1, /* HDRIFT */
+ -1, /* VDRIFT */
+ MDVI_DEFAULT_DENSITY,
+ MDVI_DEFAULT_GAMMA,
+ MDVI_PAPERNAME,
+ MDVI_HMARGIN,
+ MDVI_VMARGIN,
+ MDVI_FALLBACK_FONT,
+ MDVI_MFMODE ? MDVI_MFMODE : "auto",
+ MDVI_HRUNITS,
+ MDVI_VRUNITS,
+ MDVI_ORIENTATION,
+ MDVI_FOREGROUND,
+ MDVI_BACKGROUND);
+
+ putchar('\n');
+ printf("Current configuration:\n");
+ printf(" dpi: %d\n", app->params.dpi);
+ printf(" vdpi: %d\n", app->params.vdpi);
+ printf(" magnification: %.2f\n", app->params.mag);
+ printf(" hshrink: %d\n", app->params.hshrink);
+ printf(" vshrink: %d\n", app->params.vshrink);
+ printf(" hdrift: %d\n", app->params.hdrift);
+ printf(" vdrift: %d\n", app->params.vdrift);
+ printf(" pixel density: %d\n", app->params.density);
+ printf(" gamma factor: %.2f\n", app->params.gamma);
+ printf(" paper type: %s\n", app->paper.name);
+ printf(" margins: (%s,%s)\n", app->hmargin, app->vmargin);
+ printf(" fallback font: %s\n", app->fallback_font);
+ printf(" Metafont mode: %s\n", app->mfmode ? app->mfmode : "auto");
+ printf(" ruler units: (%s,%s)\n", app->hrule_units, app->vrule_units);
+ printf(" orientation: %s\n", orientstr[app->params.orientation]);
+ printf(" font types: %s\n", app->fontspec ? app->fontspec : "all");
+ printf(" fonts omitted: %s\n", app->fontunspec ? app->fontunspec : "none");
+ printf(" foreground: %s\n", app->fgcolor);
+ printf(" background: %s\n", app->bgcolor);
+
+ putchar('\n');
+ printf("Fonts supported in this configuration:\n");
+ for(i = -1; i <= mdvi_get_font_classes(); i++) {
+ char ** list;
+ int j;
+
+ list = mdvi_list_font_class(i);
+ if(list == NULL)
+ break;
+ printf(" Class ");
+ if(i == -1)
+ printf("M: ");
+ else
+ printf("%d: ", i);
+ if(list[0] == NULL)
+ printf("None");
+ else for(j = 0; list[j]; j++) {
+ printf("%s%s", j ? ", " : "", list[j]);
+ xfree(list[j]);
+ }
+ xfree(list);
+ putchar('\n');
+ }
+}
+
+int process_options(DviAppConfig *app, int argc, char **argv)
+{
+ static struct option dviopts[] = {
+ {"batch", 0, 0, 'z'},
+ {"debug", 1, 0, 'd'},
+ {"help", 2, 0, 'h'},
+ {"info", 0, 0, 'i'},
+ {"bg", 1, 0, 'B'},
+ {"boxes", 0, 0, 'b'},
+ {"dpi", 1, 0, 'D'},
+ {"debug", 2, 0, 'd'},
+ {"explain", 1, 0, 'e'},
+ {"fallback-font", 1, 0, 'f'},
+ {"fg", 1, 0, 'F'},
+ {"font-types", 2, 0, 'a'},
+ {"fonts-omitted", 2, 0, 'A'},
+ {"gamma", 1, 0, 'G'},
+ {"horizontal-margin", 1, 0, 'H'},
+ {"log-file", 1, 0, 'l'},
+ {"magnification", 1, 0, 'M'},
+ {"mf-mode", 1, 0, 'm'},
+ {"mono", 0, 0, 'N'},
+ {"orientation", 1, 0, 'o'},
+ {"page", 1, 0, 'P'},
+ {"page-range", 1, 0, 'r'},
+ {"paper", 1, 0, 'p'},
+ {"pixel-density", 1, 0, 't'},
+ {"shrink", 1, 0, 's'},
+ {"sort-pages", 2, 0, 'S'},
+ {"tex-page", 1, 0, 'T'},
+ {"vertical-margin", 1, 0, 'V'},
+ {"xdpi", 1, 0, 'x'},
+ {"ydpi", 1, 0, 'y'},
+ {"version", 0, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ while(1) {
+ int c;
+ int ndx;
+ char *arg;
+
+ c = getopt_long(argc, argv,
+ "a::A::d:hiB:bD:e:f:F:G:H:il:M:m:No:P:r:p:t:s:S:T:V:x:y:zv",
+ dviopts, &ndx);
+
+ arg = optarg;
+ if(c == -1)
+ break;
+
+ switch(c) {
+ case 'A':
+ case 'a':
+ if(arg && STRCEQ(arg, "list")) {
+ printf("%s", mdvi_banner);
+ print_fonts();
+ exit(EXIT_SUCCESS);
+ } else if(arg && STRCEQ(arg, "help"))
+ usage("font-types", EXIT_SUCCESS);
+ if(c == 'a')
+ registered_fonts += configure_fonts(arg, 1);
+ else
+ configure_fonts(arg, 0);
+ break;
+ case 'b':
+ app->params.flags |= MDVI_PARAM_CHARBOXES;
+ break;
+ case 'B':
+ app->bgcolor = arg;
+ break;
+ case 'd': {
+ long mask;
+
+ if(STREQ(arg, "list"))
+ usage("debug", EXIT_SUCCESS);
+ if(mdvi_getint(arg, &mask) < 0)
+ mask = (long)mdvi_get_debugmask(arg);
+ add_debug_mask((Uint32)mask);
+ break;
+ }
+ case 'x':
+ case 'y':
+ case 'D': {
+ long dpi;
+
+ if(mdvi_getint(arg, &dpi) < 0 || dpi <= 0)
+ warning(_("resolution must be a positive integer\n"));
+ else if(c == 'x')
+ app->params.dpi = (Uint)dpi;
+ else if(c == 'y')
+ app->params.vdpi = (Uint)dpi;
+ else
+ app->params.dpi = app->params.vdpi = (Uint)dpi;
+ break;
+ }
+ case 'e':
+ if(STRCEQ(arg, "list")) {
+ int i;
+
+ printf("%s", mdvi_banner);
+ printf(_("Known topics\n"));
+ for(i = 0; topics[i].topic; i++)
+ printf(" %-12s: %s\n",
+ topics[i].topic, topics[i].desc);
+ exit(EXIT_SUCCESS);
+ } else
+ usage(arg, EXIT_SUCCESS);
+ break;
+ case 'f':
+ app->fallback_font = arg;
+ break;
+ case 'F':
+ app->fgcolor = arg;
+ break;
+ case 'g':
+ /* UNUSED */
+ break;
+ case 'G':
+ app->params.gamma = strtod(arg, NULL);
+ break;
+ case 'h':
+ usage(NULL, EXIT_SUCCESS);
+ break;
+ case 'H':
+ app->hmargin = arg;
+ break;
+ case 'i':
+ print_info_only = 1;
+ break;
+ case 'l':
+ if(STRNEQ(arg, "info:", 5)) {
+ arg += 5;
+ mdvi_set_loglevel(LOG_INFO);
+ } else if(STRNEQ(arg, "warn:", 5)) {
+ arg += 5;
+ mdvi_set_loglevel(LOG_WARN);
+ } else if(STRNEQ(arg, "err:", 4)) {
+ arg += 4;
+ mdvi_set_loglevel(LOG_ERROR);
+ } else if(STRNEQ(arg, "debug:", 6)) {
+ arg += 6;
+ mdvi_set_loglevel(LOG_DEBUG);
+ } else
+ mdvi_set_loglevel(LOG_WARN);
+ if(*arg == 0 || STREQ(arg, "-") || atoi(arg) == 1)
+ mdvi_set_logstream(stdout);
+ else if(atoi(arg) == 2)
+ mdvi_set_logstream(stderr);
+ else
+ mdvi_set_logfile(arg);
+ break;
+ case 'm':
+ app->mfmode = arg;
+ break;
+ case 'M': {
+ double mag;
+
+ if(mdvi_getfloat(arg, &mag) < 0 || mag <= 0) {
+ warning(_("magnification must be positive\n"));
+ } else
+ app->params.mag = mag;
+ break;
+ }
+ case 'N':
+ app->params.flags &= ~MDVI_PARAM_ANTIALIASED;
+ app->params.flags |= MDVI_PARAM_MONO;
+ break;
+ case 'o':
+ if(STRCEQ(arg, "help"))
+ usage("orientation", EXIT_SUCCESS);
+ app->params.orientation = mdvi_getorient(arg);
+ break;
+ case 'p':
+ if(STRCEQ(arg, "help") || STRCEQ(arg, "list")) {
+ print_papers();
+ exit(EXIT_SUCCESS);
+ }
+ app->paper.name = arg;
+ break;
+ case 'P':
+ if(mdvi_getint(arg, (long *)&app->first_page) < 0) {
+ warning(_("page number must be a positive integer\n"));
+ app->first_page = 0;
+ } else
+ app->use_tex_page = 0;
+ break;
+ case 'r':
+ if(STRCEQ(arg, "help"))
+ usage("ranges", EXIT_SUCCESS);
+ app->page_ranges = arg;
+ break;
+ case 's': {
+ long h, v;
+
+ if(sscanf(arg, "%ld,%ld", &h, &v) == 2) {
+ app->params.vshrink = (Uint)v;
+ app->params.hshrink = (Uint)h;
+ } else if(mdvi_getint(arg, &h) < 0 || h < 0) {
+ warning(_("shrinking factor must be a non-negative number\n"));
+ } else
+ app->params.vshrink =
+ app->params.hshrink = (Uint)h;
+ break;
+ }
+ case 'S': {
+ int v;
+
+ if(arg == NULL)
+ app->page_sort = MDVI_PAGE_SORT_UP;
+ else if((v = mdvi_get_pagesort(arg)) < 0) {
+ warning(_("unknown sorting type `%s'\n"),
+ arg);
+ app->page_sort = MDVI_PAGE_SORT_NONE;
+ } else
+ app->page_sort = v;
+ break;
+ }
+ case 't': {
+ long s;
+
+ if(mdvi_getint(arg, &s) < 0 || s < 0)
+ warning(_("pixel density must be a non-negative number\n"));
+ else if(s > 100) {
+ warning(_("pixel density should be less than 100\n"));
+ s = 100;
+ }
+ app->params.density = (Uint)s;
+ break;
+ }
+ case 'T': {
+ long s;
+
+ if(mdvi_getint(arg, &s) < 0)
+ warning(_("tex-page must be an integer\n"));
+ else {
+ app->first_page = (int)s;
+ app->use_tex_page = 1;
+ }
+ break;
+ }
+ case 'V':
+ app->vmargin = arg;
+ break;
+ case 'v': {
+ char *a, *b;
+
+ printf("%s", mdvi_long_banner);
+ /* Check the library versions and report any differences */
+ a = strrchr(KPSE_VERSION, ' ');
+ a = (a ? a + 1 : KPSE_VERSION);
+ b = strrchr(kpathsea_version_string, ' ');
+ b = (b ? b + 1 : kpathsea_version_string);
+ printf("Compiled with kpathsea %s", a);
+ if(!STREQ(a, b))
+ printf(", using %s", b);
+ fputc('\n', stdout);
+ printf("Additional features:\n");
+#ifdef WITH_TYPE1_FONTS
+ printf("\tType1 fonts (t1lib %s)", T1LIB_VERSION);
+ b = T1_GetLibIdent();
+ if(!STREQ(T1LIB_VERSION, b))
+ printf(", using %s", b);
+ fputc('\n', stdout);
+#endif
+#ifdef WITH_TRUETYPE_FONTS
+ printf("\tTrueType fonts (Freetype 1.x)\n");
+#endif
+#ifdef WITH_AFM_FILES
+ printf("\tAFM files\n");
+#endif
+#ifdef WITH_OMEGA
+ printf("\tOmega file formats\n");
+#endif
+#ifdef WITH_REGEX_SPECIALS
+ printf("\tRegex \\specials\n");
+#endif
+ printf("Using %dbit bitmap units\n", BITMAP_BITS);
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ case 'z':
+ batch_mode = 1;
+ break;
+ default:
+ usage(NULL, EXIT_FAILURE);
+ break;
+ }
+ }
+ return optind;
+}
+
+int configure_fonts(const char *spec, int enabled)
+{
+ int done = 0;
+ int klass = -2; /* unspecified */
+ int nclasses;
+ const char *ptr;
+ const char *text;
+ struct fontinfo *type;
+ int count = 0;
+
+ nclasses = mdvi_get_font_classes();
+ if(spec == NULL || STRCEQ(spec, "all")) {
+ for(type = known_fonts; type->info; type++) {
+ if(!enabled)
+ type->klass = -2;
+ else if(type->klass != -2)
+ mdvi_register_font_type(type->info, type->klass);
+ count++;
+ }
+ if(!enabled)
+ DEBUG((DBG_FONTS, "all font types disabled by default\n"));
+ } else for(ptr = text = spec; !done; ptr++) {
+ int len;
+ int k;
+ int status;
+ char *name;
+
+ if(*ptr && *ptr != ',')
+ continue;
+ if(*ptr == 0)
+ done = 1;
+ if((len = ptr - text) == 0)
+ continue;
+ if(len >= 2 && text[1] == ':') {
+ switch(text[0]) {
+ case 'm': case 'M':
+ k = -1;
+ break;
+ case '0': case '1':
+ case '2': case '3':
+ case '4': case '5':
+ case '6': case '7':
+ case '8': case '9':
+ k = *text - '0';
+ break;
+ default:
+ text -= 2; /* will be fixed later */
+ break;
+ }
+ if(k < -1 || k > nclasses) {
+ k = klass;
+ warning("font class %d does not exist\n");
+ }
+ klass = k;
+ text += 2;
+ } else if(*text == ':')
+ k = klass = -3;
+ else
+ k = klass;
+ for(type = known_fonts; type->info; type++) {
+ if(STRNCEQ(type->info->name, text, len))
+ break;
+ }
+ text = ptr + 1;
+ if(type->info == NULL)
+ continue;
+ name = type->info->name;
+ if(!enabled) {
+ DEBUG((DBG_FONTS, "%s fonts disabled by default\n",
+ name));
+ type->klass = -2;
+ continue;
+ }
+ if(k < -2)
+ k = type->klass;
+ /* if the user wants to put a metric font in a real class,
+ * or the other way around, give a warning */
+ if(type->klass < 0 && k >= 0) {
+ warning("adding %s fonts to `real' class %d\n",
+ name, k);
+ } else if(type->klass >= 0 && k < 0) {
+ warning("adding %s fonts to the metric class\n",
+ name);
+ }
+
+ status = mdvi_register_font_type(type->info, k);
+ if(status < 0) {
+ warning("could not register font type `%s' in class %d\n",
+ name, k);
+ } else {
+ DEBUG((DBG_FONTS, "%s: added to font class %d\n",
+ name, k));
+ count++;
+ }
+ }
+ return count;
+}
+
+int main(int argc, char **argv)
+{
+ DviPageSpec *spec;
+ DviContext *ctx;
+ char *dvifile;
+ char *ptr;
+ int i;
+
+#ifdef ENABLE_NLS
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+#endif
+
+ program_name = strrchr(argv[0], '/');
+ if(program_name == NULL)
+ program_name = argv[0];
+ else
+ program_name++;
+ /* get as integer */
+ ptr = getenv("MDVI_DEBUG");
+ if(ptr != NULL) {
+ long x;
+
+ if(mdvi_getint(ptr, &x) < 0)
+ x = (long)mdvi_get_debugmask(ptr);
+ set_debug_mask((Uint32)x);
+ }
+
+ mdvi_app = mdvi_init_app(program_name, "mdvi");
+
+ if(mdvi_app->fontunspec)
+ configure_fonts(mdvi_app->fontunspec, 0);
+
+ i = process_options(mdvi_app, argc, argv);
+ if(i < 0)
+ exit(EXIT_FAILURE);
+
+ dvifile = argv[i];
+
+ /* check that everything is alright */
+ if(mdvi_check_config(mdvi_app) < 0)
+ exit(EXIT_FAILURE);
+
+ if(mdvi_app->page_ranges != NULL)
+ spec = mdvi_parse_page_spec(mdvi_app->page_ranges);
+ else
+ spec = NULL;
+
+ if(mdvi_app->fallback_font == NULL)
+ mdvi_set_fallback_font(mdvi_app->fallback_font);
+#ifdef MDVI_FALLBACK_FONT
+ else
+ mdvi_set_fallback_font(MDVI_FALLBACK_FONT);
+#endif
+
+ /* if no fonts have been registered, do that now */
+ if(!registered_fonts)
+ registered_fonts = configure_fonts(mdvi_app->fontspec, 1);
+ if(!registered_fonts)
+ fatal("no font types registered\n");
+
+ if(print_info_only) {
+ print_config(mdvi_app);
+ exit(EXIT_SUCCESS);
+ }
+
+ if(dvifile == NULL) {
+ fprintf(stderr, _("%s: no DVI file specified\n"),
+ program_name);
+ fprintf(stderr, _("Try `%s --help' for more information\n"),
+ program_name);
+ exit(EXIT_FAILURE);
+ }
+
+ ctx = mdvi_init_context(&mdvi_app->params, spec, dvifile);
+ if(ctx == NULL)
+ exit(1);
+ ctx->paper = mdvi_app->paper;
+ if(!batch_mode && init_x11() == -1)
+ exit(EXIT_FAILURE);
+
+ if(mdvi_app->page_sort != MDVI_PAGE_SORT_NONE)
+ mdvi_sort_pages(ctx, mdvi_app->page_sort);
+
+ if(mdvi_app->use_tex_page)
+ mdvi_app->first_page =
+ mdvi_find_tex_page(ctx, mdvi_app->first_page);
+ else if(mdvi_app->first_page < 0)
+ mdvi_app->first_page += MDVI_LASTPAGE(ctx) + 1;
+
+ if(!MDVI_VALIDPAGE(ctx, mdvi_app->first_page))
+ mdvi_app->first_page = 0;
+
+ if(batch_mode == 0) {
+ /* beginning of device-specific code */
+ ctx->params.fg = get_color_byname(mdvi_app->fgcolor);
+ ctx->params.bg = get_color_byname(mdvi_app->bgcolor);
+ mdvi_create_window(ctx, NULL);
+ mdvi_reset_color(ctx);
+ view_page(ctx, mdvi_app->first_page);
+ /* end of device-specific code */
+ } else {
+ ctx->params.fg = (Ulong)-1;
+ ctx->params.bg = 0;
+ if(DEBUGGING(DVI)) {
+ printf("%s", ctx->filename);
+ for(i = 0; i < ctx->npages; i++) {
+ mdvi_dopage(ctx, i);
+ printf(" [%d]", ctx->pagemap[i][1]);
+ }
+ } else
+ for(i = 0; i < ctx->npages; i++)
+ mdvi_dopage(ctx, i);
+ fputc('\n', stdout);
+ }
+
+ mdvi_destroy_context(ctx);
+ mdvi_flush_fontmaps();
+ mdvi_flush_encodings();
+ mdvi_ps_flush_fonts();
+ flush_color_table();
+
+ exit(0);
+}
diff --git a/dviware/mdvi/x11/dvidraw.c b/dviware/mdvi/x11/dvidraw.c
new file mode 100644
index 0000000000..f0ecb68d94
--- /dev/null
+++ b/dviware/mdvi/x11/dvidraw.c
@@ -0,0 +1,1510 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "mdvi.h"
+#include "private.h"
+#include "x11.h"
+
+#define WIN_BORDER 0
+#define STATUS_BORDER 0
+
+#define PAGEMOVE_TINY 0
+#define PAGEMOVE_SMALL 1
+#define PAGEMOVE_NORMAL 2
+#define PAGEMOVE_LARGE 3
+
+#include <X11/keysym.h>
+#include <X11/cursorfont.h>
+
+typedef struct {
+ Window win;
+ Uint w;
+ Uint h;
+ int xorig;
+ int yorig;
+ int minx;
+ int miny;
+ int maxx;
+ int maxy;
+ int dirty;
+} WinArea;
+
+#define MAX_MARKS 16
+
+typedef struct {
+ DrawArea area;
+ char **strings;
+ int size;
+ int top;
+} StatusLine;
+
+typedef void (*RulerDrawer) __PROTO((DviContext *, int, int, int, int));
+
+typedef struct {
+ TopWindow dd_top;
+ WinArea dd_dvi;
+ Ulong dd_fg;
+ Ulong dd_bg;
+ Uint dd_page_w;
+ Uint dd_page_h;
+ Uint dd_paper_w;
+ Uint dd_paper_h;
+ double dd_hruler_inches;
+ double dd_vruler_inches;
+ short dd_hsteps;
+ short dd_vsteps;
+ Uint dd_base_x;
+ Uint dd_base_y;
+ short dd_marks[MAX_MARKS];
+ GC dd_gc;
+ short dd_busy;
+ int dd_ruler_xorig;
+ int dd_ruler_yorig;
+ int dd_ruler_x;
+ int dd_ruler_y;
+ int dd_inruler;
+ RulerDrawer dd_ruler_draw;
+ int dd_reset_origin;
+ DviAppConfig *dd_app;
+} DviDrawData;
+
+/* these are constant after initialization */
+static Cursor busy, point;
+static GC rulergc;
+static GC scrollgc;
+
+extern DviAppConfig *mdvi_app;
+
+static DviOrientation pos_rotate_sequence[] = {
+ MDVI_ORIENT_RP90,
+ MDVI_ORIENT_IRP90,
+ MDVI_ORIENT_IRM90,
+ MDVI_ORIENT_RM90,
+ MDVI_ORIENT_BTRL,
+ MDVI_ORIENT_TBLR,
+ MDVI_ORIENT_BTLR,
+ MDVI_ORIENT_TBRL
+};
+
+static DviOrientation neg_rotate_sequence[] = {
+ MDVI_ORIENT_RM90,
+ MDVI_ORIENT_IRM90,
+ MDVI_ORIENT_IRP90,
+ MDVI_ORIENT_RP90,
+ MDVI_ORIENT_TBLR,
+ MDVI_ORIENT_BTRL,
+ MDVI_ORIENT_TBRL,
+ MDVI_ORIENT_BTLR
+};
+
+static DviOrientation h_flip_sequence[] = {
+ MDVI_ORIENT_TBRL,
+ MDVI_ORIENT_TBLR,
+ MDVI_ORIENT_BTRL,
+ MDVI_ORIENT_BTLR,
+ MDVI_ORIENT_IRM90,
+ MDVI_ORIENT_IRP90,
+ MDVI_ORIENT_RM90,
+ MDVI_ORIENT_RP90
+};
+
+static DviOrientation v_flip_sequence[] = {
+ MDVI_ORIENT_BTLR,
+ MDVI_ORIENT_BTRL,
+ MDVI_ORIENT_TBLR,
+ MDVI_ORIENT_TBRL,
+ MDVI_ORIENT_IRP90,
+ MDVI_ORIENT_IRM90,
+ MDVI_ORIENT_RP90,
+ MDVI_ORIENT_RM90
+};
+
+/*
+ * I know this is poor style, but it saves a lot of routine
+ * typing.
+ */
+#define GET_DRAW_DATA \
+ DviDrawData *dd = (DviDrawData *)dvi->device.device_data
+
+#define top dd->dd_top
+#define dviwin dd->dd_dvi
+#define page_w dd->dd_page_w
+#define page_h dd->dd_page_h
+#define paper_w dd->dd_paper_w
+#define paper_h dd->dd_paper_h
+#define hruler_inches dd->dd_hruler_inches
+#define vruler_inches dd->dd_vruler_inches
+#define hsteps dd->dd_hsteps
+#define vsteps dd->dd_vsteps
+#define base_x dd->dd_base_x
+#define base_y dd->dd_base_y
+#define marks dd->dd_marks
+#define drawgc dd->dd_gc
+#define inruler dd->dd_inruler
+#define reset_origin dd->dd_reset_origin
+#define dviapp dd->dd_app
+
+#define NORULER 0
+#define HRULER 1
+#define VRULER 2
+#define VHRULER 3
+
+#define SET_RULER_ORIGIN(t,x,y) do { \
+ XSync(dpy, False); \
+ dd->dd_ruler_xorig = dd->dd_ruler_x = (x); \
+ dd->dd_ruler_yorig = dd->dd_ruler_y = (y); \
+ switch(t) { \
+ case NORULER: dd->dd_ruler_draw = NULL; break; \
+ case HRULER: dd->dd_ruler_draw = draw_hruler; break; \
+ case VRULER: dd->dd_ruler_draw = draw_vruler; break; \
+ case VHRULER: dd->dd_ruler_draw = draw_ruler; break; \
+ } \
+ dd->dd_inruler = (t); \
+ } while(0)
+
+#define UNSET_RULER() do { \
+ dd->dd_ruler_draw = NULL; dd->dd_inruler = NORULER; \
+ } while(0)
+
+#define DRAW_RULER() do { \
+ if(dd->dd_ruler_draw) \
+ dd->dd_ruler_draw(dvi, \
+ dd->dd_ruler_xorig, \
+ dd->dd_ruler_yorig, \
+ dd->dd_ruler_x, \
+ dd->dd_ruler_y); \
+ } while(0)
+
+#define MOVE_RULER(x,y) do { \
+ DRAW_RULER(); \
+ dd->dd_ruler_x = (x); \
+ dd->dd_ruler_y = (y); \
+ DRAW_RULER(); \
+ } while(0)
+
+#define WORKING() do { \
+ if(++dd->dd_busy == 1 && busy != None) \
+ XDefineCursor(dpy, top.win, busy); \
+ } while(0)
+#define RESTING() do { \
+ if(--dd->dd_busy == 0 && busy != None) \
+ XUndefineCursor(dpy, top.win); \
+ } while(0)
+
+int mdvi_create_window(DviContext *dvi, const char *geometry);
+void view_page __PROTO((DviContext *dvi, int pageno));
+
+static void print_key_help __PROTO((void));
+static void handle_special_key __PROTO((DviContext *dvi, int argno, int den, KeySym sym, int state));
+static void handle_key __PROTO((DviContext *dvi, XKeyEvent *ev));
+static void do_redraw __PROTO((DviContext *dvi));
+static void do_expose __PROTO((DviContext *dvi, int x, int y, Uint w, Uint h));
+static void handle_dvi __PROTO((DviContext *dvi, XEvent *ev));
+static void x11_draw_glyph __PROTO((DviContext *dvi, DviFontChar *ch, int x0, int y0));
+static void x11_draw_rule __PROTO((DviContext *dvi, int x, int y, Uint w, Uint h, int));
+static void draw_hticks __PROTO((DviContext *dvi, int x, int y, int x2));
+static void draw_vticks __PROTO((DviContext *dvi, int x, int y, int y2));
+static void draw_hruler __PROTO((DviContext *dvi, int x1, int y1, int x2, int y2));
+static void draw_vruler __PROTO((DviContext *dvi, int x1, int y1, int x2, int y2));
+static void draw_ruler __PROTO((DviContext *dvi, int x, int y, int x2, int y2));
+static void reset_page __PROTO((DviContext *dvi));
+static void reset_view_origin __PROTO((DviContext *dvi));
+static void position_windows __PROTO((DviContext *dvi));
+static int configure_window __PROTO((DviContext *dvi));
+static void scroll_window __PROTO((DviContext *dvi, int newx, int newy));
+static void pageup __PROTO((DviContext *dvi, int n, int mode));
+static void pageleft __PROTO((DviContext *dvi, int n, int mode));
+static int set_pageno __PROTO((DviContext *dvi, int page));
+static int set_tex_pageno __PROTO((DviContext *dvi, int page));
+static void top_events __PROTO((DviContext *dvi, XEvent *ev));
+
+extern void font_print __PROTO((void));
+
+/* functions that are used as DviDevice in the DVI context */
+
+static void x11_draw_glyph(DviContext *dvi, DviFontChar *ch, int x0, int y0)
+{
+ int rx, ry;
+ int x, y, w, h;
+ int isbitmap;
+ int isbox;
+ DviGlyph *glyph;
+ GET_DRAW_DATA;
+
+ /* coordinates into the page */
+ rx = base_x + x0;
+ ry = base_y + y0;
+
+ isbitmap = 1;
+ if(dvi->params.hshrink == 1 && dvi->params.vshrink == 1)
+ glyph = &ch->glyph;
+ else if(dvi->params.flags & MDVI_PARAM_ANTIALIASED) {
+ glyph = &ch->grey;
+ isbitmap = 0;
+ } else
+ glyph = &ch->shrunk;
+
+ isbox = (glyph->data == NULL ||
+ (dvi->params.flags & MDVI_PARAM_CHARBOXES));
+
+ x = glyph->x;
+ y = glyph->y;
+ w = glyph->w;
+ h = glyph->h;
+
+ switch(dvi->params.orientation) {
+ case MDVI_ORIENT_TBLR:
+ break;
+ case MDVI_ORIENT_TBRL:
+ rx = page_w - rx;
+ break;
+ case MDVI_ORIENT_BTLR:
+ ry = page_h - ry;
+ break;
+ case MDVI_ORIENT_BTRL:
+ rx = page_w - rx;
+ ry = page_h - ry;
+ break;
+ case MDVI_ORIENT_RP90:
+ SWAPINT(rx, ry);
+ ry = page_h - ry;
+ break;
+ case MDVI_ORIENT_RM90:
+ SWAPINT(rx, ry);
+ rx = page_w - rx;
+ break;
+ case MDVI_ORIENT_IRM90:
+ SWAPINT(rx, ry);
+ rx = page_w - rx;
+ ry = page_h - ry;
+ break;
+ case MDVI_ORIENT_IRP90:
+ SWAPINT(rx, ry);
+ break;
+ default:
+ break;
+ }
+
+ rx -= x + dviwin.xorig;
+ ry -= y + dviwin.yorig;
+
+ /*
+ * drawing is allowed only in the rectangle inside
+ * [minx, miny] - [maxx, maxy]
+ * of dviwin
+ */
+ if(rx > dviwin.maxx || dviwin.minx > rx + w ||
+ ry > dviwin.maxy || dviwin.miny > ry + h)
+ return;
+ if(isbox)
+ XDrawRectangle(dpy, dviwin.win, drawgc,
+ rx, ry, w, h);
+ else if(isbitmap)
+ draw_bitmap(dviwin.win, (BITMAP *)glyph->data, rx, ry);
+ else
+ put_image(dviwin.win, glyph->data, rx, ry, w, h);
+}
+
+static void x11_draw_rule(DviContext *dvi, int x, int y, Uint w, Uint h, int fill)
+{
+ int rx, ry;
+ GET_DRAW_DATA;
+
+ rx = base_x + x;
+ ry = base_y + y;
+
+ switch(dvi->params.orientation) {
+ case MDVI_ORIENT_TBLR:
+ break;
+ case MDVI_ORIENT_TBRL:
+ rx = page_w - rx - w;
+ break;
+ case MDVI_ORIENT_BTLR:
+ ry = page_h - ry - h;
+ break;
+ case MDVI_ORIENT_BTRL:
+ rx = page_w - rx - w;
+ ry = page_h - ry - h;
+ break;
+ case MDVI_ORIENT_RP90:
+ SWAPINT(rx, ry);
+ SWAPINT(w, h);
+ ry = page_h - ry - h;
+ break;
+ case MDVI_ORIENT_RM90:
+ SWAPINT(rx, ry);
+ SWAPINT(w, h);
+ rx = page_w - rx - w;
+ break;
+ case MDVI_ORIENT_IRM90:
+ SWAPINT(rx, ry);
+ SWAPINT(w, h);
+ rx = page_w - rx - w;
+ ry = page_h - ry - h;
+ break;
+ case MDVI_ORIENT_IRP90:
+ SWAPINT(rx, ry);
+ SWAPINT(w, h);
+ break;
+ }
+ rx -= dviwin.xorig;
+ ry -= dviwin.yorig;
+
+ if(rx <= dviwin.maxx && dviwin.minx <= rx + w &&
+ ry <= dviwin.maxy && dviwin.miny <= ry + h) {
+ if(fill == 0)
+ XDrawRectangle(dpy, dviwin.win, image_gc,
+ rx, ry, w ? w : 1, h ? h : 1);
+ else
+ XFillRectangle(dpy, dviwin.win, image_gc,
+ rx, ry, w ? w : 1, h ? h : 1);
+ }
+}
+
+static int x11_interpolate_colors(void *device_data,
+ Ulong *pixels, int nlevels, Ulong fg, Ulong bg, double g, int density)
+{
+ double frac;
+ XColor xc, xfg, xbg;
+ int i, n;
+
+ xfg.pixel = fg;
+ xbg.pixel = bg;
+ XQueryColor(dpy, colormap, &xfg);
+ XQueryColor(dpy, colormap, &xbg);
+
+ n = nlevels - 1;
+ for(i = 0; i < nlevels; i++) {
+ if(g > 0)
+ frac = pow((double)i / n, 1 / g);
+ else
+ frac = 1 - pow((double)(n - i) / n, -g);
+ xc.red = frac * ((double)xfg.red - xbg.red) + xbg.red;
+ xc.green = frac * ((double)xfg.green - xbg.green) + xbg.green;
+ xc.blue = frac * ((double)xfg.blue - xbg.blue) + xbg.blue;
+ if(XAllocColor(dpy, colormap, &xc))
+ pixels[i] = xc.pixel;
+ else
+ pixels[i] = (i * 100 >= density * 15) ?
+ xfg.pixel : xbg.pixel;
+ }
+ return nlevels;
+}
+
+static void *x11_create_image(void *device_data, Uint w, Uint h, Uint bpp)
+{
+ XImage *image;
+
+ image = XCreateImage(dpy, visual, depth, ZPixmap, 0,
+ (char *)0, w, h, bpp, 0);
+ image->data = xcalloc(image->bytes_per_line, h);
+ return image;
+}
+
+static void x11_free_image(void *ptr)
+{
+ XImage *image = (XImage *)ptr;
+ char *data;
+
+ data = image->data;
+ image->data = NULL;
+ XDestroyImage(image);
+ xfree(data);
+}
+
+static void x11_put_pixel(void *image, int x, int y, Ulong color)
+{
+ XPutPixel((XImage *)image, x, y, color);
+}
+
+static void x11_refresh(DviContext *dvi, void *device_data)
+{
+ GET_DRAW_DATA;
+
+ configure_window(dvi);
+ if(!reset_origin)
+ set_pageno(dvi, dvi->currpage);
+}
+
+static void x11_set_color(void *device_data, Ulong fg, Ulong bg)
+{
+ DviDrawData *dd = (DviDrawData *)device_data;
+
+ if(fg != dd->dd_fg) {
+ DEBUG((DBG_DEVICE, "foreground %lu -> %lu\n",
+ dd->dd_fg, fg));
+ XSetForeground(dpy, image_gc, fg);
+ dd->dd_fg = fg;
+ }
+ if(bg != dd->dd_bg) {
+ DEBUG((DBG_DEVICE, "background %lu -> %lu\n",
+ dd->dd_bg, bg));
+ XSetBackground(dpy, image_gc, bg);
+ dd->dd_bg = bg;
+ }
+}
+
+/* draws tick marks for horizontal rulers */
+static void draw_hticks(DviContext *dvi, int x, int y, int x2)
+{
+ int i, n;
+ double dh;
+ GET_DRAW_DATA;
+
+ dh = hruler_inches * dvi->params.dpi / (hsteps * dvi->params.hshrink);
+ if(x > x2)
+ dh = -dh;
+ for(n = 0, i = x; (x < x2 ? i < x2 : i > x2); ) {
+ if(hsteps > 1 && (n % hsteps) == 0)
+ XDrawLine(dpy, dviwin.win, rulergc, i, y+6, i, y-6);
+ else if((hsteps & 1) || (n % (hsteps >> 1)))
+ XDrawLine(dpy, dviwin.win, rulergc, i, y+2, i, y-2);
+ else
+ XDrawLine(dpy, dviwin.win, rulergc, i, y+4, i, y-4);
+ i = x + FROUND(++n * dh);
+ }
+}
+
+/* draws tick marks for vertical rulers */
+static void draw_vticks(DviContext *dvi, int x, int y, int y2)
+{
+ int i, n;
+ double dh;
+ GET_DRAW_DATA;
+
+ dh = vruler_inches * dvi->params.vdpi / (vsteps * dvi->params.vshrink);
+ if(y > y2)
+ dh = -dh;
+ for(n = 0, i = y; (y < y2 ? i < y2 : i > y2); ) {
+ if(vsteps > 1 && (n % vsteps) == 0)
+ XDrawLine(dpy, dviwin.win, rulergc, x+6, i, x-6, i);
+ else if((vsteps & 1) || (n % (vsteps >> 1)))
+ XDrawLine(dpy, dviwin.win, rulergc, x+2, i, x-2, i);
+ else
+ XDrawLine(dpy, dviwin.win, rulergc, x+4, i, x-4, i);
+ i = y + FROUND(++n * dh);
+ }
+}
+
+static void draw_hruler(DviContext *dvi, int x1, int y1, int x2, int y2)
+{
+ int tx, ty, n, d;
+ double fraction;
+ char str[64];
+ GET_DRAW_DATA;
+
+ /* grab the server */
+ XRaiseWindow(dpy, dviwin.win);
+ XSync(dpy, True);
+ XGrabServer(dpy);
+
+ /* draw a horizontal line */
+ XDrawLine(dpy, dviwin.win, rulergc,
+ x1, y1, x2, y1);
+
+ /* draw tick marks */
+ draw_hticks(dvi, x1, y1, x2);
+
+ /* draw a small rectangle at the end of the ruler */
+ XFillRectangle(dpy, dviwin.win, rulergc, x2-1, y1-1, 3, 3);
+ XDrawLine(dpy, dviwin.win, rulergc, x2, y1, x2, y2);
+
+ /* draw text */
+ if(x1 != x2) {
+ /* make the text centered under the ruler */
+ fraction = (double)abs(x1 - x2) * dvi->params.hshrink /
+ (dvi->params.dpi * hruler_inches);
+ d = sprintf(str, "%.2f", fraction);
+ n = XTextWidth(default_font, str, d);
+ tx = x2 + 15;
+ ty = y2 - FONT_HEIGHT(default_font) / 2 +
+ default_font->max_bounds.ascent;
+ if(ty - 2 < default_font->max_bounds.ascent)
+ ty = default_font->max_bounds.ascent + 2;
+ if(ty + default_font->max_bounds.descent + 2 > dviwin.h)
+ ty = dviwin.h - default_font->max_bounds.descent - 2;
+ if(tx < 2)
+ tx = 2;
+ if(tx + n + 2 > dviwin.w)
+ tx = Min(x2, dviwin.w) - n - 10;
+ XDrawString(dpy, dviwin.win, rulergc, tx, ty, str, d);
+ }
+ XUngrabServer(dpy);
+}
+
+static void draw_vruler(DviContext *dvi, int x1, int y1, int x2, int y2)
+{
+ int tx, ty, n, d;
+ char str[64];
+ double fraction;
+ GET_DRAW_DATA;
+
+ /* grab the server */
+ XGrabServer(dpy);
+
+ /* draw a horizontal line */
+ XDrawLine(dpy, dviwin.win, rulergc, x1, y1, x1, y2);
+
+ /* draw tick marks */
+ draw_vticks(dvi, x1, y1, y2);
+
+ /* draw a small rectangle at the end of the ruler */
+ XFillRectangle(dpy, dviwin.win, rulergc, x1-1, y2-1, 3, 3);
+ XDrawLine(dpy, dviwin.win, rulergc, x1, y2, x2, y2);
+
+ /* draw text */
+ if(y1 != y2) {
+ /* make the text centered under the ruler */
+ fraction = (double)abs(y1 - y2) * dvi->params.vshrink /
+ (dvi->params.vdpi * vruler_inches);
+ d = sprintf(str, "%.2f", fraction);
+ n = XTextWidth(default_font, str, d);
+ if(n % 2) n++;
+ tx = x2 - n / 2;
+ ty = y2 + default_font->max_bounds.ascent + 10;
+ /* make sure the text is visible */
+ if(tx < 2)
+ tx = 2;
+ if(tx + n + 2 > dviwin.w)
+ tx = dviwin.w - n - 2;
+ if(ty > 0 && ty > dviwin.h - 2)
+ ty = Min(y2, dviwin.h) - default_font->max_bounds.descent - 10;
+ if(ty < default_font->max_bounds.ascent + 2)
+ ty = default_font->max_bounds.ascent + 2;
+ XDrawString(dpy, dviwin.win, rulergc, tx, ty, str, d);
+ }
+ XUngrabServer(dpy);
+}
+
+/*ARGSUSED*/
+static void draw_ruler(DviContext *dvi, int x0, int y0, int x, int y)
+{
+ GET_DRAW_DATA;
+
+ /* Grab the server */
+ XGrabServer(dpy);
+
+ /* Draw horizontal line */
+ XDrawLine(dpy, dviwin.win, rulergc, 0, y, dviwin.w, y);
+
+ /* Draw vertical line */
+ XDrawLine(dpy, dviwin.win, rulergc, x, 0, x, dviwin.h);
+
+ /* hand back the server */
+ XUngrabServer(dpy);
+
+ /* draw ticks */
+
+ /* horizontal ticks */
+ draw_hticks(dvi, x, y, dviwin.w);
+ draw_hticks(dvi, x, y, 0);
+
+ /* vertical ticks */
+ draw_vticks(dvi, x, y, dviwin.h);
+ draw_vticks(dvi, x, y, 0);
+
+}
+
+static void reset_page(DviContext *dvi)
+{
+ GET_DRAW_DATA;
+
+ dviwin.minx = 0;
+ dviwin.miny = 0;
+ dviwin.maxx = dviwin.w;
+ dviwin.maxy = dviwin.h;
+ dviwin.dirty = 1;
+}
+
+static void reset_view_origin(DviContext *dvi)
+{
+ GET_DRAW_DATA;
+
+ switch(dvi->params.orientation) {
+ case MDVI_ORIENT_TBLR:
+ case MDVI_ORIENT_IRP90:
+ dviwin.xorig = 0;
+ dviwin.yorig = 0;
+ break;
+ case MDVI_ORIENT_TBRL:
+ case MDVI_ORIENT_RM90:
+ dviwin.xorig = page_w - dviwin.w;
+ dviwin.yorig = 0;
+ break;
+ case MDVI_ORIENT_BTLR:
+ case MDVI_ORIENT_RP90:
+ dviwin.xorig = 0;
+ dviwin.yorig = page_h - dviwin.h;
+ break;
+ case MDVI_ORIENT_BTRL:
+ case MDVI_ORIENT_IRM90:
+ dviwin.xorig = page_w - dviwin.w;
+ dviwin.yorig = page_h - dviwin.h;
+ break;
+ }
+ if(dviwin.xorig < 0)
+ dviwin.xorig = 0;
+ if(dviwin.yorig < 0)
+ dviwin.yorig = 0;
+
+}
+
+static void position_windows(DviContext *dvi)
+{
+ int tw, th;
+ GET_DRAW_DATA;
+
+ tw = top.w - 2*WIN_BORDER;
+ th = top.h - 2*WIN_BORDER;
+ XMoveResizeWindow(dpy, dviwin.win, 0, 0, tw, th);
+ dviwin.w = tw;
+ dviwin.h = th;
+ reset_page(dvi);
+}
+
+static int configure_window(DviContext *dvi)
+{
+ Uint w, h;
+ double ratio;
+ int hs, vs;
+ int changed = 0;
+ GET_DRAW_DATA;
+
+ ratio = dvi->paper.inches_tall / dvi->paper.inches_wide;
+ base_x = unit2pix(dvi->params.dpi, dviapp->hmargin);
+ base_y = unit2pix(dvi->params.vdpi, dviapp->vmargin);
+ page_w = FROUND(dvi->dviconv * dvi->dvi_page_w);
+ page_h = FROUND(dvi->dvivconv * dvi->dvi_page_h);
+ hs = dvi->params.hshrink;
+ vs = dvi->params.vshrink;
+ if(!hs && !vs) {
+ /* compute both */
+ w = root_w;
+ h = FROUND(w * ratio);
+ if(h > root_h) {
+ h = root_h;
+ w = FROUND(h / ratio);
+ }
+ /* determine shrinking factors */
+ hs = ROUND(page_w + 2*base_x, w);
+ vs = ROUND(page_h + 2*base_y, h);
+ if(hs < 1) hs = 1;
+ if(vs < 1) vs = 1;
+ } else if(!hs) {
+ h = FROUND(dvi->params.vdpi * dvi->paper.inches_tall /
+ dvi->params.vshrink) + 2;
+ w = FROUND(h / ratio);
+ hs = ROUND(page_w + 2*base_x, w);
+ } else if(!vs) {
+ w = FROUND(dvi->params.dpi * dvi->paper.inches_wide /
+ dvi->params.hshrink) + 2;
+ h = FROUND(w * ratio);
+ vs = ROUND(page_h + 2*base_y, h);
+ } else {
+ w = FROUND(dvi->params.dpi * dvi->paper.inches_wide /
+ dvi->params.hshrink) + 2;
+ h = FROUND(dvi->params.vdpi * dvi->paper.inches_tall /
+ dvi->params.vshrink) + 2;
+ }
+
+ /* convert page dimensions */
+ if(!dvi->params.hshrink) {
+ dvi->params.hshrink = hs;
+ dvi->params.conv /= hs;
+ }
+ if(!dvi->params.vshrink) {
+ dvi->params.vshrink = vs;
+ dvi->params.vconv /= vs;
+ }
+
+ /* fix margins */
+ base_x = unit2pix(dvi->params.dpi, dviapp->hmargin) / dvi->params.hshrink;
+ base_y = unit2pix(dvi->params.vdpi, dviapp->vmargin) / dvi->params.vshrink;
+
+ /* recompute things now that we have all the information */
+ page_w = pixel_round(dvi, dvi->dvi_page_w) + base_x;
+ page_h = vpixel_round(dvi, dvi->dvi_page_h) + base_y;
+
+ /* get paper dimensions */
+ paper_w = FROUND(dvi->params.dpi * dvi->paper.inches_wide /
+ dvi->params.hshrink) + 2;
+ paper_h = FROUND(dvi->params.vdpi * dvi->paper.inches_tall /
+ dvi->params.vshrink) + 2;
+
+ /* this is the new window size */
+ if(page_w < paper_w)
+ page_w = paper_w;
+ if(page_h < paper_h)
+ page_h = paper_h;
+
+ switch(dvi->params.orientation) {
+ case MDVI_ORIENT_TBLR:
+ case MDVI_ORIENT_TBRL:
+ case MDVI_ORIENT_BTLR:
+ case MDVI_ORIENT_BTRL:
+ break;
+ case MDVI_ORIENT_RP90:
+ case MDVI_ORIENT_RM90:
+ case MDVI_ORIENT_IRP90:
+ case MDVI_ORIENT_IRM90:
+ SWAPINT(paper_w, paper_h);
+ SWAPINT(page_w, page_h);
+ break;
+ }
+
+ w = Min(page_w, root_w);
+ h = Min(page_h, root_h);
+
+ changed = 1;
+ if(top.win == None) {
+ create_top_window(&top, dvi->filename, w, h);
+ expose_window(top.win, False);
+ get_win_size(top.win, &top.w, &top.h);
+ } else if(w != top.w || h != top.h)
+ XResizeWindow(dpy, top.win, w, h);
+ else
+ changed = 0;
+
+ /* setup ruler units */
+ hruler_inches = unit2pix_factor(dviapp->hrule_units);
+ vruler_inches = unit2pix_factor(dviapp->vrule_units);
+ ratio = hruler_inches * dvi->params.dpi;
+ if(ratio < 10)
+ hsteps = 1;
+ else if(ratio < 100)
+ hsteps = 5;
+ else
+ hsteps = 10;
+ ratio = vruler_inches * dvi->params.vdpi;
+ if(ratio < 10)
+ vsteps = 1;
+ else if(ratio < 100)
+ vsteps = 5;
+ else
+ vsteps = 10;
+
+ return changed;
+}
+
+int mdvi_create_window(DviContext *dvi, const char *geometry)
+{
+ DviDrawData *dd;
+ int i;
+
+ dd = xalloc(DviDrawData);
+ memzero(dd, sizeof(DviDrawData));
+ dvi->device.device_data = dd;
+
+ /* if this looks weird, see the comment about bad style above */
+ dviapp = mdvi_app;
+ top.win = None;
+ configure_window(dvi);
+ if(top.win == None)
+ return -1;
+
+ XSelectInput(dpy, top.win,
+ ExposureMask|StructureNotifyMask|KeyPressMask);
+
+ /* GC for drawing */
+ drawgc = create_gc(GXcopy, top.win, dvi->params.fg, dvi->params.bg);
+
+ /* GC for rulers */
+ rulergc = create_gc(GXxor, top.win, white, black);
+
+ /* create our child window */
+ dviwin.win = create_window(top.win, dvi->params.bg,
+ top.w - 2*WIN_BORDER,
+ top.h - 2*WIN_BORDER, WIN_BORDER);
+ XSelectInput(dpy, dviwin.win,
+ ExposureMask|ButtonPressMask|ButtonReleaseMask|ButtonMotionMask);
+ get_win_size(dviwin.win, &dviwin.w, &dviwin.h);
+ dviwin.minx = 0;
+ dviwin.miny = 0;
+ dviwin.maxx = dviwin.w;
+ dviwin.maxy = dviwin.h;
+
+ reset_view_origin(dvi);
+ add_window_events(dviwin.win, ButtonMotionMask);
+
+ /* GC for scrolling */
+ scrollgc = create_gc(GXcopy, dviwin.win, dvi->params.fg, dvi->params.bg);
+ XSetGraphicsExposures(dpy, scrollgc, True);
+
+ /* setup the functions in the dvi context */
+ dvi->device.draw_glyph = x11_draw_glyph;
+ dvi->device.draw_rule = x11_draw_rule;
+ dvi->device.alloc_colors = x11_interpolate_colors;
+ dvi->device.create_image = x11_create_image;
+ dvi->device.free_image = x11_free_image;
+ dvi->device.put_pixel = x11_put_pixel;
+ dvi->device.set_color = x11_set_color;
+ dvi->device.refresh = NULL; /*x11_refresh;*/
+
+ /* initialize marks */
+ for(i = 0; i < MAX_MARKS; i++)
+ marks[i] = -1;
+
+ position_windows(dvi);
+
+ printf("Type `q' to quit, `?' to see keyboard and mouse commands\n");
+
+ return 0;
+}
+
+static void scroll_window(DviContext *dvi, int newx, int newy)
+{
+ int x, y, w, h;
+ int src_x, dest_x;
+ int src_y, dest_y;
+ GET_DRAW_DATA;
+
+ x = newx - dviwin.xorig;
+ y = newy - dviwin.yorig;
+ dviwin.xorig = newx;
+ dviwin.yorig = newy;
+ dviwin.minx -= x;
+ dviwin.maxx -= x;
+ dviwin.miny -= y;
+ dviwin.maxy -= y;
+ if(dviwin.minx < 0)
+ dviwin.minx = 0;
+ if(dviwin.miny < 0)
+ dviwin.miny = 0;
+ if(dviwin.maxx > dviwin.w)
+ dviwin.maxx = dviwin.w;
+ if(dviwin.maxy > dviwin.h)
+ dviwin.maxy = dviwin.h;
+
+ if(x > 0) {
+ src_x = x;
+ dest_x = 0;
+ } else {
+ src_x = 0;
+ dest_x = -x;
+ }
+ if(y > 0) {
+ src_y = y;
+ dest_y = 0;
+ } else {
+ src_y = 0;
+ dest_y = -y;
+ }
+ w = dviwin.w - abs(x);
+ h = dviwin.h - abs(y);
+ if(w <= 0 || h <= 0) {
+ /* need to refresh the entire window */
+ reset_page(dvi);
+ XClearArea(dpy, dviwin.win, 0, 0, dviwin.w, dviwin.h, True);
+ } else {
+ XCopyArea(dpy, dviwin.win, dviwin.win, scrollgc,
+ src_x, src_y, w, h, dest_x, dest_y);
+ if(dest_x > 0 && h)
+ XClearArea(dpy, dviwin.win,
+ 0, dest_y, dviwin.w - w, h, True);
+ else if(dest_x == 0 && h)
+ XClearArea(dpy, dviwin.win,
+ w, dest_y, dviwin.w - w, h, True);
+ if(dest_y > 0 && w)
+ XClearArea(dpy, dviwin.win,
+ dest_x, 0, w, dviwin.h - h, True);
+ else if(dest_y == 0 && w)
+ XClearArea(dpy, dviwin.win,
+ dest_x, h, w, dviwin.h - h, True);
+ if(w < dviwin.w && h < dviwin.h) {
+ XClearArea(dpy, dviwin.win,
+ dest_x ? 0 : w,
+ dest_y ? 0 : h,
+ dviwin.w - w, dviwin.h - h, True);
+ }
+ }
+}
+
+static void pageup(DviContext *dvi, int n, int mode)
+{
+ int z;
+ int maxh;
+ GET_DRAW_DATA;
+
+ n = n * (int)page_h;
+ switch(mode) {
+ case PAGEMOVE_TINY: n /= 80; break;
+ case PAGEMOVE_SMALL: n /= 40; break;
+ case PAGEMOVE_NORMAL: n /= 10; break;
+ case PAGEMOVE_LARGE: break;
+ }
+
+ z = dviwin.yorig + n;
+ maxh = page_h - dviwin.h;
+ if(z > maxh)
+ z = maxh;
+ if(z < 0)
+ z = 0;
+ if(z != dviwin.yorig)
+ scroll_window(dvi, dviwin.xorig, z);
+ else
+ beep_sound();
+}
+
+static void pageleft(DviContext *dvi, int n, int mode)
+{
+ int z;
+ int maxw;
+ GET_DRAW_DATA;
+
+ n = n * (int)page_w;
+ switch(mode) {
+ case PAGEMOVE_TINY: n /= 80; break;
+ case PAGEMOVE_SMALL: n /= 40; break;
+ case PAGEMOVE_NORMAL: n /= 10; break;
+ case PAGEMOVE_LARGE: break;
+ }
+ z = dviwin.xorig + n;
+ maxw = page_w - dviwin.w;
+ if(z > maxw)
+ z = maxw;
+ if(z < 0)
+ z = 0;
+ if(z != dviwin.xorig)
+ scroll_window(dvi, z, dviwin.yorig);
+ else
+ beep_sound();
+}
+
+static int set_pageno(DviContext *dvi, int page)
+{
+ GET_DRAW_DATA;
+
+ if(page < 0 || page > dvi->npages - 1)
+ return -1;
+ dvi->currpage = page;
+ reset_page(dvi);
+ XClearArea(dpy, dviwin.win, 0, 0, dviwin.w, dviwin.h, True);
+ return 0;
+}
+
+static int set_tex_pageno(DviContext *dvi, int tex_page)
+{
+ int page;
+
+ page = mdvi_find_tex_page(dvi, tex_page);
+ if(page == dvi->npages)
+ return -1;
+ return set_pageno(dvi, page);
+}
+
+void print_key_help(void)
+{
+ printf(
+"Keystroke commands: (S=Shift, C=Control)\n"
+" PageUp/PageDown go to previous/next page\n"
+" C-PageUp/PageDown go to first/last page\n"
+" [S/C] Left/Right scroll document horizontally\n"
+" Up/Down scroll document vertically\n"
+" q quit\n"
+" b switch between your eyes and TeX's\n"
+" a toggle antialiasing\n"
+" l redraw page\n"
+" L reload the DVI file from disk\n"
+" R/r rotate page clockwise/counter-clockwise\n"
+" F/f flip page vertically/horizontally\n"
+" ? this help\n"
+" (NUM) p go to current page + NUM (-\\infty < NUM < \\infty)\n"
+" (NUM) j go to output page number NUM (last+NUM if NUM < 0)\n"
+" (NUM) t go to TeX's (i.e. document's) page number NUM\n"
+" (NUM) d change resolution\n"
+" (NUM) m change magnification\n"
+" (NUM) s change shrinking factor (both set to NUM)\n"
+" (NUM) x change horizontal shrinking factor\n"
+" (NUM) y change vertical shrinking factor\n"
+" (NUM) n change pixel density (for bitmap shrinking)\n"
+" (NUM) g change gamma correction factor\n"
+" C-Fn set bookmark\n"
+" Fn goto bookmark\n"
+"Mouse usage:\n"
+" Button 1 display ruler\n"
+" Button 1 + Shift display horizontal ruler\n"
+" Button 1 + Control display vertical ruler\n"
+ "");
+}
+
+void handle_special_key(DviContext *dvi, int argno, int den, KeySym sym, int state)
+{
+ int arg;
+ GET_DRAW_DATA;
+
+ switch(sym) {
+ case XK_Page_Down:
+ if(state & ControlMask)
+ arg = dvi->npages - 1;
+ else
+ arg = dvi->currpage + 1;
+ if(arg != dvi->currpage && set_pageno(dvi, arg) < 0)
+ beep_sound();
+ break;
+ case XK_Page_Up:
+ if(state & ControlMask)
+ arg = 0;
+ else
+ arg = dvi->currpage - 1;
+ if(arg != dvi->currpage && set_pageno(dvi, arg) < 0)
+ beep_sound();
+ break;
+ case XK_Left:
+ if(state & ControlMask)
+ arg = PAGEMOVE_TINY;
+ else if(state & ShiftMask)
+ arg = PAGEMOVE_SMALL;
+ else
+ arg = PAGEMOVE_NORMAL;
+ pageleft(dvi, -1, arg);
+ break;
+ case XK_Right:
+ if(state & ControlMask)
+ arg = PAGEMOVE_TINY;
+ else if(state & ShiftMask)
+ arg = PAGEMOVE_SMALL;
+ else
+ arg = PAGEMOVE_NORMAL;
+ pageleft(dvi, 1, arg);
+ break;
+ case XK_Up:
+ if(state & ControlMask)
+ arg = PAGEMOVE_TINY;
+ else if(state & ShiftMask)
+ arg = PAGEMOVE_SMALL;
+ else
+ arg = PAGEMOVE_NORMAL;
+ pageup(dvi, -1, arg);
+ break;
+ case XK_Down:
+ if(state & ControlMask)
+ arg = PAGEMOVE_TINY;
+ else if(state & ShiftMask)
+ arg = PAGEMOVE_SMALL;
+ else
+ arg = PAGEMOVE_NORMAL;
+ pageup(dvi, 1, arg);
+ break;
+ case XK_F1: arg = 0; goto setmark;
+ case XK_F2: arg = 1; goto setmark;
+ case XK_F3: arg = 2; goto setmark;
+ case XK_F4: arg = 3; goto setmark;
+ case XK_F5: arg = 4; goto setmark;
+ case XK_F6: arg = 5; goto setmark;
+ case XK_F7: arg = 6; goto setmark;
+ case XK_F8: arg = 7; goto setmark;
+ case XK_F9: arg = 8; goto setmark;
+ case XK_F10: arg = 9; goto setmark;
+ case XK_F11: arg = 10; goto setmark;
+ case XK_F12: arg = 11; goto setmark;
+ case XK_F13: arg = 12; goto setmark;
+ case XK_F14: arg = 13; goto setmark;
+ case XK_F15: arg = 14; goto setmark;
+ case XK_F16: arg = 15; goto setmark;
+ setmark:
+ if(arg < 0 || arg >= MAX_MARKS) {
+ beep_sound();
+ break;
+ }
+ if(state & ControlMask) {
+ /* set a mark */
+ marks[arg] = dvi->currpage;
+ } else if(marks[arg] >= 0) {
+ if(set_pageno(dvi, marks[arg]) < 0)
+ beep_sound();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+#define NEWNUMBER \
+ (has_number = 1, has_dot = 0, number = 0, logten = 1, sign = 1)
+#define RESETNUMBER \
+ (has_number = has_dot = 0, number = 0, sign = 1)
+
+void handle_key(DviContext *dvi, XKeyEvent *ev)
+{
+ char num_buf[256];
+ int length;
+ char ch;
+ KeySym sym;
+ XComposeStatus unused;
+ int reconfigure = 0;
+ static int has_number = 0;
+ static int sign = 1;
+ static int number;
+ static int has_dot = 0;
+ static double logten = 1;
+ GET_DRAW_DATA;
+
+ length = XLookupString(ev, num_buf, 256, &sym, &unused);
+ if(length == 0) {
+ sym = XLookupKeysym(ev, 0);
+ if(sym != NoSymbol) {
+ handle_special_key(dvi,
+ has_number ? number : 0,
+ has_dot ? logten : 1,
+ sym, ev->state);
+ }
+ RESETNUMBER;
+ return;
+ }
+ if(length == 1)
+ ch = num_buf[0];
+ else
+ ch = 0;
+
+ /* if user is typing a number, update our state */
+ if(ch >= '0' && ch <= '9') {
+ has_number = 1;
+ number = number * 10 + sign * (ch - '0');
+ if(has_dot) logten *= 10;
+ return;
+ } else if(ch == '-') {
+ NEWNUMBER;
+ sign = -1;
+ return;
+ } else if(ch == '+') {
+ NEWNUMBER;
+ return;
+ } else if(ch == '.' && !has_dot) {
+ /* it's a floating point number */
+ has_number = 1;
+ has_dot = 1;
+ logten = 1;
+ return;
+ }
+
+ switch(ch) {
+ case 8:
+ if(has_number)
+ dvi->params.layer = FROUND((double)number / logten);
+ else if(dvi->params.layer)
+ dvi->params.layer--;
+ set_pageno(dvi, dvi->currpage);
+ break;
+ case 9:
+ if(has_number)
+ dvi->params.layer = FROUND((double)number / logten);
+ else
+ dvi->params.layer++;
+ reset_page(dvi);
+ break;
+ case 'q':
+ top.active = 0;
+ break;
+ case 'b':
+ dvi->params.flags ^= MDVI_PARAM_CHARBOXES;
+ set_pageno(dvi, dvi->currpage);
+ break;
+ case 'a':
+ dvi->params.flags ^= MDVI_PARAM_ANTIALIASED;
+ set_pageno(dvi, dvi->currpage);
+ break;
+ case 'p':
+ if(!has_number)
+ break;
+ number += dvi->currpage;
+ if(number < 0)
+ number = 0;
+ if(number > dvi->npages-1)
+ number = dvi->npages-1;
+ set_pageno(dvi, number);
+ break;
+ case 'j':
+ if(!has_number)
+ break;
+ if(number < 0)
+ has_number = (set_pageno(dvi, dvi->npages+number) < 0);
+ else
+ has_number = (set_pageno(dvi, number) < 0);
+ if(has_number)
+ beep_sound();
+ break;
+ case 't':
+ if(!has_number)
+ break;
+ if(set_tex_pageno(dvi, number) < 0)
+ beep_sound();
+ break;
+ case 'l':
+ set_pageno(dvi, dvi->currpage);
+ break;
+ case 'L':
+ /* reload! */
+ WORKING();
+ if(mdvi_reload(dvi, NULL) == -1)
+ beep_sound();
+ else
+ reconfigure = 1;
+ RESTING();
+ break;
+ case 'd':
+ /* change DPI */
+ if(!has_number || number == dvi->params.dpi)
+ break;
+ WORKING();
+ reconfigure = mdvi_set_dpi(dvi, number);
+ RESTING();
+ break;
+ case 's':
+ if(!has_number || number < 0)
+ break;
+ WORKING();
+ reconfigure = mdvi_set_shrink(dvi, number, number);
+ RESTING();
+ break;
+ case 'x':
+ if(!has_number || number < 0)
+ break;
+ WORKING();
+ reconfigure = mdvi_set_hshrink(dvi, number);
+ RESTING();
+ break;
+ case 'y':
+ if(!has_number || number < 0)
+ break;
+ WORKING();
+ reconfigure = mdvi_set_vshrink(dvi, number);
+ RESTING();
+ break;
+ case 'm': {
+ double x;
+
+ if(!has_number)
+ break;
+ x = has_dot ? (double)number / logten : (double)number;
+ if(x <= 0) {
+ warning(_("%s: magnification must be positive\n"),
+ dvi->filename);
+ break;
+ }
+ WORKING();
+ reconfigure = mdvi_set_mag(dvi, x);
+ RESTING();
+ break;
+ }
+ case '?':
+ print_key_help();
+ break;
+ case 'r':
+ /* rotate +90 */
+ reconfigure = mdvi_set_orientation(dvi,
+ pos_rotate_sequence[dvi->params.orientation]);
+ reset_origin = 1;
+ break;
+ case 'R':
+ /* rotate -90 */
+ reconfigure = mdvi_set_orientation(dvi,
+ neg_rotate_sequence[dvi->params.orientation]);
+ reset_origin = 1;
+ break;
+ case 'f':
+ /* flip horizontally */
+ reconfigure = mdvi_set_orientation(dvi,
+ h_flip_sequence[dvi->params.orientation]);
+ reset_origin = 1;
+ break;
+ case 'F':
+ /* flip vertically */
+ reconfigure = mdvi_set_orientation(dvi,
+ v_flip_sequence[dvi->params.orientation]);
+ reset_origin = 1;
+ break;
+ case 'g': {
+ double x;
+
+ if(!has_number)
+ break;
+ x = has_dot ? (double)number / logten : (double)number;
+ reconfigure = mdvi_set_gamma(dvi, x);
+ break;
+ }
+ case 'n':
+ if(!has_number)
+ break;
+ if(number < 0)
+ beep_sound();
+ else
+ reconfigure = mdvi_set_density(dvi, number);
+ break;
+ case '/':
+ font_print();
+ break;
+ }
+
+ RESETNUMBER;
+
+ if(reconfigure) {
+ configure_window(dvi);
+ if(!reset_origin)
+ set_pageno(dvi, dvi->currpage);
+ }
+}
+
+static void top_events(DviContext *dvi, XEvent *ev)
+{
+ int tw, th;
+ GET_DRAW_DATA;
+
+ tw = top.w; th = top.h;
+
+ if(handle_top_events(&top, ev))
+ return;
+ switch(ev->type) {
+ case ConfigureNotify:
+ if(reset_origin ||
+ ev->xconfigure.width != tw || ev->xconfigure.height != th) {
+ position_windows(dvi);
+ if(reset_origin) {
+ reset_view_origin(dvi);
+ reset_origin = 0;
+ set_pageno(dvi, dvi->currpage);
+ }
+ }
+ break;
+ case KeyPress:
+ handle_key(dvi, &ev->xkey);
+ break;
+ }
+}
+
+void do_redraw(DviContext *dvi)
+{
+ GET_DRAW_DATA;
+
+ WORKING();
+ if(mdvi_dopage(dvi, dvi->currpage) == -1)
+ fatal("%s: failed to display page\n", dvi->filename);
+ RESTING();
+ XDrawRectangle(dpy, dviwin.win, normal_gc,
+ -dviwin.xorig, -dviwin.yorig, paper_w-1, paper_h-1);
+ reset_page(dvi);
+ dviwin.dirty = 0;
+}
+
+void do_expose(DviContext *dvi, int x, int y, Uint w, Uint h)
+{
+ GET_DRAW_DATA;
+
+ if(!dviwin.dirty) {
+ dviwin.minx = x;
+ dviwin.miny = y;
+ dviwin.maxx = x + w;
+ dviwin.maxy = y + h;
+ } else {
+ if(x < dviwin.minx)
+ dviwin.minx = x;
+ if(y < dviwin.miny)
+ dviwin.miny = y;
+ if(x + w > dviwin.maxx)
+ dviwin.maxx = x + w;
+ if(y + h > dviwin.maxy)
+ dviwin.maxy = y + h;
+ }
+}
+
+void handle_dvi(DviContext *dvi, XEvent *ev)
+{
+ GET_DRAW_DATA;
+
+ switch(ev->type) {
+ case ButtonPress:
+ if(inruler == NORULER && ev->xbutton.button == Button1) {
+ int type;
+
+ /* Raise our window */
+ XRaiseWindow(dpy, top.win);
+ XFlush(dpy);
+
+ /* rulers */
+ if(ev->xbutton.state & ControlMask)
+ type = VRULER;
+ else if(ev->xbutton.state & ShiftMask)
+ type = HRULER;
+ else
+ type = VHRULER;
+ SET_RULER_ORIGIN(type, ev->xbutton.x, ev->xbutton.y);
+ DRAW_RULER();
+ XDefineCursor(dpy, top.win, point);
+ }
+ break;
+ case ButtonRelease:
+ if(inruler != NORULER) {
+ XUndefineCursor(dpy, top.win);
+ DRAW_RULER();
+ UNSET_RULER();
+ }
+ break;
+ case MotionNotify:
+ if(inruler != NORULER)
+ MOVE_RULER(ev->xmotion.x, ev->xmotion.y);
+ break;
+ case GraphicsExpose:
+ case Expose:
+ do_expose(dvi, ev->xexpose.x, ev->xexpose.y,
+ ev->xexpose.width, ev->xexpose.height);
+ dviwin.dirty = 1;
+ break;
+ }
+}
+
+void view_page(DviContext *dvi, int pageno)
+{
+ GET_DRAW_DATA;
+
+ if(busy == None)
+ busy = XCreateFontCursor(dpy, XC_watch);
+ if(point == None)
+ point = XCreateFontCursor(dpy, XC_crosshair);
+ do_expose(dvi, 0, 0, dviwin.w, dviwin.h);
+ set_pageno(dvi, pageno);
+ expose_window(dviwin.win, True);
+ while(top.active) {
+ XEvent ev;
+
+ if(!XPending(dpy)) {
+ if(dviwin.dirty)
+ do_redraw(dvi);
+ else if(reset_origin) {
+ position_windows(dvi);
+ reset_view_origin(dvi);
+ set_pageno(dvi, dvi->currpage);
+ reset_origin = 0;
+ }
+ }
+
+ XNextEvent(dpy, &ev);
+ if(ev.xany.window == top.win)
+ top_events(dvi, &ev);
+ else if(ev.xany.window == dviwin.win)
+ handle_dvi(dvi, &ev);
+ }
+ /* destroy everything */
+ XFreeGC(dpy, drawgc);
+ XFreeGC(dpy, rulergc);
+ XFreeGC(dpy, scrollgc);
+ XDestroyWindow(dpy, dviwin.win);
+ /* destroy our private data */
+ xfree(dvi->device.device_data);
+ dvi->device.device_data = NULL;
+}
diff --git a/dviware/mdvi/x11/x11.c b/dviware/mdvi/x11/x11.c
new file mode 100644
index 0000000000..cd28fa1ba4
--- /dev/null
+++ b/dviware/mdvi/x11/x11.c
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* This file contains routines I always use to make X programming easier */
+
+#include "common.h"
+
+#ifndef X_DISPLAY_MISSING
+
+/*#define XSYNCH*/
+#define DEFAULT_FONT "-*-helvetica-medium-r-*-*-*-*-*-*-*-*-*-*"
+
+#include "x11.h"
+#include "bitmap.h"
+#include "private.h"
+
+#include <X11/Xatom.h>
+
+Display *dpy = NULL;
+int scrno = 0;
+GC normal_gc = NULL;
+GC image_gc = NULL;
+GC inv_gc = NULL;
+int depth = 0;
+Visual *visual = NULL;
+Colormap colormap = None;
+XFontStruct *default_font = NULL;
+int bell_percent = 100;
+
+static Window group_leader = None;
+static Atom protocols = None;
+static Atom delete = None;
+static XImage *image = NULL;
+
+Uint root_w = 0;
+Uint root_h = 0;
+Ulong black;
+Ulong white;
+
+int errorhandler(Display *d, XErrorEvent *e)
+{
+ d=d, e=e;
+ abort();
+}
+
+#define NORMAL_EVENTS \
+ (ExposureMask|KeyPressMask|StructureNotifyMask|\
+ ButtonPressMask|ButtonReleaseMask)
+
+/* functions to query information about a window */
+
+void get_screen_size(int *w, int *h)
+{
+ *w = root_w;
+ *h = root_h;
+}
+
+void beep_sound(void)
+{
+ XBell(dpy, bell_percent);
+}
+
+int get_win_size(Window win, Uint *w, Uint *h)
+{
+ Window junk;
+ int junk1;
+
+ XGetGeometry(dpy, win,
+ &junk, &junk1, &junk1,
+ w, h,
+ (Uint*)&junk1, (Uint*)&junk1);
+ return 0;
+}
+
+void free_propdata(PropData *prop)
+{
+ if(prop->name) {
+ /* this pointer was returned by XGetAtomName */
+ XFree(prop->name);
+ prop->name = NULL;
+ }
+ prop->format = 8;
+ prop->type = XA_STRING;
+ prop->nitems = 0;
+ if(prop->data) {
+ xfree(prop->data);
+ prop->data = NULL;
+ }
+}
+
+/*
+ * This is a general purpose function to get the data associated to a
+ * window's property. It serves as an example of how to use
+ * XGetWindowProperty.
+ *
+ * Returns -1 if there was an error, 0 on success. If all is well, it fills
+ * the `ret' PropData structure with all the information reported about the
+ * property. It must be freed with `free_propdata()'.
+ */
+int get_window_property(Display *dpy, Window w, Atom property, PropData *ret)
+{
+ Uchar *data;
+ int status;
+ Atom prop_type;
+ int prop_format;
+ Ulong prop_nitems;
+ Ulong bytes_left;
+ Uchar *copy, *ptr;
+ long size;
+ long length;
+ long total;
+
+ /* request 1024 32bit words (we'll probably get much less than
+ * that), and get format and type */
+ status = XGetWindowProperty(dpy, w, property,
+ 0L, 1024, False,
+ AnyPropertyType, &prop_type,
+ &prop_format, &prop_nitems,
+ &bytes_left, &data);
+
+ if(status != Success || prop_type == None)
+ return -1;
+
+ /* this is the number of bytes we just read */
+ length = prop_nitems * (prop_format >> 3);
+
+ /* this is the total length of the data for this property */
+ total = length + bytes_left;
+
+ /* allocate memory to hold all the data for this property.
+ *
+ * Note that we allocate one extra byte and set that to 0 so strings
+ * can be used directly. The docs for XGetWindowProperty say that
+ * this is automatically done, but they don't mention if this extra
+ * byte is included in the # of items returned. I assume it is not.
+ * The worst that can happen is that we're adding a second NUL at
+ * the end, but I better be safe than sorry.
+ */
+ ptr = copy = (Uchar *)xmalloc(total + 1);
+ size = total;
+ if(ptr == NULL) {
+ XFree(data);
+ return -1;
+ }
+
+ /* copy what we have so far */
+ memcpy(copy, data, length);
+ ptr = copy + length;
+
+ /* we dont need this anymore */
+ XFree(data);
+
+ while(bytes_left) {
+ int nbytes;
+
+ /* we could request all the data that is left, but
+ * this will work too */
+ XGetWindowProperty(dpy, w, property,
+ length / 4, 1024L, False,
+ AnyPropertyType, &prop_type,
+ &prop_format, &prop_nitems,
+ &bytes_left, &data);
+
+ /* # of bytes we read */
+ nbytes = prop_nitems * (prop_format >> 3);
+
+ /* # of bytes so far */
+ length += nbytes;
+
+ /* check that we don't have more data than we should */
+ if(length > total) {
+ printf("I expected %ld bytes, but already got %ld, "
+ "and there are %ld more to come.\n",
+ total, length, bytes_left);
+ break;
+ }
+ /* update our copy */
+ memcpy(ptr, data, nbytes);
+ XFree(data);
+ ptr += nbytes;
+ }
+ copy[length] = 0;
+
+ /* fill the PropData structure */
+ ret->name = XGetAtomName(dpy, property);
+ ret->format = prop_format;
+ ret->type = prop_type;
+ ret->nitems = length / (prop_format >> 3);
+ ret->data = copy;
+
+ return 0;
+}
+
+/* open a connection to a remote display */
+int init_x11(void)
+{
+ XGCValues xg;
+ XKeyboardState kbd;
+
+ dpy = XOpenDisplay(NULL);
+ if(dpy == NULL) {
+ error(_("connection to X server failed\n"));
+ return -1;
+ }
+ scrno = DefaultScreen(dpy);
+ get_win_size(RootWindow(dpy, scrno), &root_w, &root_h);
+ depth = DefaultDepth(dpy, scrno);
+ visual = DefaultVisual(dpy, scrno);
+ colormap = DefaultColormap(dpy, scrno);
+ black = BlackPixel(dpy, scrno);
+ white = WhitePixel(dpy, scrno);
+
+ /* load a default font */
+ default_font = XLoadQueryFont(dpy, DEFAULT_FONT);
+ if(default_font == NULL)
+ default_font = XLoadQueryFont(dpy, "fixed");
+ if(default_font == NULL) {
+ error(_("%s: could not find display font `%s'\n"),
+ program_name, DEFAULT_FONT);
+ XCloseDisplay(dpy);
+ return -1;
+ }
+
+ /* create GCs */
+ xg.foreground = black;
+ xg.background = white;
+ xg.font = default_font->fid;
+ xg.graphics_exposures = False;
+ normal_gc = XCreateGC(dpy, RootWindow(dpy, scrno),
+ GCForeground|GCBackground|GCGraphicsExposures|GCFont, &xg);
+ image_gc = XCreateGC(dpy, RootWindow(dpy, scrno),
+ GCForeground|GCBackground|GCGraphicsExposures|GCFont, &xg);
+#ifdef CHEAP_X_TRICK
+ XSetFunction(dpy, image_gc, GXand);
+#endif
+ xg.foreground = white;
+ xg.background = black;
+ inv_gc = XCreateGC(dpy, RootWindow(dpy, scrno),
+ GCForeground|GCBackground|GCGraphicsExposures|GCFont, &xg);
+
+ image = XCreateImage(dpy, visual, 1, XYBitmap, 0,
+ (char *)0, 0, 0, BITMAP_BITS, 0);
+#ifdef WORD_BIG_ENDIAN
+ image->byte_order = image->bitmap_bit_order = MSBFirst;
+#else
+ image->byte_order = image->bitmap_bit_order = LSBFirst;
+#endif
+
+#if !defined(NODEBUG) && defined(XSYNCH)
+ XSynchronize(dpy, True);
+ XSetErrorHandler(errorhandler);
+#endif
+
+ /* get keyboard state */
+ XGetKeyboardControl(dpy, &kbd);
+ bell_percent = kbd.bell_percent;
+ if(bell_percent < -100)
+ bell_percent = -100;
+ if(bell_percent > 100)
+ bell_percent = 100;
+
+ return 0;
+}
+
+int window_closed(XClientMessageEvent *ev, Window w)
+{
+ if(ev->window != w)
+ return 0;
+ if(ev->message_type == protocols && ev->data.l[0] == delete)
+ return 1;
+ return 0;
+}
+
+int handle_top_events(TopWindow *tw, XEvent *ev)
+{
+ if(ev->xany.window != tw->win)
+ return 0;
+ switch(ev->type) {
+ case ClientMessage:
+ if(window_closed(&ev->xclient, tw->win)) {
+ tw->active = 0;
+ return 1;
+ }
+ break;
+ case ConfigureNotify:
+ tw->w = ev->xconfigure.width;
+ tw->h = ev->xconfigure.height;
+ break;
+ case KeyPress: {
+ if(XLookupKeysym((XKeyEvent *)ev, 0) == XK_Escape) {
+ tw->active = 0;
+ return 1;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+void close_top_window(TopWindow *tw)
+{
+ XDestroyWindow(dpy, tw->win);
+ if(tw->win == group_leader)
+ group_leader = None;
+ tw->win = None;
+ tw->active = 0;
+}
+
+void expose_window(Window w, Bool putback)
+{
+ XEvent ev;
+
+ XMapWindow(dpy, w);
+ while(!XCheckTypedWindowEvent(dpy, w, Expose, &ev))
+ ;
+ if(putback)
+ XPutBackEvent(dpy, &ev);
+}
+
+void resize_top_window(TopWindow *tw, Uint w, Uint h)
+{
+ XSizeHints size_hints;
+
+ size_hints.width = w;
+ size_hints.height = h;
+ size_hints.flags = USSize;
+ XSetWMNormalHints(dpy, tw->win, &size_hints);
+ XResizeWindow(dpy, tw->win, w, h);
+ XFlush(dpy);
+ get_win_size(tw->win, &tw->w, &tw->h);
+}
+
+int create_top_window(TopWindow *tw, const char *name, int w, int h)
+{
+ XSetWindowAttributes xwa;
+
+ if(dpy == NULL && init_x11() == -1)
+ return -1;
+
+ if(w > root_w)
+ w = root_w;
+ if(h > root_h)
+ h = root_h;
+
+ xwa.background_pixel = white;
+ xwa.backing_pixel = white;
+ xwa.bit_gravity = NorthWestGravity;
+ xwa.backing_store = WhenMapped;
+ xwa.colormap = colormap;
+
+ tw->win = XCreateWindow(dpy,
+ RootWindow(dpy, scrno), 0, 0,
+ w, h, 0, depth,
+ InputOutput, CopyFromParent,
+ CWBackPixel|CWBackingPixel|
+ CWBitGravity|CWBackingStore|
+ CWColormap, &xwa);
+
+ /* select `Expose' events */
+ XSelectInput(dpy, tw->win, NORMAL_EVENTS);
+ XStoreName(dpy, tw->win, name);
+
+ protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
+ delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+ if(delete != None)
+ XSetWMProtocols(dpy, tw->win, &delete, 1);
+
+ /* set this as group leader, if it's the first */
+ if(group_leader == None)
+ group_leader = tw->win;
+ else {
+ XWMHints hints;
+
+ hints.window_group = (XID)group_leader;
+ hints.flags = WindowGroupHint;
+ XSetWMHints(dpy, tw->win, &hints);
+ }
+
+ tw->active = 1;
+ return 0;
+}
+
+void set_max_winsize(Window win, int w, int h)
+{
+ XSizeHints size_hints;
+
+ size_hints.flags = PMaxSize;
+ size_hints.max_width = w;
+ size_hints.max_height = h;
+ XSetWMNormalHints(dpy, win, &size_hints);
+}
+
+void add_window_events(Window w, Ulong mask)
+{
+ XWindowAttributes attr;
+
+ XGetWindowAttributes(dpy, w, &attr);
+ attr.your_event_mask |= mask;
+ XSelectInput(dpy, w, attr.your_event_mask);
+ XFlush(dpy);
+}
+
+void clear_window_events(Window w, Ulong mask)
+{
+ XWindowAttributes attr;
+
+ XGetWindowAttributes(dpy, w, &attr);
+ attr.your_event_mask &= ~mask;
+ XSelectInput(dpy, w, attr.your_event_mask);
+ XFlush(dpy);
+}
+
+void set_window_events(Window w, Ulong mask)
+{
+ XSelectInput(dpy, w, mask);
+}
+
+Window create_window(Window parent, Ulong c, int w, int h, int b)
+{
+ XSetWindowAttributes xwa;
+ Window win;
+
+ if(parent == None)
+ parent = RootWindow(dpy, scrno);
+
+ xwa.background_pixel = c;
+ xwa.bit_gravity = NorthWestGravity;
+#ifndef NODEBUG
+ xwa.backing_store = NotUseful;
+#else
+ xwa.backing_store = WhenMapped;
+#endif
+ xwa.colormap = colormap;
+ xwa.border_pixel = black;
+ win = XCreateWindow(dpy, parent, 0, 0,
+ w, h, b, depth,
+ InputOutput, CopyFromParent,
+ CWBackPixel|CWBitGravity|CWBackingStore|CWColormap,
+ &xwa);
+
+ /* select `Expose' events */
+ set_window_events(win, NORMAL_EVENTS);
+
+ return win;
+}
+
+Window create_subwindow(Window parent, Ulong c, int x, int y, int w, int h, int b)
+{
+ XSetWindowAttributes xwa;
+ Window win;
+
+ if(parent == None)
+ parent = RootWindow(dpy, scrno);
+
+ xwa.background_pixel = c;
+ xwa.bit_gravity = NorthWestGravity;
+#ifndef NODEBUG
+ xwa.backing_store = NotUseful;
+#else
+ xwa.backing_store = WhenMapped;
+#endif
+ xwa.colormap = colormap;
+ xwa.border_pixel = black;
+ win = XCreateWindow(dpy, parent,
+ x, y, w, h, b, depth,
+ InputOutput, CopyFromParent,
+ CWBackPixel|CWBitGravity|CWBackingStore|
+ CWColormap, &xwa);
+
+ /* select `Expose' events */
+ set_window_events(win, NORMAL_EVENTS);
+
+ return win;
+}
+
+Pixmap create_pixmap(Window parent, int w, int h)
+{
+ Pixmap p;
+
+ p = XCreatePixmap(dpy, parent, w, h, depth);
+ XFillRectangle(dpy, p, inv_gc, 0, 0, w, h);
+ return p;
+}
+
+int create_draw_area(DrawArea *area, Window in, int w, int h, int b)
+{
+ XGCValues xgc;
+
+ area->win = create_window(in, white, w, h, b);
+ if(area->win == None)
+ return -1;
+ xgc.foreground = black;
+ xgc.background = white;
+ xgc.graphics_exposures = False;
+ area->gc = XCreateGC(dpy, area->win,
+ GCForeground|GCBackground|GCGraphicsExposures, &xgc);
+ area->p = create_pixmap(area->win, w, h);
+ area->w = w;
+ area->h = h;
+ area->hidden = 1;
+ area->fg = black;
+ area->bg = white;
+ return 0;
+}
+
+void set_area_foreground(DrawArea *area, Ulong fg)
+{
+ if(fg != area->fg) {
+ XSetForeground(dpy, area->gc, fg);
+ area->fg = fg;
+ }
+}
+
+void set_area_background(DrawArea *area, Ulong bg)
+{
+ if(bg != area->bg) {
+ XSetBackground(dpy, area->gc, bg);
+ area->bg = bg;
+ }
+}
+
+void destroy_area(DrawArea *area)
+{
+ XFreePixmap(dpy, area->p);
+ XFreeGC(dpy, area->gc);
+ XDestroyWindow(dpy, area->win);
+ area->win = None;
+ area->p = None;
+ area->w = 0;
+ area->h = 0;
+ area->hidden = 1;
+ area->gc = NULL;
+}
+
+void refresh_area(DrawArea *area, int x, int y, int w, int h)
+{
+ if(!area->hidden)
+ XCopyArea(dpy, area->p, area->win, area->gc, x, y, w, h, x, y);
+}
+
+void clear_area(DrawArea *area)
+{
+ XSetForeground(dpy, area->gc, area->bg);
+ XFillRectangle(dpy, area->p, area->gc, 0, 0, area->w, area->h);
+ XClearArea(dpy, area->win, 0, 0, area->w, area->h, True);
+ XSetForeground(dpy, area->gc, area->fg);
+}
+
+void show_area(DrawArea *area)
+{
+ XEvent ev;
+
+ if(!area->hidden)
+ return;
+ add_window_events(area->win, ExposureMask);
+ XFlush(dpy);
+ XMapWindow(dpy, area->win);
+ while(!XCheckTypedWindowEvent(dpy, area->win, Expose, &ev))
+ ;
+ XPutBackEvent(dpy, &ev);
+ area->hidden = 0;
+}
+
+void hide_area(DrawArea *area)
+{
+ XUnmapWindow(dpy, area->win);
+ area->hidden = 1;
+}
+
+int resize_area(DrawArea *area, Uint w, Uint h)
+{
+ Pixmap p;
+
+ p = create_pixmap(area->win, w, h);
+ if(p == None)
+ return -1;
+ XFreePixmap(dpy, area->p);
+ area->p = p;
+ XResizeWindow(dpy, area->win, w, h);
+ area->w = w;
+ area->h = h;
+ return 0;
+}
+
+void set_clip_area(DrawArea *area, int x, int y, int w, int h)
+{
+ XRectangle rect;
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+ XSetClipRectangles(dpy, area->gc, 0, 0, &rect, 1, Unsorted);
+}
+
+void draw_line(Drawable d, int x0, int y0, int x1, int y1)
+{
+ XDrawLine(dpy, d, normal_gc, x0, y0, x1, y1);
+}
+
+void draw_box(Drawable d, int x, int y, int w, int h, int filled)
+{
+ if(filled)
+ XFillRectangle(dpy, d, normal_gc, x, y, w, h);
+ else
+ XDrawRectangle(dpy, d, normal_gc, x, y, w, h);
+}
+
+void attach_window(Window win, Window to)
+{
+ XReparentWindow(dpy, win, to, 0, 0);
+}
+
+void detach_window(TopWindow *tw, Window win, int x, int y)
+{
+ /* set window transient for the top window */
+ if(tw && win == tw->win)
+ return;
+ if(tw != NULL)
+ XSetTransientForHint(dpy, win, tw->win);
+ /* make window a child of the root */
+ XReparentWindow(dpy, win, RootWindow(dpy, scrno), x, y);
+ /* and make it exit cleanly */
+ if(delete != None)
+ XSetWMProtocols(dpy, win, &delete, 1);
+}
+
+void close_x11(void)
+{
+ XFreeGC(dpy, normal_gc);
+ XFreeGC(dpy, inv_gc);
+ XFreeGC(dpy, image_gc);
+ XFreeFont(dpy, default_font);
+ XCloseDisplay(dpy);
+ dpy = NULL;
+}
+
+void draw_bitmap(Drawable d, BITMAP *bm, int x, int y)
+{
+ if(bm->width <= 0 || bm->height <= 0)
+ return;
+ /* create X image */
+ if(bm->data != NULL) {
+ image->width = bm->width;
+ image->height = bm->height;
+ image->data = (char *)bm->data;
+ image->bytes_per_line = bm->stride;
+ XPutImage(dpy, d, image_gc, image,
+ 0, 0, x, y,
+ bm->width, bm->height);
+ }
+}
+
+void put_image(Drawable d, void *image, int x, int y, int w, int h)
+{
+ XPutImage(dpy, d, image_gc, (XImage *)image,
+ 0, 0, x, y, w, h);
+}
+
+GC create_gc(int func, Window p, Ulong fg, Ulong bg)
+{
+ XGCValues xgc;
+
+ xgc.foreground = fg;
+ xgc.background = bg;
+ xgc.function = func;
+ xgc.font = default_font->fid;
+ xgc.graphics_exposures = False;
+ return XCreateGC(dpy, p,
+ GCFunction|GCForeground|GCBackground|
+ GCGraphicsExposures|GCFont, &xgc);
+}
+
+void draw_text(DrawArea *area, GC gc, int x, int y, const char *text, int justify)
+{
+ int n = strlen(text);
+ int w, y0;
+
+ w = XTextWidth(default_font, text, n);
+ switch(justify & MX11_HJUSTIFY) {
+ case MX11_LEFT:
+ x = 2; break;
+ case MX11_RIGHT:
+ x = area->w - w - 2;
+ if(x < 2) x = 2;
+ break;
+ case MX11_HCENTER:
+ x = (area->w - w) / 2;
+ break;
+ }
+ switch(justify & MX11_VJUSTIFY) {
+ case MX11_ABOVE:
+ y -= default_font->max_bounds.descent;
+ if(y < 2) y = 2;
+ break;
+ case MX11_BELOW:
+ y += default_font->max_bounds.ascent;
+ if(y + default_font->max_bounds.descent + 2 > area->h)
+ y = area->h - default_font->max_bounds.descent - 2;
+ if(y < 2) y = 2;
+ break;
+ case MX11_VCENTER:
+ y -= FONT_HEIGHT(default_font) / 2 +
+ default_font->max_bounds.ascent;
+ if(y < 2) y = 2;
+ break;
+ }
+ if(gc == NULL)
+ gc = area->gc;
+ y0 = y - default_font->max_bounds.ascent;
+ XFillRectangle(dpy, area->p, inv_gc,
+ x, y0, w, FONT_HEIGHT(default_font));
+ XDrawString(dpy, area->p, gc, x, y, text, n);
+}
+
+Ulong get_color_byname(const char *name)
+{
+ XColor xc;
+
+ if(dpy == NULL)
+ return 0UL;
+ if(!XParseColor(dpy, colormap, name, &xc)) {
+ warning(_("invalid color name `%s', using black\n"));
+ return black;
+ }
+ if(!XAllocColor(dpy, colormap, &xc)) {
+ warning(_("failed to allocate color `%s', using black\n"));
+ return black;
+ }
+ return xc.pixel;
+}
+
+#endif /* X_DISPLAY_MISSING */
diff --git a/dviware/mdvi/x11/x11.h b/dviware/mdvi/x11/x11.h
new file mode 100644
index 0000000000..fafdff5425
--- /dev/null
+++ b/dviware/mdvi/x11/x11.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2000, Matias Atria
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#include "mdvi.h"
+
+typedef struct {
+ char *name; /* name of the property */
+ int format; /* format = 8, 16, 32 */
+ Atom type;
+ int nitems;
+ Uchar *data;
+} PropData;
+
+typedef struct {
+ Window win;
+ Pixmap p;
+ int w, h;
+ int hidden;
+ GC gc;
+ Ulong fg;
+ Ulong bg;
+} DrawArea;
+
+typedef struct {
+ Window win;
+ Uint w;
+ Uint h;
+ int active;
+} TopWindow;
+
+extern Display *dpy;
+extern Colormap colormap;
+extern int scrno;
+extern GC normal_gc;
+extern GC inv_gc;
+extern GC color_gc;
+extern GC image_gc;
+extern int depth;
+extern Visual *visual;
+extern Ulong black;
+extern Ulong white;
+extern XFontStruct *default_font;
+extern Uint root_w;
+extern Uint root_h;
+
+#define MX11_LEFT 0x0001
+#define MX11_RIGHT 0x0002
+#define MX11_HCENTER 0x0004
+#define MX11_ABOVE 0x0100
+#define MX11_BELOW 0x0200
+#define MX11_VCENTER 0x0400
+#define MX11_HJUSTIFY 0x00ff
+#define MX11_VJUSTIFY 0xff00
+
+#define FONT_HEIGHT(x) ((x)->max_bounds.ascent + (x)->max_bounds.descent)
+#define FONT_ASCENT(x) ((x)->max_bounds.ascent)
+#define FONT_DESCENT(x) ((x)->max_bounds.descent)
+
+extern int init_x11 (void);
+extern void close_x11 (void);
+extern int handle_top_events (TopWindow *, XEvent *);
+extern int create_top_window (TopWindow *, const char *, int, int);
+extern void resize_top_window (TopWindow *, Uint, Uint);
+extern Window create_window (Window, Ulong, int, int, int);
+extern Window create_subwindow (Window, Ulong, int, int, int, int, int);
+extern void expose_window (Window, Bool);
+extern void close_top_window (TopWindow *);
+extern void set_max_winsize (Window, int, int);
+extern void set_window_events (Window, Ulong);
+extern void add_window_events (Window, Ulong);
+extern void clear_window_events (Window, Ulong);
+extern Pixmap create_pixmap (Window, int, int);
+extern int create_draw_area (DrawArea *, Window, int, int, int);
+extern void destroy_area (DrawArea *);
+extern void refresh_area (DrawArea *, int, int, int, int);
+extern void show_area (DrawArea *);
+extern void hide_area (DrawArea *);
+extern void clear_area (DrawArea *);
+extern int resize_area (DrawArea *, Uint, Uint);
+extern void set_clip_area (DrawArea *, int, int, int, int);
+extern void resize_top (TopWindow *, Uint, Uint);
+extern int get_win_size (Window, Uint *, Uint *);
+extern void draw_line (Drawable, int, int, int, int);
+extern void draw_box (Drawable, int, int, int, int, int);
+extern void draw_bitmap (Drawable, BITMAP *, int, int);
+extern void draw_text (DrawArea *, GC, int, int, const char *, int);
+extern void put_image (Drawable, void *, int, int, int, int);
+extern int window_closed (XClientMessageEvent *, Window);
+extern void detach_window (TopWindow *, Window, int, int);
+extern void attach_window (Window, Window);
+extern GC create_gc (int, Window, Ulong, Ulong);
+
+extern void beep_sound(void);
+extern void set_area_foreground(DrawArea *, Ulong);
+extern void set_area_background(DrawArea *, Ulong);
+extern Ulong get_color_byname (const char *);
+
+extern int get_window_property (Display *, Window, Atom, PropData *);
+extern void free_propdata (PropData *);