diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/mdvi/x11 |
Initial commit
Diffstat (limited to 'dviware/mdvi/x11')
-rw-r--r-- | dviware/mdvi/x11/Makefile.in | 60 | ||||
-rw-r--r-- | dviware/mdvi/x11/dvi.c | 1008 | ||||
-rw-r--r-- | dviware/mdvi/x11/dvidraw.c | 1510 | ||||
-rw-r--r-- | dviware/mdvi/x11/x11.c | 750 | ||||
-rw-r--r-- | dviware/mdvi/x11/x11.h | 118 |
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 *); |