/* * x11.c * kirk johnson * july 1993 * * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson * * Parts of the source code (as marked) are: * Copyright (C) 1989, 1990, 1991 by Jim Frost * Copyright (C) 1992 by Jamie Zawinski * * Permission to use, copy, modify and freely distribute xearth for * non-commercial and not-for-profit purposes is hereby granted * without fee, provided that both the above copyright notice and this * permission notice appear in all copies and in supporting * documentation. * * Unisys Corporation holds worldwide patent rights on the Lempel Zev * Welch (LZW) compression technique employed in the CompuServe GIF * image file format as well as in other formats. Unisys has made it * clear, however, that it does not require licensing or fees to be * paid for freely distributed, non-commercial applications (such as * xearth) that employ LZW/GIF technology. Those wishing further * information about licensing the LZW patent should contact Unisys * directly at (lzw_info@unisys.com) or by writing to * * Unisys Corporation * Welch Licensing Department * M/S-C1SW19 * P.O. Box 500 * Blue Bell, PA 19424 * * The author makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "xearth.h" #include #include #include #include #include #include "kljcpyrt.h" #define RETAIN_PROP_NAME "_XSETROOT_ID" #define MONO_1 (0) #define MONO_8 (1) #define COLOR_8 (2) #define MONO_16 (3) #define COLOR_16 (4) #define MONO_32 (5) #define COLOR_32 (6) #define LABEL_LEFT_FLUSH (1<<0) #define LABEL_TOP_FLUSH (1<<1) static void init_x_general _P((int, char *[])); static void process_opts _P((void)); static void init_x_colors _P((void)); static void init_x_pixmaps _P((void)); static void init_x_root_window _P((void)); static void init_x_separate_window _P((void)); static void wakeup _P((int)); static int get_bits_per_pixel _P((int)); static XFontStruct *load_x_font _P((Display *, char *)); static void get_proj_type _P((void)); static void get_viewing_position _P((void)); static void get_sun_position _P((void)); static void get_rotation _P((void)); static void get_size _P((void)); static void get_shift _P((void)); static void get_labelpos _P((void)); static void get_geometry _P((void)); static void x11_setup _P((void)); static void pack_mono_1 _P((u16or32 *, u_char *)); static void pack_8 _P((u16or32 *, Pixel *, u_char *)); static void pack_16 _P((u16or32 *, Pixel *, u_char *)); static void pack_24 _P((u16or32 *, Pixel *, u_char *)); static void pack_32 _P((u16or32 *, Pixel *, u_char *)); static int x11_row _P((u_char *)); static void x11_cleanup _P((void)); static void draw_label _P((Display *)); static void mark_location _P((Display *, MarkerInfo *)); static void draw_outlined_string _P((Display *, Pixmap, Pixel, Pixel, int, int, char *, int)); static Window GetVRoot _P((Display *)); static void updateProperty _P((Display *, Window, const char *, Atom, int, int, int)); static void preserveResource _P((Display *, Window)); static void freePrevious _P((Display *, Window)); static int xkill_handler _P((Display *, XErrorEvent *)); static int bpp; static u16or32 *dith; static u_char *xbuf; static int idx; static XImage *xim; static Pixmap work_pix; static Pixmap disp_pix; static int (*orig_error_handler) _P((Display *, XErrorEvent *)); #ifdef DEBUG static int frame = 0; #endif /* DEBUG */ char *progclass; Widget app_shell; XtAppContext app_context; XrmDatabase db; Display *dsply; /* display connection */ int scrn; /* screen number */ Window root; /* root window */ Window xearth_window; /* xearth window */ Colormap cmap; /* default colormap */ Visual *visl; /* default visual */ int dpth; /* default depth */ Pixel white; /* white pixel */ Pixel black; /* black pixel */ Pixel hlight; /* highlight pixel */ GC gc; /* graphics context */ Pixel *pels; /* allocated colors */ char *font_name; /* text font name */ XFontStruct *font; /* basic text font */ static int do_once; /* only render once? */ static int mono; /* render in mono? */ static int use_root; /* render into root? */ static int window_pos_flag; /* spec'ed window pos? */ static int window_xvalue; /* window x position */ static int window_yvalue; /* window y position */ static int window_gravity; /* window gravity */ static int label_xvalue; /* label x position */ static int label_yvalue; /* label y position */ static int label_orient; /* label orientation */ static char *defaults[] = { "*proj: orthographic", "*pos: sunrel 0 0", "*rot: 0", "*shift: 0 0", "*mag: 1.0", "*shade: on", "*label: off", "*labelpos: -5-5", "*markers: on", "*markerfile: built-in", "*wait: 300", "*timewarp: 1", "*day: 100", "*night: 5", "*term: 1", "*twopix: on", "*ncolors: 64", "*fork: off", "*once: off", "*nice: 0", "*stars: on", "*starfreq: 0.002", "*bigstars: 0", "*grid: off", "*grid1: 6", "*grid2: 15", "*gamma: 1.0", "*font: variable", "*title: xearth", "*iconname: xearth", NULL }; static XrmOptionDescRec options[] = { { "-proj", ".proj", XrmoptionSepArg, 0 }, { "-pos", ".pos", XrmoptionSepArg, 0 }, { "-rot", ".rot", XrmoptionSepArg, 0 }, { "-mag", ".mag", XrmoptionSepArg, 0 }, { "-shade", ".shade", XrmoptionNoArg, "on" }, { "-noshade", ".shade", XrmoptionNoArg, "off" }, { "-sunpos", ".sunpos", XrmoptionSepArg, 0 }, { "-size", ".size", XrmoptionSepArg, 0 }, { "-shift", ".shift", XrmoptionSepArg, 0 }, { "-label", ".label", XrmoptionNoArg, "on" }, { "-nolabel", ".label", XrmoptionNoArg, "off" }, { "-labelpos", ".labelpos", XrmoptionSepArg, 0 }, { "-markers", ".markers", XrmoptionNoArg, "on" }, { "-nomarkers", ".markers", XrmoptionNoArg, "off" }, { "-markerfile", ".markerfile", XrmoptionSepArg, 0 }, { "-showmarkers", ".showmarkers", XrmoptionNoArg, "on" }, { "-wait", ".wait", XrmoptionSepArg, 0 }, { "-timewarp", ".timewarp", XrmoptionSepArg, 0 }, { "-day", ".day", XrmoptionSepArg, 0 }, { "-night", ".night", XrmoptionSepArg, 0 }, { "-term", ".term", XrmoptionSepArg, 0 }, { "-onepix", ".twopix", XrmoptionNoArg, "off" }, { "-twopix", ".twopix", XrmoptionNoArg, "on" }, { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, { "-fork", ".fork", XrmoptionNoArg, "on" }, { "-nofork", ".fork", XrmoptionNoArg, "off" }, { "-once", ".once", XrmoptionNoArg, "on" }, { "-noonce", ".once", XrmoptionNoArg, "off" }, { "-nice", ".nice", XrmoptionSepArg, 0 }, { "-version", ".version", XrmoptionNoArg, "on" }, { "-stars", ".stars", XrmoptionNoArg, "on" }, { "-nostars", ".stars", XrmoptionNoArg, "off" }, { "-starfreq", ".starfreq", XrmoptionSepArg, 0 }, { "-bigstars", ".bigstars", XrmoptionSepArg, 0 }, { "-grid", ".grid", XrmoptionNoArg, "on" }, { "-nogrid", ".grid", XrmoptionNoArg, "off" }, { "-grid1", ".grid1", XrmoptionSepArg, 0 }, { "-grid2", ".grid2", XrmoptionSepArg, 0 }, { "-time", ".time", XrmoptionSepArg, 0 }, { "-gamma", ".gamma", XrmoptionSepArg, 0 }, { "-font", ".font", XrmoptionSepArg, 0 }, { "-mono", ".mono", XrmoptionNoArg, "on" }, { "-nomono", ".mono", XrmoptionNoArg, "off" }, { "-root", ".root", XrmoptionNoArg, "on" }, { "-noroot", ".root", XrmoptionNoArg, "off" }, { "-geometry", ".geometry", XrmoptionSepArg, 0 }, { "-title", ".title", XrmoptionSepArg, 0 }, { "-iconname", ".iconname", XrmoptionSepArg, 0 }, }; void command_line_x(argc, argv) int argc; char *argv[]; { init_x_general(argc, argv); process_opts(); init_x_colors(); init_x_pixmaps(); font = load_x_font(dsply, font_name); if (use_root) init_x_root_window(); else init_x_separate_window(); } static void init_x_general(argc, argv) int argc; char *argv[]; { progname = argv[0]; progclass = "XEarth"; app_shell = XtAppInitialize(&app_context, progclass, options, XtNumber(options), &argc, argv, defaults, 0, 0); if (argc > 1) usage(NULL); dsply = XtDisplay(app_shell); scrn = DefaultScreen(dsply); db = XtDatabase(dsply); XtGetApplicationNameAndClass(dsply, &progname, &progclass); root = RootWindow(dsply, scrn); cmap = DefaultColormap(dsply, scrn); visl = DefaultVisual(dsply, scrn); dpth = DefaultDepth(dsply, scrn); wdth = DisplayWidth(dsply, scrn); hght = DisplayHeight(dsply, scrn); white = WhitePixel(dsply, scrn); black = BlackPixel(dsply, scrn); gc = XCreateGC(dsply, root, 0, NULL); hlight = white; XSetState(dsply, gc, white, black, GXcopy, AllPlanes); bpp = get_bits_per_pixel(dpth); } static void process_opts() { if (get_boolean_resource("version", "Version")) version_info(1); if (get_boolean_resource("showmarkers", "Showmarkers")) { markerfile = get_string_resource("markerfile", "Markerfile"); show_marker_info(markerfile); } /* process complex resources */ get_proj_type(); get_viewing_position(); get_sun_position(); get_size(); get_shift(); get_labelpos(); get_rotation(); get_geometry(); /* process simple resources */ view_mag = get_float_resource("mag", "Mag"); do_shade = get_boolean_resource("shade", "Shade"); do_label = get_boolean_resource("label", "Label"); do_markers = get_boolean_resource("markers", "Markers"); markerfile = get_string_resource("markerfile", "Markerfile"); wait_time = get_integer_resource("wait", "Wait"); time_warp = get_float_resource("timewarp", "Timewarp"); day = get_integer_resource("day", "Day"); night = get_integer_resource("night", "Night"); terminator = get_integer_resource("term", "Term"); use_two_pixmaps = get_boolean_resource("twopix", "Twopix"); num_colors = get_integer_resource("ncolors", "Ncolors"); do_fork = get_boolean_resource("fork", "Fork"); do_once = get_boolean_resource("once", "Once"); priority = get_integer_resource("nice", "Nice"); do_stars = get_boolean_resource("stars", "Stars"); star_freq = get_float_resource("starfreq", "Starfreq"); big_stars = get_integer_resource("bigstars", "Bigstars"); do_grid = get_boolean_resource("grid", "Grid"); grid_big = get_integer_resource("grid1", "Grid1"); grid_small = get_integer_resource("grid2", "Grid2"); fixed_time = get_integer_resource("time", "Time"); xgamma = get_float_resource("gamma", "Gamma"); font_name = get_string_resource("font", "Font"); mono = get_boolean_resource("mono", "Mono"); /* various sanity checks on simple resources */ if ((view_rot < -180) || (view_rot > 360)) fatal("viewing rotation must be between -180 and 360"); if (view_mag <= 0) fatal("viewing magnification must be positive"); if (wait_time < 0) fatal("arg to -wait must be non-negative"); if (time_warp <= 0) fatal("arg to -timewarp must be positive"); if ((num_colors < 3) || (num_colors > 1024)) fatal("arg to -ncolors must be between 3 and 1024"); if ((star_freq < 0) || (star_freq > 1)) fatal("arg to -starfreq must be between 0 and 1"); if ((big_stars < 0) || (big_stars > 100)) fatal("arg to -bigstars must be between 0 and 100"); if (grid_big <= 0) fatal("arg to -grid1 must be positive"); if (grid_small <= 0) fatal("arg to -grid2 must be positive"); if ((day > 100) || (day < 0)) fatal("arg to -day must be between 0 and 100"); if ((night > 100) || (night < 0)) fatal("arg to -night must be between 0 and 100"); if ((terminator > 100) || (terminator < 0)) fatal("arg to -term must be between 0 and 100"); if (xgamma <= 0) fatal("arg to -gamma must be positive"); /* if we're only rendering once, make sure we don't * waste memory by allocating two pixmaps */ if (do_once) use_two_pixmaps = 0; /* if we're working with a one-bit display, force -mono mode */ if (dpth == 1) mono = 1; } static void init_x_colors() { int i; XColor xc, junk; u_char *tmp; double inv_xgamma; if (mono) { mono_dither_setup(); pels = (Pixel *) malloc((unsigned) sizeof(Pixel) * 2); assert(pels != NULL); pels[0] = black; pels[1] = white; } else { if (XAllocNamedColor(dsply, cmap, "red", &xc, &junk) != 0) hlight = xc.pixel; dither_setup(num_colors); pels = (Pixel *) malloc((unsigned) sizeof(Pixel) * dither_ncolors); assert(pels != NULL); tmp = dither_colormap; inv_xgamma = 1.0 / xgamma; for (i=0; iwidth = wdth; xsh->height = hght; xsh->min_width = wdth; xsh->min_height = hght; xsh->max_width = wdth; xsh->max_height = hght; xsh->base_width = wdth; xsh->base_height = hght; xsh->flags = (PSize|PMinSize|PMaxSize|PBaseSize); if (window_pos_flag) { xsh->x = window_xvalue; xsh->y = window_yvalue; xsh->win_gravity = window_gravity; xsh->flags |= (USPosition|PWinGravity); } title = get_string_resource("title", "Title"); iname = get_string_resource("iconname", "Iconname"); if ((title == NULL) || (iname == NULL)) fatal("title or iconname is NULL (this shouldn't happen)"); XSetWMNormalHints(dsply, xearth_window, xsh); XStoreName(dsply, xearth_window, title); XSetIconName(dsply, xearth_window, iname); XMapRaised(dsply, xearth_window); XSync(dsply, False); XFree((char *) xsh); free(title); free(iname); } void x11_output() { while (1) { compute_positions(); /* if we were really clever, we'd only * do this if the position has changed */ scan_map(); do_dots(); /* for now, go ahead and reload the marker info every time * we redraw, but maybe change this in the future? */ load_marker_info(markerfile); x11_setup(); render(x11_row); x11_cleanup(); if (do_once) { if (use_root) preserveResource(dsply, xearth_window); XSync(dsply, True); return; } /* schedule an alarm for wait_time seconds and pause. alarm() and * pause() are used instead of sleep so that if xearth is sent a * SIGSTOP and SIGCONT separated by more than wait_time, it will * refresh the screen as soon as the SIGCONT is received. this * facilitates graceful interaction with things like FvwmBacker. * (thanks to Richard Everson for passing this along.) */ signal(SIGALRM, wakeup); signal(SIGCONT, wakeup); if (wait_time > 0) { /* only do the alarm()/pause() stuff if wait_time is non-zero, * else alarm() will not behave as desired. */ alarm(wait_time); pause(); } } } /* no-op signal handler for catching SIGALRM and SIGCONT * (used to wake up from pause() system call) */ static void wakeup(int junk) { /* nothing */ } /* determine bits_per_pixel value for pixmaps of specified depth */ static int get_bits_per_pixel(depth) int depth; { int i; int cnt; XPixmapFormatValues *pmf; int rslt; pmf = XListPixmapFormats(dsply, &cnt); if (pmf == NULL) fatal("unable to get pixmap format list"); rslt = 0; for (i=0; ifid); } return rslt; } /* fetch and decode 'proj' resource (projection type) */ static void get_proj_type() { char *res; res = get_string_resource("proj", "Proj"); if (res != NULL) { decode_proj_type(res); free(res); } } /* fetch and decode 'pos' resource (viewing position specifier) */ static void get_viewing_position() { char *res; res = get_string_resource("pos", "Pos"); if (res != NULL) { decode_viewing_pos(res); free(res); } } /* fetch and decode 'sunpos' resource (sun position specifier) */ static void get_sun_position() { char *res; res = get_string_resource("sunpos", "Sunpos"); if (res != NULL) { decode_sun_pos(res); free(res); } } /* fetch and decode 'rot' resource (rotation specifier) */ static void get_rotation() { char *res; res = get_string_resource("rot", "Rotation"); if (res != NULL) { decode_rotation(res); free(res); } } /* fetch and decode 'size' resource (size specifier) */ static void get_size() { char *res; res = get_string_resource("size", "Size"); if (res != NULL) { decode_size(res); free(res); } } /* fetch and decode 'shift' resource (shift specifier) */ static void get_shift() { char *res; res = get_string_resource("shift", "Shift"); if (res != NULL) { decode_shift(res); free(res); } } /* fetch and decode 'labelpos' resource (label position) */ static void get_labelpos() { char *res; int mask; int x, y; unsigned w, h; /* it's somewhat brute-force ugly to hard-code these here, * duplicating information contained in defaults[], but such it is. */ label_orient = 0; label_xvalue = wdth - 5; label_yvalue = hght - 5; res = get_string_resource("labelpos", "Labelpos"); if (res != NULL) { mask = XParseGeometry(res, &x, &y, &w, &h); if (mask & (WidthValue | HeightValue)) warning("width and height ignored in label position"); if ((mask & XValue) && (mask & YValue)) { label_xvalue = x; label_yvalue = y; if ((mask & XNegative) == 0) label_orient |= LABEL_LEFT_FLUSH; if ((mask & YNegative) == 0) label_orient |= LABEL_TOP_FLUSH; } else { warning("label position must specify x and y offsets"); } free(res); } } /* fetch and decode 'root' and 'geometry' resource (whether to render * into root or separate window; if separate window, position of that * window) [this is pretty ugly code, but it gets the job done ...] */ static void get_geometry() { int check_geom; char *res; int mask; int x, y; int w, h; res = get_string_resource("root", "Root"); if (res != NULL) { free(res); if (get_boolean_resource("root", "Root")) { /* user specified -root; render into the root window * (ignore any -geometry, if provided) */ use_root = 1; check_geom = 0; } else { /* user specified -noroot; render into separate window */ use_root = 0; check_geom = 1; } } else { /* user specified neither -root nor -noroot; if -geometry is * provided, render into separate window, else render into root */ use_root = 1; check_geom = 1; } /* if check_geom isn't set, nothing more to do */ if (check_geom == 0) return; /* look for -geometry and try to make sense of it */ res = get_string_resource("geometry", "Geometry"); if (res != NULL) { /* if -geometry is specified, assume -noroot and set default width * and height (which get overridden by -geometry width and height, * if provided) */ use_root = 0; wdth = DefaultWdthHght; hght = DefaultWdthHght; mask = XParseGeometry(res, &x, &y, &w, &h); /* extract width and height information */ if ((mask & WidthValue) && (mask & HeightValue)) { wdth = w; hght = h; } else { if ((mask & WidthValue) || (mask & HeightValue)) warning("geometry must specify both width and height"); } /* extract position information */ if ((mask & XValue) && (mask & YValue)) { window_pos_flag = 1; window_xvalue = x; window_yvalue = y; if (mask & XNegative) { window_xvalue += (DisplayWidth(dsply, scrn) - wdth); window_xvalue -= (2 * DefaultBorderWidth); } if (mask & YNegative) { window_yvalue += (DisplayHeight(dsply, scrn) - hght); window_yvalue -= (2 * DefaultBorderWidth); } if (mask & XNegative) if (mask & YNegative) window_gravity = SouthEastGravity; else window_gravity = NorthEastGravity; else if (mask & YNegative) window_gravity = SouthWestGravity; else window_gravity = NorthWestGravity; } else { if ((mask & XValue) || (mask & YValue)) warning("geometry must specify both x and y offsets"); window_pos_flag = 0; window_xvalue = 0; window_yvalue = 0; window_gravity = 0; } free(res); } else if (use_root == 0) { /* if -noroot was specified but no -geometry was provided, assume * defaults */ wdth = DefaultWdthHght; hght = DefaultWdthHght; window_pos_flag = 0; window_xvalue = 0; window_yvalue = 0; } } static void x11_setup() { unsigned dith_size; unsigned xbuf_size; switch (bpp) { case 1: dith_size = wdth + 7; break; case 8: case 16: case 24: case 32: dith_size = wdth; break; default: dith_size = 0; /* keep lint happy */ fprintf(stderr, "xearth %s: fatal - unsupported pixmap format (%d bits/pixel)\n", VersionString, bpp); exit(1); } xbuf_size = (dith_size * bpp) >> 3; dith = (u16or32 *) malloc((unsigned) sizeof(u16or32) * dith_size); assert(dith != NULL); xbuf = (u_char *) malloc((unsigned) xbuf_size); assert(xbuf != NULL); xim = XCreateImage(dsply, visl, (unsigned) dpth, ZPixmap, 0, (char *) xbuf, (unsigned) wdth, 1, 8, xbuf_size); if (xim->bits_per_pixel != bpp) { fprintf(stderr, "xearth %s: fatal - unexpected bits/pixel for depth %d\n", VersionString, dpth); fprintf(stderr, " (expected %d bits/pixel, actual value is %d)\n", bpp, xim->bits_per_pixel); exit(1); } if (bpp == 1) { /* force MSBFirst bitmap_bit_order and byte_order */ xim->bitmap_bit_order = MSBFirst; xim->byte_order = MSBFirst; } idx = 0; } /* pack pixels into ximage format (assuming bits_per_pixel == 1, * bitmap_bit_order == MSBFirst, and byte_order == MSBFirst) */ static void pack_mono_1(src, dst) u16or32 *src; u_char *dst; { int i, i_lim; unsigned val; i_lim = wdth; for (i=0; i>3] = (white == 0) ? (~ val) : val; src += 8; } } /* pack pixels into ximage format (assuming bits_per_pixel == 8) */ static void pack_8(src, map, dst) u16or32 *src; Pixel *map; u_char *dst; { int i, i_lim; unsigned val; i_lim = wdth; for (i=0; ibyte_order == MSBFirst) { for (i=0; i> 8) & 0xff; dst[1] = val & 0xff; dst += 2; } } else /* (xim->byte_order == LSBFirst) */ { for (i=0; i> 8) & 0xff; dst += 2; } } } /* pack pixels into ximage format (assuming bits_per_pixel == 24) */ static void pack_24(src, map, dst) u16or32 *src; Pixel *map; u_char *dst; { int i, i_lim; unsigned val; i_lim = wdth; if (xim->byte_order == MSBFirst) { for (i=0; i> 16) & 0xff; dst[1] = (val >> 8) & 0xff; dst[2] = val & 0xff; dst += 3; } } else /* (xim->byte_order == LSBFirst) */ { for (i=0; i> 8) & 0xff; dst[2] = (val >> 16) & 0xff; dst += 3; } } } /* pack pixels into ximage format (assuming bits_per_pixel == 32) */ static void pack_32(src, map, dst) u16or32 *src; Pixel *map; u_char *dst; { int i, i_lim; unsigned val; i_lim = wdth; if (xim->byte_order == MSBFirst) { for (i=0; i> 24) & 0xff; dst[1] = (val >> 16) & 0xff; dst[2] = (val >> 8) & 0xff; dst[3] = val & 0xff; dst += 4; } } else /* (xim->byte_order == LSBFirst) */ { for (i=0; i> 8) & 0xff; dst[2] = (val >> 16) & 0xff; dst[3] = (val >> 24) & 0xff; dst += 4; } } } static int x11_row(row) u_char *row; { if (mono) mono_dither_row(row, dith); else dither_row(row, dith); switch (bpp) { case 1: pack_mono_1(dith, xbuf); break; case 8: pack_8(dith, pels, xbuf); break; case 16: pack_16(dith, pels, xbuf); break; case 24: pack_24(dith, pels, xbuf); break; case 32: pack_32(dith, pels, xbuf); break; default: fprintf(stderr, "xearth %s: fatal - unsupported pixmap format (%d bits/pixel)\n", VersionString, bpp); exit(1); } XPutImage(dsply, work_pix, gc, xim, 0, 0, 0, idx, (unsigned) wdth, 1); idx += 1; return 0; } static void x11_cleanup() { MarkerInfo *minfo; Display *dpy; Pixmap tmp; XDestroyImage(xim); free(dith); dpy = dsply; if (do_markers) { minfo = marker_info; while (minfo->label != NULL) { mark_location(dpy, minfo); minfo += 1; } } if (do_label) draw_label(dpy); XSetWindowBackgroundPixmap(dpy, xearth_window, work_pix); XClearWindow(dpy, xearth_window); XSync(dpy, True); if (use_two_pixmaps) { tmp = work_pix; work_pix = disp_pix; disp_pix = tmp; } } static void draw_label(dpy) Display *dpy; { int dy; int x, y; int len; int direction; int ascent; int descent; char buf[128]; XCharStruct extents; dy = font->ascent + font->descent + 1; if (label_orient & LABEL_TOP_FLUSH) { y = label_yvalue + font->ascent; } else { y = (hght + label_yvalue) - font->descent; #ifdef DEBUG y -= 3 * dy; /* 4 lines of text */ #else y -= 2 * dy; /* 3 lines of text */ #endif } #ifdef DEBUG frame += 1; sprintf(buf, "frame %d", frame); len = strlen(buf); XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents); if (label_orient & LABEL_LEFT_FLUSH) x = label_xvalue - extents.lbearing; else x = (wdth + label_xvalue) - extents.rbearing; draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len); y += dy; #endif /* DEBUG */ strftime(buf, sizeof(buf), "%d %b %y %H:%M %Z", localtime(¤t_time)); len = strlen(buf); XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents); if (label_orient & LABEL_LEFT_FLUSH) x = label_xvalue - extents.lbearing; else x = (wdth + label_xvalue) - extents.rbearing; draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len); y += dy; sprintf(buf, "view %.1f %c %.1f %c", fabs(view_lat), ((view_lat < 0) ? 'S' : 'N'), fabs(view_lon), ((view_lon < 0) ? 'W' : 'E')); len = strlen(buf); XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents); if (label_orient & LABEL_LEFT_FLUSH) x = label_xvalue - extents.lbearing; else x = (wdth + label_xvalue) - extents.rbearing; draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len); y += dy; sprintf(buf, "sun %.1f %c %.1f %c", fabs(sun_lat), ((sun_lat < 0) ? 'S' : 'N'), fabs(sun_lon), ((sun_lon < 0) ? 'W' : 'E')); len = strlen(buf); XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents); if (label_orient & LABEL_LEFT_FLUSH) x = label_xvalue - extents.lbearing; else x = (wdth + label_xvalue) - extents.rbearing; draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len); y += dy; } static void mark_location(dpy, info) Display *dpy; MarkerInfo *info; { int x, y; int len; double lat, lon; double pos[3]; char *text; int direction; int ascent; int descent; XCharStruct extents; lat = info->lat * (M_PI/180); lon = info->lon * (M_PI/180); pos[0] = sin(lon) * cos(lat); pos[1] = sin(lat); pos[2] = cos(lon) * cos(lat); XFORM_ROTATE(pos, view_pos_info); if (proj_type == ProjTypeOrthographic) { /* if the marker isn't visible, return immediately */ if (pos[2] <= 0) return; } else if (proj_type == ProjTypeMercator) { /* apply mercator projection */ pos[0] = MERCATOR_X(pos[0], pos[2]); pos[1] = MERCATOR_Y(pos[1]); } else /* (proj_type == ProjTypeCylindrical) */ { /* apply cylindrical projection */ pos[0] = CYLINDRICAL_X(pos[0], pos[2]); pos[1] = CYLINDRICAL_Y(pos[1]); } x = XPROJECT(pos[0]); y = YPROJECT(pos[1]); XSetForeground(dpy, gc, black); XDrawArc(dpy, work_pix, gc, x-3, y-3, 6, 6, 0, 360*64); XDrawArc(dpy, work_pix, gc, x-1, y-1, 2, 2, 0, 360*64); XSetForeground(dpy, gc, hlight); XDrawArc(dpy, work_pix, gc, x-2, y-2, 4, 4, 0, 360*64); text = info->label; if (text != NULL) { len = strlen(text); XTextExtents(font, text, len, &direction, &ascent, &descent, &extents); switch (info->align) { case MarkerAlignLeft: x -= (extents.rbearing + 4); y += (font->ascent + font->descent) / 3; break; case MarkerAlignRight: case MarkerAlignDefault: x += (extents.lbearing + 3); y += (font->ascent + font->descent) / 3; break; case MarkerAlignAbove: x -= (extents.rbearing - extents.lbearing) / 2; y -= (extents.descent + 4); break; case MarkerAlignBelow: x -= (extents.rbearing - extents.lbearing) / 2; y += (extents.ascent + 5); break; default: assert(0); } draw_outlined_string(dpy, work_pix, hlight, black, x, y, text, len); } XSetForeground(dpy, gc, white); } static void draw_outlined_string(dpy, pix, fg, bg, x, y, text, len) Display *dpy; Pixmap pix; Pixel fg; Pixel bg; int x; int y; char *text; int len; { XSetForeground(dpy, gc, bg); XDrawString(dpy, pix, gc, x+1, y, text, len); XDrawString(dpy, pix, gc, x-1, y, text, len); XDrawString(dpy, pix, gc, x, y+1, text, len); XDrawString(dpy, pix, gc, x, y-1, text, len); XSetForeground(dpy, gc, fg); XDrawString(dpy, pix, gc, x, y, text, len); } /* Function Name: GetVRoot * Description: Gets the root window, even if it's a virtual root * Arguments: the display and the screen * Returns: the root window for the client * * (taken nearly verbatim from the june 1993 comp.windows.x FAQ, item 148) */ static Window GetVRoot(dpy) Display *dpy; { int i; Window rootReturn, parentReturn, *children; unsigned int numChildren; Atom __SWM_VROOT = None; Window rslt = root; __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False); XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren); for (i=0; ierror_code == BadValue) && (xev->request_code == X_KillClient)) { fprintf(stderr, "ignoring BadValue error from XKillClient()\n"); fflush(stderr); return 0; } /* pass any other errors get on to the original error handler */ return orig_error_handler(dpy, xev); }