home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xlibpr3.zip / basecalc / basecalc.c next >
C/C++ Source or Header  |  1991-01-26  |  34KB  |  1,329 lines

  1. /*
  2.  * Copyright 1989 O'Reilly and Associates, Inc.
  3.  * Copyright 1988 Stellar Computer, Inc.
  4.  * See ../Copyright for complete rights and liability information.
  5.  */
  6. /*
  7.  * X Version 11 Integer Programmer's Calculator
  8.  * Written by Alan Greenspan, modified slightly by Adrian Nye.
  9.  */
  10. #include <X11/Xlib.h>
  11. #include <X11/Xutil.h>
  12. #include <X11/Xresource.h>
  13. #include <X11/cursorfont.h>
  14.  
  15. #include <stdio.h>
  16.  
  17. #ifdef SysV
  18. #include <termio.h>
  19. #else
  20. #include <sgtty.h>
  21. #include <sys/ttychars.h>
  22. #endif SysV
  23.  
  24. #include <ctype.h>
  25. #include <pwd.h>
  26.  
  27. #include "basecalc.h"
  28.  
  29. /*
  30.  * Programmer's calculator with 
  31.  * number base conversions
  32.  */
  33. main (argc, argv)
  34. int argc;
  35. register char *argv[];
  36. {
  37.     /* so we can use the resource manager data merging functions */
  38.     XrmInitialize();
  39.  
  40.     /* parse command line first so we can open display, store any
  41.      * options in a database  */
  42.     parseOpenDisp (&argc, argv);
  43.  
  44.     /* get server defaults, program defaults, .Xdefaults, command 
  45.      * line, etc. and merge them */
  46.     mergeDatabases();
  47.  
  48.     /* extract values from database for use */
  49.     extractOpts ();
  50.  
  51.     /* load font, make pixmaps, set up arrays of windows */
  52.     initCalc ();
  53.  
  54.     /* get keyboard settings for interrupt, delete, etc. */
  55.     initTty ();
  56.  
  57.     /* make a standard cursor */
  58.     makeCursor ();
  59.  
  60.     /* set standard properties, create and map windows */
  61.     makeWindows (argc, argv);
  62.  
  63.     /* get events */
  64.     takeEvents ();
  65.  
  66.     /* bow out gracefully */
  67.     XCloseDisplay(display);
  68.     exit (1);
  69. }
  70.  
  71.  
  72. static char *getHomeDir( dest )
  73. char *dest;
  74. {
  75.     int uid;
  76.     extern char *getenv();
  77.     extern int getuid();
  78.     extern struct passwd *getpwuid();
  79.     struct passwd *pw;
  80.     register char *ptr;
  81.  
  82.     if ((ptr = getenv("HOME")) != NULL) {
  83.         (void) strcpy(dest, ptr);
  84.  
  85.     } else {
  86.         if ((ptr = getenv("USER")) != NULL) {
  87.             pw = getpwnam(ptr);
  88.         } else {
  89.             uid = getuid();
  90.             pw = getpwuid(uid);
  91.         }
  92.         if (pw) {
  93.             (void) strcpy(dest, pw->pw_dir);
  94.         } else {
  95.             *dest = '\0';
  96.         }
  97.     }
  98.     return dest;
  99. }
  100.  
  101.  
  102. /*
  103.  * Get program's and user's defaults
  104.  */
  105. mergeDatabases()
  106. {
  107.     XrmDatabase homeDB, serverDB, applicationDB;
  108.  
  109.     char filenamebuf[1024];
  110.     char *filename = &filenamebuf[0];
  111.     char *environment;
  112.     char *classname = "Basecalc";
  113.     char name[255];
  114.  
  115.     (void) strcpy(name, "/usr/lib/X11/app-defaults/");
  116.     (void) strcat(name, classname);
  117.     /* get application defaults file, if any */
  118.     applicationDB = XrmGetFileDatabase(name);
  119.     (void) XrmMergeDatabases(applicationDB, &rDB);
  120.  
  121.     /* MERGE server defaults, these are created by xrdb, loaded as a
  122.      * property of the root window when the server initializes, and
  123.      * loaded into the display structure on XOpenDisplay.  If not defined,
  124.          * use .Xdefaults  */
  125.     if (XResourceManagerString(display) != NULL) {
  126.         serverDB = XrmGetStringDatabase(XResourceManagerString(display));
  127.     } else {
  128.         /* Open .Xdefaults file and merge into existing data base */
  129.         (void) getHomeDir(filename);
  130.         (void) strcat(filename, "/.Xdefaults");
  131.  
  132.         serverDB = XrmGetFileDatabase(filename);
  133.     }
  134.     XrmMergeDatabases(serverDB, &rDB);
  135.  
  136.     /* Open XENVIRONMENT file, or if not defined, the ~/.Xdefaults,
  137.          * and merge into existing data base */
  138.     if ((environment = getenv("XENVIRONMENT")) == NULL) {
  139.         int len;
  140.         environment = getHomeDir(filename);
  141.         (void) strcat(environment, "/.Xdefaults-");
  142.         len = strlen(environment);
  143.         (void) gethostname(environment + len, 1024 - len);
  144.     }
  145.     homeDB = XrmGetFileDatabase(environment);
  146.     XrmMergeDatabases(homeDB, &rDB);
  147.  
  148.     /* command line takes precedence over everything */
  149.     XrmMergeDatabases(commandlineDB, &rDB);
  150. }
  151.  
  152.  
  153. /*
  154.  * Get command line options
  155.  */
  156. parseOpenDisp (argc, argv)
  157. int *argc;
  158. register char *argv[];
  159. {
  160.  
  161.     XrmValue value;
  162.     char *str_type[20];
  163.  
  164.     myDisplayName[0] = '\0';
  165.  
  166.     XrmParseCommand(&commandlineDB, opTable, opTableEntries,
  167.             argv[0], argc, argv);
  168.  
  169.     /*
  170.      * Check for any arguments left
  171.      */
  172.     if (*argc != 1) 
  173.         Usage();
  174.  
  175.     /* get display now, because we need it to get other databases*/
  176.     if (XrmGetResource(commandlineDB, "basecalc.display",
  177.             "Basecalc.Display", str_type, &value) == True) {
  178.         (void) strncpy(myDisplayName, value.addr, (int) value.size);
  179.     }
  180.  
  181.     /*
  182.      * Open display 
  183.      */
  184.     if (!(display = XOpenDisplay(myDisplayName))) {
  185.         (void) fprintf(stderr, "%s: Can't open display '%s'\n",
  186.                 argv[0], XDisplayName(myDisplayName));
  187.         exit(1);
  188.     }
  189.  
  190.     screen_number = DefaultScreen(display);
  191.     visual = DefaultVisual(display, screen_number);
  192.     colormap = DefaultColormap(display, screen_number);
  193. }
  194.  
  195.  
  196. extractOpts()
  197. {
  198.     char *str_type[20];
  199.     char buffer[20];
  200.     long flags;
  201.     XrmValue value;
  202.     int x, y, width, height;
  203.     XColor screen_def;
  204.  
  205.     /* get geometry (actually, this is currently ignored) */
  206.     if (XrmGetResource(rDB, "basecalc.geometry", "Basecalc.Geometry",
  207.             str_type, &value) == True) {
  208.         (void) strncpy(Geostr, value.addr, (int) value.size);
  209.     } else {
  210.         Geostr[0] = NULL;
  211.     }
  212.  
  213.     if (XrmGetResource(rDB, "basecalc.iconGeometry", "Basecalc.IconGeometry",
  214.             str_type, &value) == True) {
  215.         (void) strncpy(iconGeostr, value.addr, (int) value.size);
  216.     } else {
  217.         iconGeostr[0] = NULL;
  218.     }
  219.  
  220.     if (XrmGetResource(rDB, "basecalc.unsigned", "Basecalc.Unsigned",
  221.             str_type, &value) == True)
  222.         if (strncmp(value.addr, "False", (int) value.size) ==
  223.                 0) 
  224.             Unsigned = False;
  225.  
  226.  
  227.     if (XrmGetResource(rDB, "basecalc.base", "Basecalc.Base",
  228.             str_type, &value) == True) {
  229.         (void) strncpy(buffer, value.addr, (int) value.size);
  230.         buffer[value.size] = NULL;
  231.         Base = atoi(buffer);
  232.     } else 
  233.         Base = 10;
  234.  
  235.     if (XrmGetResource(rDB, "basecalc.foreground", "Basecalc.Foreground",
  236.             str_type, &value) == True) {
  237.         (void) strncpy(buffer, value.addr, (int) value.size);
  238.         if (XParseColor(display, colormap, buffer,  &screen_def) ==
  239.                 0)  {
  240.             (void) fprintf(stderr, "basecalc: fg color specification %s invalid",
  241.                     buffer);
  242.             foreground = BlackPixel(display, screen_number);
  243.         }  else {
  244.             if ((visual->class == StaticGray) || (visual->class ==
  245.                     GrayScale))
  246.  
  247.                 foreground = BlackPixel(display,
  248.                         screen_number);
  249.             else if (XAllocColor(display, colormap,
  250.                     &screen_def) == 0) {
  251.                 foreground = BlackPixel(display,
  252.                         screen_number);
  253.                 (void) fprintf(stderr, "basecalc: couldn't allocate color: %s.\n",
  254.                         buffer);
  255.             } else
  256.                 foreground = screen_def.pixel;
  257.         }
  258.     } else {
  259.         foreground = BlackPixel(display, screen_number);
  260.     }
  261.  
  262.     if (XrmGetResource(rDB, "basecalc.background", "Basecalc.Background",
  263.             str_type, &value) == True) {
  264.         (void) strncpy(buffer, value.addr, (int) value.size);
  265.         if (XParseColor(display, colormap, buffer,  &screen_def) ==
  266.                 0)  {
  267.             (void) fprintf(stderr, "basecalc: bg color specification %s invalid",
  268.                     buffer);
  269.             background = WhitePixel(display, screen_number);
  270.         }  else {
  271.             if ((visual->class == StaticGray) || (visual->class ==
  272.                     GrayScale))
  273.                 background = WhitePixel(display,
  274.                         screen_number);
  275.             else if (XAllocColor(display, colormap,
  276.                     &screen_def) == 0) {
  277.                 background = WhitePixel(display,
  278.                         screen_number);
  279.                 (void) fprintf(stderr, "basecalc: couldn't allocate color: %s.\n",
  280.                         buffer);
  281.             } else
  282.                 background = screen_def.pixel;
  283.         }
  284.     } else {
  285.         background = WhitePixel(display, screen_number);
  286.     }
  287.  
  288.     /* one last check to make sure the colors are different! */
  289.     if (background == foreground) {
  290.         background = WhitePixel(display, screen_number);
  291.         foreground = BlackPixel(display, screen_number);
  292.     }
  293.  
  294.  
  295.     /*  Could add a command line option for initial state:
  296.      *    iconOnly[0] = NULL; 
  297.      */
  298.  
  299.     /*
  300.      * Get window geometry info.
  301.      */
  302.     if (Geostr != NULL) {
  303.         flags = XParseGeometry(Geostr,  &x, &y, &width,
  304.                 &height);
  305.         if ((WidthValue | HeightValue) & flags)
  306.             Usage ();
  307.         if (XValue & flags) {
  308.             if (XNegative & flags)
  309.                 x = DisplayWidth(display, screen_number) +
  310.                                             x - sizehints.width;
  311.             sizehints.flags |= USPosition;
  312.             sizehints.x = x;
  313.         }
  314.         if (YValue & flags) {
  315.             if (YNegative & flags)
  316.                 y = DisplayHeight(display, screen_number) +
  317.                                             x - sizehints.width;
  318.             sizehints.flags |= USPosition;
  319.             sizehints.y = y;
  320.         }
  321.     }
  322.  
  323.     /*
  324.      * Get icon geometry info.
  325.      */
  326.     if (iconGeostr != NULL) {
  327.         iconGeostr[0] = '=';
  328.         flags = XParseGeometry(iconGeostr,  &x, &y, &width,
  329.                 &height);
  330.         if ((WidthValue | HeightValue) & flags)
  331.             Usage ();
  332.         if (XValue & flags) {
  333.             if (XNegative & flags)
  334.                 x = DisplayWidth(display, screen_number) +
  335.                                             x - iconsizehints.width;
  336.             iconsizehints.flags |= USPosition;
  337.             wmhints.flags |= IconPositionHint;
  338.             wmhints.icon_x = x;
  339.             iconsizehints.x = x;
  340.         }
  341.         if (YValue & flags) {
  342.             if (YNegative & flags)
  343.                 y = DisplayHeight(display, screen_number) +
  344.                                             x - iconsizehints.width;
  345.             iconsizehints.flags |= USPosition;
  346.             wmhints.flags |= IconPositionHint;
  347.             wmhints.icon_y = y;
  348.             iconsizehints.y = y;
  349.         }
  350.     }
  351. }
  352.  
  353.  
  354. /*
  355.  * Print message to stderr and exit
  356.  */
  357. Usage ()
  358. {
  359.     (void) fprintf (stderr, "%s: [-iconic] [-unsigned] [-hex|x|dec|oct|binary] [-display <display>] [-geometry <geometrystring>] [-iconGeometry <icongeometrystring>\n",
  360.             calcName ? calcName : "basecalc");
  361.     exit (1);
  362. }
  363.  
  364.  
  365. /*
  366.  * Make a pixmap.
  367.  */
  368. Pixmap 
  369. makePixmap(data, width, height)
  370. char *data;
  371. unsigned int width, height;
  372. {
  373.     Pixmap pid;
  374.  
  375.     pid = XCreatePixmapFromBitmapData(display, DefaultRootWindow(display),
  376.             data, width, height, foreground, background, DefaultDepth(display,
  377.             screen_number));
  378.     return(pid);
  379. }
  380.  
  381.  
  382. /*
  383.  * Initialize calculator options
  384.  */
  385. initCalc ()
  386. {
  387.     register int win;
  388.     register int found = -1;
  389.     XGCValues values;
  390.     extern char lgray_bits[];
  391.  
  392.     if ((theFont = XLoadQueryFont (display, myFontName)) ==
  393.             NULL) {
  394.         (void) fprintf(stderr, "basecalc: can't open font %s\n",
  395.                 myFontName);
  396.         exit(-1);
  397.     }
  398.  
  399.     /*
  400.      * Make the utility pixmaps.
  401.      */
  402.     grayPixmap = makePixmap(gray_bits, gray_width, gray_height);
  403.     lgrayPixmap = makePixmap(lgray_bits, lgray_width, lgray_height);
  404.  
  405.     /*
  406.      * Make the utility gc's.
  407.      */
  408.     values.font = theFont->fid;
  409.     values.foreground = foreground;
  410.     fgGC = XCreateGC(display, DefaultRootWindow(display),
  411.             GCForeground | GCFont, &values);
  412.     values.foreground = background;
  413.     values.function = GXcopy;
  414.     bgGC = XCreateGC(display, DefaultRootWindow(display),
  415.             GCForeground | GCFont | GCFunction, &values);
  416.  
  417.     /*
  418.      * Loop through buttons, setting disabled buttons
  419.      * to Color Light Gray. Also, find the window
  420.      * which corresponds to the starting dsplay base.
  421.      * Also add ascent to y position of text.
  422.      */
  423.     for (win = 1; win < NBUTTONS; win++) {
  424.         if (windata[win].type == WTYP_CONV &&  windata[win].value ==
  425.                 Base) {
  426.             found = win;
  427.         } else if (windata[win].type == WTYP_DIG &&  windata[win].value >=
  428.                 Base) {
  429.             windata[win].color = disabledColor;
  430.         } else if (windata[win].type == WTYP_SPEC && 
  431.                 windata[win].value == OPR_UNS) {
  432.             if (Unsigned)
  433.                 windata[win].text = "U";
  434.             else
  435.                 windata[win].text = "S";
  436.             windata[win].color = pressedColor;
  437.         } else
  438.             windata[win].color = unpressedColor;
  439.         windata[win].y += theFont->max_bounds.ascent;
  440.     }
  441.     windata[0].y += theFont->max_bounds.ascent;
  442.     if (found >= 0) {
  443.         Winbase = found;
  444.         windata[found].color = pressedColor;
  445.     } else {
  446.         (void) fprintf(stderr, "basecalc: can't use base %d\n",
  447.                 Base);
  448.         exit(-1);
  449.     }
  450.     windata[0].color = displayColor;
  451. }
  452.  
  453.  
  454. /*
  455.  * Get the user's tty special chars
  456.  * This is currently 4.2 specific.
  457.  */
  458. initTty ()
  459. {
  460.     register struct KeyCode *KeyCodePtr;
  461.     register int fd;
  462. #ifdef SysV
  463.     struct termio term;
  464. #else
  465.     struct sgttyb tty;
  466.     struct tchars tchars;
  467.     struct ltchars ltchars;
  468. #endif SysV
  469.  
  470.     if (!isatty(0)) {
  471.         if ((fd = open ("/dev/console", 0)) < 0)
  472.             return;
  473.     } else
  474.         fd = 0;
  475. #ifdef SysV
  476.     (void) ioctl  (fd, TCGETA,   &term);
  477. #else
  478.     (void) ioctl  (fd, TIOCGETP, &tty);
  479.     (void) ioctl  (fd, TIOCGETC, &tchars);
  480.     (void) ioctl  (fd, TIOCGLTC, <chars);
  481. #endif SysV
  482.     if (fd)
  483.         (void) close (fd);
  484.  
  485.     KeyCodePtr = KeyCodes;
  486. #ifdef SysV
  487.     KeyCodePtr++->kc_char = term.c_cc[VERASE];
  488.     KeyCodePtr++;
  489.     KeyCodePtr++->kc_char = term.c_cc[VKILL];
  490.     KeyCodePtr->kc_char = term.c_cc[VINTR];
  491.     QuitChar = term.c_cc[VQUIT];
  492. #else
  493.     KeyCodePtr++->kc_char = tty.sg_erase;
  494.     KeyCodePtr++->kc_char = ltchars.t_werasc;
  495.     KeyCodePtr++->kc_char = tty.sg_kill;
  496.     KeyCodePtr->kc_char = tchars.t_intrc;
  497.     QuitChar = tchars.t_quitc;
  498. #endif SysV
  499. }
  500.  
  501.  
  502. /*
  503.  * Make the cursor
  504.  */
  505. makeCursor ()
  506. {
  507.     theCursor = XCreateFontCursor (display, XC_hand1);
  508. }
  509.  
  510.  
  511. /*
  512.  * Set up the selection of events
  513.  */
  514. selectEvents ()
  515. {
  516.     int win;
  517.  
  518.     XSelectInput (display, calcWin, KeyPressMask | KeyReleaseMask);
  519.     XSelectInput (display, dispWin, ExposureMask);
  520.     for (win = 1; win < NBUTTONS; win++)
  521.         XSelectInput (display, Buttons[win].self,  ExposureMask
  522.                 |             ButtonPressMask | ButtonReleaseMask
  523.                 |             EnterWindowMask | LeaveWindowMask);
  524. }
  525.  
  526.  
  527. /*
  528.  * Get events and process them
  529.  */
  530. takeEvents ()
  531. {
  532.     XEvent Event;
  533.     register int win;
  534.     register int Pressed = False;
  535.     register int InWindow = False;
  536.     char buffer[10];
  537.     register char *KeyChars = buffer;
  538.     register int WasKeyDown = False;
  539.     unsigned i, nbytes;
  540.     int old_color;
  541.  
  542.     while (1) {
  543.         if (!WasKeyDown)
  544.             XNextEvent (display, &Event);
  545.         else
  546.             Event.type = KeyRelease;
  547.  
  548.         /*
  549.          * Map keyboard events
  550.          * to Window Events
  551.          */
  552.         if (Event.type == KeyPress || Event.type == KeyRelease) {
  553.             nbytes = XLookupString (&Event, buffer,
  554.                     sizeof(buffer), NULL, NULL);
  555.             if (Event.type == KeyPress) {
  556.                 Event.type = ButtonPress;
  557.                 WasKeyDown = 1;
  558.             } else {
  559.                 for (i = 0; i < 60000; i++)
  560.                     ;
  561.                 Event.type = ButtonRelease;
  562.             }
  563.             if ((Event.xbutton.window =  keyToWin (KeyChars,
  564.                     nbytes)) == None) {
  565.                 WasKeyDown = 0;
  566.                 continue;
  567.             }
  568.         }
  569.         for (win = 0; win < NBUTTONS; win++)
  570.             if (Buttons[win].self == Event.xbutton.window)
  571.                 break;
  572.         switch (Event.type) {
  573.         case EnterNotify:
  574.             old_color = windata[win].color;
  575.             break;
  576.         case ButtonPress:
  577.             if (windata[win].color == disabledColor)
  578.                 break;
  579.             Pressed = win;
  580.             if (!WasKeyDown)
  581.                 InWindow = True;
  582.             windata[win].color = pressedColor;
  583.             drawButton (win, 0);
  584.             break;
  585.         case LeaveNotify:
  586.             if (Pressed != win)
  587.                 break;
  588.             InWindow = False;
  589.             windata[win].color = old_color;
  590.             drawButton (win, 0);
  591.             break;
  592.             /*
  593.         case EnterNotify:
  594.             if (Pressed != win)
  595.                 break;
  596.             InWindow = True;
  597.             windata[win].color = pressedColor;
  598.             drawButton (win, 0);
  599.             break;
  600.         */
  601.         case ButtonRelease:
  602.             if (windata[win].color == disabledColor ||
  603.                                     Pressed != win) {
  604.                 WasKeyDown = False;
  605.                 break;
  606.             }
  607.             Pressed = False;
  608.             windata[win].color = unpressedColor;
  609.             if (WasKeyDown || InWindow)
  610.                 winPressed (win);
  611.             WasKeyDown = False;
  612.             InWindow = False;
  613.             drawButton (win, 0);
  614.             break;
  615.         case Expose:
  616.             drawButton (win, 1);
  617.             break;
  618.         }
  619.         XFlush(display);
  620.     }
  621. }
  622.  
  623.  
  624. /*
  625.      * Make the calculator windows
  626.      */
  627. makeWindows (argc, argv)
  628. int argc;
  629. char *argv[];
  630. {
  631.     register int i;
  632.     XSetWindowAttributes attributes;
  633.     char *window_name = "Programmer's Calculator";
  634.     char *icon_name = "basecalc";
  635.  
  636.     /*
  637.      * Define the border and background for the main window.
  638.      * - Black border and a patterned background.
  639.      */
  640.     attributes.border_pixel = foreground;
  641.     attributes.background_pixmap = grayPixmap;
  642.     /*
  643.      * Create the main window (calculator frame) as a 
  644.      * child of the Root Window
  645.      */
  646.     attributes.cursor = theCursor;
  647.     calcWin = XCreateWindow(display, DefaultRootWindow(display),
  648.             sizehints.x, sizehints.y, sizehints.width, sizehints.height,
  649.             1, DefaultDepth(display, screen_number), InputOutput,
  650.             CopyFromParent, CWBorderPixel | CWBackPixmap | CWCursor,
  651.             &attributes);
  652. #ifdef X11R3
  653.     XSetStandardProperties (display, calcWin, window_name,
  654.             icon_name, NULL, argv, argc, &sizehints);
  655. #endif
  656.  
  657.     /*
  658.      * Create the icon window and associate it with the calculator
  659.      */
  660.     iconPixmap = makePixmap(icon_bits, icon_width, icon_height);
  661.     attributes.border_pixel = foreground;
  662.     attributes.background_pixmap = iconPixmap;
  663.     iconWin = XCreateWindow(display, DefaultRootWindow(display),
  664.             iconsizehints.x, iconsizehints.y, iconsizehints.width,
  665.             iconsizehints.height, 1, DefaultDepth(display, screen_number),
  666.             InputOutput, CopyFromParent, CWBorderPixel | CWBackPixmap,
  667.             &attributes);
  668.     wmhints.icon_window = iconWin;
  669.     wmhints.initial_state = iconOnly ? IconicState : NormalState;
  670.     wmhints.input = True;
  671.     wmhints.flags |= InputHint | StateHint | IconWindowHint;
  672. #ifdef X11R3
  673.     XSetWMHints(display, calcWin, &wmhints);
  674. #else
  675.     {
  676.         XClassHint class_hints;
  677.  
  678.         /* format of the window name and icon name 
  679.      * arguments has changed in R4 */
  680.         XTextProperty windowName, iconName;
  681.  
  682.         /* These calls store window_name and icon_name into
  683.      * XTextProperty structures and set their other 
  684.      * fields properly. */
  685.         if (XStringListToTextProperty(&window_name, 1,
  686.                 &windowName) == 0) {
  687.             (void) fprintf( stderr, "%s: structure allocation for windowName failed.\n",
  688.                                     argv[0]);
  689.             exit(-1);
  690.         }
  691.  
  692.         if (XStringListToTextProperty(&icon_name, 1, &iconName) ==
  693.                 0) {
  694.             (void) fprintf( stderr, "%s: structure allocation for iconName failed.\n",
  695.                                     argv[0]);
  696.             exit(-1);
  697.         }
  698.  
  699.         class_hints.res_name = argv[0];
  700.         class_hints.res_class = "Basicwin";
  701.  
  702.         XSetWMProperties(display, calcWin, &windowName,
  703.                 &iconName,  argv, argc, &sizehints, &wmhints,
  704.                             &class_hints);
  705.     }
  706. #endif
  707.  
  708.     /*
  709.      * Create the buttons as subwindows. 
  710.      */
  711.     attributes.background_pixmap = lgrayPixmap;
  712.     attributes.border_pixel = foreground;
  713.     for (i = 0; i < NBUTTONS; i++)
  714.         switch (windata[i].color) {
  715.         case WHITE:
  716.             Buttons[i].self = XCreateSimpleWindow(display,
  717.                     calcWin, Buttons[i].x, Buttons[i].y,
  718.                     Buttons[i].width, Buttons[i].height,
  719.                     1, foreground, background);
  720.             break;
  721.         case BLACK:
  722.             Buttons[i].self = XCreateSimpleWindow(display,
  723.                     calcWin, Buttons[i].x, Buttons[i].y,
  724.                     Buttons[i].width, Buttons[i].height,
  725.                     1, background, foreground);
  726.             break;
  727.         case LIGHTGRAY:
  728.             Buttons[i].self = XCreateWindow(display,
  729.                     calcWin, Buttons[i].x, Buttons[i].y,
  730.                     Buttons[i].width, Buttons[i].height,
  731.                     1, CopyFromParent, InputOutput, CopyFromParent,
  732.                                     CWBorderPixel | CWBackPixmap,
  733.                     &attributes);
  734.             break;
  735.         }
  736.  
  737.     /*
  738.      * The display window is distinguished
  739.      */
  740.     dispWin = Buttons[0].self;
  741.  
  742.     /*
  743.      * Initialize event catching.
  744.      */
  745.     selectEvents ();
  746.  
  747.     /*
  748.      * Map the calculator and sub-windows.
  749.      */
  750.     XMapSubwindows(display, calcWin);
  751.     XMapWindow(display, calcWin);
  752. }
  753.  
  754.  
  755. /*
  756.  * Draw a single button with its text
  757.  */
  758. drawButton (win, exposeEvent)
  759. register int win;
  760. {
  761.     register char *string;
  762.     register int x, y;
  763.     struct windata *winp;
  764.     char *measure;
  765.     XSetWindowAttributes attributes;
  766.     unsigned long valuemask;
  767.     GC gc;
  768.  
  769.     winp = &windata[win];
  770.     x = winp->x;
  771.     y = winp->y;
  772.     string = winp->text;
  773.  
  774.     switch (windata[win].color) {
  775.     case WHITE:
  776.         gc = fgGC;
  777.         attributes.background_pixel = background;
  778.         attributes.border_pixel = foreground;
  779.         valuemask = CWBackPixel | CWBorderPixel;
  780.         break;
  781.     case BLACK:
  782.         gc = bgGC;
  783.         attributes.background_pixel = foreground;
  784.         attributes.border_pixel = background;
  785.         valuemask = CWBackPixel | CWBorderPixel;
  786.         break;
  787.     case LIGHTGRAY:
  788.         gc = bgGC;
  789.         attributes.background_pixmap = lgrayPixmap;
  790.         attributes.border_pixel = foreground;
  791.         valuemask = CWBackPixmap | CWBorderPixel;
  792.         break;
  793.     }
  794.     if (!exposeEvent) {
  795.         XChangeWindowAttributes(display, Buttons[win].self,
  796.                 valuemask, &attributes);
  797.         XClearWindow(display, Buttons[win].self);
  798.     }
  799.     XDrawString (display, Buttons[win].self, gc, x, y, string,
  800.             strlen (string));
  801.     if (win == 0) {
  802.         switch (Base) {
  803.         case 10:
  804.         case 8:
  805.             measure = Octmeasure;
  806.             break;
  807.         default:
  808.         case 16:
  809.         case 2:
  810.             measure = Hexmeasure;
  811.             break;
  812.         }
  813.         XDrawString (display, dispWin, gc, 7, 6, measure,
  814.                 31);
  815.     }
  816. }
  817.  
  818.  
  819. static unsigned int LastDisp = 1;
  820. /*
  821.  * Do the operation corresponding to a key press
  822.  */
  823. winPressed (win)
  824. {
  825.     register int type;
  826.  
  827.     type = windata[win].type;
  828.     switch (type) {
  829.     case WTYP_CONV:
  830.         convButton (win);
  831.         displayVal (LastDisp == 1 ? Value : Accum);
  832.         break;
  833.     case WTYP_DIG:
  834.         digitButton (win);
  835.         displayVal (Value);
  836.         LastDisp = 1;
  837.         break;
  838.     case WTYP_OPER:
  839.         if (operButton (win) == 0) {
  840.             displayVal (Accum);
  841.             LastDisp = 2;
  842.         } else {
  843.             displayVal (Value);
  844.             LastDisp = 1;
  845.         }
  846.         break;
  847.     case WTYP_SPEC:
  848.         specButton (win);
  849.         displayVal (LastDisp == 1 ? Value : Accum);
  850.         LastDisp = 1;
  851.     }
  852. }
  853.  
  854.  
  855. /*
  856.  * Handle a conversion button
  857.  */
  858. convButton (win)
  859. {
  860.     register int i, NewBase, Diff, Digit;
  861.     register int HiBase, LowBase;
  862.  
  863.     NewBase = windata[win].value;
  864.     windata[Winbase].color = unpressedColor;
  865.     drawButton (Winbase, 0);
  866.     windata[win].color = pressedColor;
  867.  
  868.     Diff = NewBase - Base;
  869.     if (Diff) {
  870.         if (NewBase > Base) {
  871.             LowBase = Base;
  872.             HiBase = NewBase;
  873.         } else {
  874.             LowBase = NewBase;
  875.             HiBase = Base;
  876.         }
  877.         for (i = 1; i < NBUTTONS; i++) {
  878.             if (windata[i].type == WTYP_DIG) {
  879.                 Digit = windata[i].value;
  880.                 if (Digit >= LowBase && Digit <
  881.                         HiBase) {
  882.                     if (Diff < 0)
  883.                         windata[i].color =
  884.                                 disabledColor;
  885.                     else
  886.                         windata[i].color =
  887.                                 unpressedColor;
  888.                     drawButton (i, 0);
  889.                 }
  890.             }
  891.         }
  892.     }
  893.     Winbase = win;
  894.     Base = NewBase;
  895. }
  896.  
  897.  
  898. /*
  899.  * Handle a digit button
  900.  */
  901. digitButton (win)
  902. {
  903.     register unsigned long Temp;
  904.  
  905.     if (CalcReset) {
  906.         CalcReset = 0;
  907.         Accum = 0;
  908.         Value = 0;
  909.         LastOpt = OPR_ADD;
  910.     }
  911.     Digit = windata[win].value;
  912.     if (Unsigned)
  913.         Temp = (unsigned)Value * (unsigned)Base + Digit;
  914.     else
  915.         Temp = Value * Base + Digit;
  916.     if ((unsigned)Temp / Base != (unsigned)Value) {    /* OverfLow? */
  917.         /*
  918.          * Flash the display since the character didn't register
  919.          */
  920.         windata[0].color =  (displayColor == WHITE) ?
  921.                 BLACK : WHITE;
  922.         drawButton (0, 0);
  923.         XFlush(display);
  924.         Delay ();
  925.         windata[0].color = displayColor;
  926.         drawButton (0, 0);
  927.         return;
  928.     }
  929.     Value = Temp;
  930. }
  931.  
  932.  
  933. /*
  934.  * Handle a special operator
  935.  */
  936. specButton (win)
  937. {
  938.     register int oper;
  939.  
  940.     oper = windata[win].value;
  941.  
  942.     switch (oper) {
  943.     case OPR_CLRD:
  944.         if (LastOpt == OPR_ASGN)
  945.             break;
  946.         Value = (unsigned)Value / Base;
  947.         break;
  948.     case OPR_CLRE:
  949.         Value = 0;
  950.         break;
  951.     case OPR_CLRA:
  952.         Accum = 0;
  953.         Value = 0;
  954.         LastOpt = OPR_ADD;
  955.         break;
  956.     case OPR_UNS:
  957.         Unsigned = !Unsigned;
  958.         windata[win].text = Unsigned ? "U" : "S";
  959.         windata[win].color = pressedColor;
  960.         drawButton (win, 0);
  961.         break;
  962.     }
  963. }
  964.  
  965.  
  966. /*
  967.  * Handle an operator
  968.  */
  969. operButton (win)
  970. {
  971.     register int oper;
  972.  
  973.     oper = LastOpt;
  974.     LastOpt = windata[win].value;
  975.  
  976.     CalcReset = 0;
  977.     switch (LastOpt) {
  978.     case OPR_NEG:
  979.         Value = -Value;
  980.         if ((LastOpt = oper) == OPR_ASGN)
  981.             Accum = Value;
  982.         return 1;
  983.     case OPR_NOT:
  984.         Value = ~Value;
  985.         if ((LastOpt = oper) == OPR_ASGN)
  986.             Accum = Value;
  987.         return 1;
  988.     }
  989.  
  990.     switch (oper) {
  991.     case OPR_ADD:
  992.         if (Unsigned)
  993.             Accum = (unsigned)Accum + (unsigned)Value;
  994.         else
  995.             Accum += Value;
  996.         break;
  997.     case OPR_SUB:
  998.         if (Unsigned)
  999.             Accum = (unsigned)Accum - (unsigned)Value;
  1000.         else
  1001.             Accum -= Value;
  1002.         break;
  1003.     case OPR_MUL:
  1004.         if (Unsigned)
  1005.             Accum = (unsigned)Accum * (unsigned)Value;
  1006.         else
  1007.             Accum *= Value;
  1008.         break;
  1009.     case OPR_DIV:
  1010.         if (Value == 0)
  1011.             break;
  1012.         if (Unsigned)
  1013.             Accum = (unsigned)Accum / (unsigned)Value;
  1014.         else
  1015.             Accum /= Value;
  1016.         break;
  1017.     case OPR_MOD:
  1018.         if (Value == 0)
  1019.             break;
  1020.         if (Unsigned)
  1021.             Accum = (unsigned)Accum % (unsigned)Value;
  1022.         else
  1023.             Accum %= Value;
  1024.         break;
  1025.     case OPR_OR:
  1026.         Accum |= Value;
  1027.         break;
  1028.     case OPR_AND:
  1029.         Accum &= Value;
  1030.         break;
  1031.     case OPR_SHR:
  1032.         if (Unsigned)
  1033.             Accum = (unsigned)Accum >> (unsigned)Value;
  1034.         else
  1035.             Accum >>= Value;
  1036.         break;
  1037.     case OPR_SHL:
  1038.         if (Unsigned)
  1039.             Accum = (unsigned)Accum << (unsigned)Value;
  1040.         else
  1041.             Accum <<= Value;
  1042.         break;
  1043.     case OPR_XOR:
  1044.         Accum ^= Value;
  1045.         break;
  1046.     case OPR_ASGN:
  1047.         break;
  1048.     }
  1049.     if (LastOpt == OPR_ASGN) {
  1050.         Value = Accum;
  1051.         CalcReset = 1;
  1052.         return 1;
  1053.     }
  1054.     Value = 0;
  1055.     return 0;
  1056. }
  1057.  
  1058.  
  1059. /*
  1060.  * Display a number in the display window
  1061.  */
  1062. displayVal (number)
  1063. register long number;
  1064. {
  1065.     register char *Fmt;
  1066.     register char *cp;
  1067.     register int i;
  1068.  
  1069.     switch (Base) {
  1070.     case 16:
  1071.         Fmt = "%32x";
  1072.         break;
  1073.     case 10:
  1074.         Fmt = "%32d";
  1075.         break;
  1076.     case 8:
  1077.         Fmt = "%32o";
  1078.         break;
  1079.     case 2:
  1080.         Fmt = "%032b";
  1081.         break;
  1082.     }
  1083.     cp = windata[0].text;
  1084.     for (i = 32; --i >= 0; )
  1085.         *cp++ = ' ';
  1086.     *cp = '\0';
  1087.     Sprintf (windata[0].text, Fmt, number);
  1088.     drawButton (0, 0);
  1089. }
  1090.  
  1091.  
  1092. /*
  1093.  * Translate a key code to a corresponding window
  1094.  */
  1095. keyToWin (str, n)
  1096. register char *str;
  1097. register unsigned n;
  1098. {
  1099.     register int value = -1;
  1100.     register struct KeyCode *KeyCodePtr;
  1101.     register char ch;
  1102.     register int i;
  1103.  
  1104.     if (n > (unsigned) 0) {
  1105.         ch = *str;
  1106.         if (islower(ch) && isxdigit(ch))
  1107.             value = 10 + ch - 'a';
  1108.         else if (isdigit(ch))
  1109.             value = ch - '0';
  1110.         if (value >= 0) {
  1111.             for (i = 1; i < NBUTTONS; i++)
  1112.                 if (windata[i].type == WTYP_DIG &&
  1113.                                             windata[i].value ==
  1114.                         value)
  1115.                     return Buttons[i].self;
  1116.         } else {
  1117.             /*
  1118.              * Do some translations - these should be driven
  1119.              * from the user's terminal erase, kill, etc
  1120.              */
  1121.             switch (ch) {
  1122.             case 'U':
  1123.                 if (Unsigned)
  1124.                     return - 1;
  1125.                 str = "S";
  1126.                 n = 1;
  1127.                 break;
  1128.             case 'S':
  1129.                 if (!Unsigned)
  1130.                     return - 1;
  1131.                 str = "U";
  1132.                 n = 1;
  1133.                 break;
  1134.             case '\r':
  1135.             case '\n':
  1136.                 str = "=";
  1137.                 n = 1;
  1138.                 break;
  1139.             default:
  1140.                 if (ch == QuitChar) {
  1141.                     XCloseDisplay(display);
  1142.                     exit (1);
  1143.                 }
  1144.                 KeyCodePtr = KeyCodes;
  1145.                 while ((n = KeyCodePtr->kc_len) >
  1146.                         (unsigned) 0) {
  1147.                     if (ch == KeyCodePtr->kc_char) {
  1148.                         str = KeyCodePtr->kc_func;
  1149.                         break;
  1150.                     }
  1151.                     KeyCodePtr++;
  1152.                 }
  1153.                 if (n == 0)
  1154.                     n = 1;
  1155.                 break;
  1156.             }
  1157.             for (i = 1; i < NBUTTONS; i++) {
  1158.                 if (windata[i].type != WTYP_DIG &&
  1159.                                             strncmp (windata[i].text,
  1160.                         str, (int) n) == 0)
  1161.                     return Buttons[i].self;
  1162.             }
  1163.         }
  1164.     }
  1165.     return None;
  1166. }
  1167.  
  1168.  
  1169. /*
  1170.  * Specialized version of C Library sprintf.
  1171.  *
  1172.  * %u %d %o %x %b (binary) are recognized.
  1173.  * %0W... - where 0 means pad with zeros otherwise blanks
  1174.  *       - if W, the minimum field width is larger than
  1175.  *      - the number
  1176.  */
  1177. Sprintf(cp, fmt, x1)
  1178. register char *cp;
  1179. register char *fmt;
  1180. unsigned x1;
  1181. {
  1182.     register int c, b, sign;
  1183.     register char *s;
  1184.     register unsigned short fw;
  1185.     char *printInBase();
  1186.     char pad;
  1187.  
  1188.     while ((c = *fmt++) != '%') {
  1189.         if (c == '\0') {
  1190.             *cp = c;
  1191.             return;   /* to displayVal */
  1192.         }
  1193.         *cp++ = c;
  1194.     }
  1195.     c = *fmt++;
  1196.     if (c == '0') {
  1197.         pad = '0';
  1198.         c = *fmt++;
  1199.     } else
  1200.         pad = ' ';
  1201.  
  1202.     /*
  1203.      * Calculate minimum field width
  1204.      */
  1205.     fw = 0;
  1206.     while (c >= '0' && c <= '9') {
  1207.         fw = fw * 10 + (c - '0');
  1208.         c = *fmt++;
  1209.     }
  1210.     sign = 0;
  1211.     switch (c) {
  1212.     case 'x':
  1213.         b = 16;
  1214.         break;
  1215.     case 'd':
  1216.         if (!Unsigned)
  1217.             sign = 1;
  1218.         /*  falls through into 'u' case */
  1219.     case 'u':
  1220.         b = 10;
  1221.         break;
  1222.     case 'o':
  1223.         b = 8;
  1224.         break;
  1225.     case 'b':
  1226.         b = 2;
  1227.         break;
  1228.     default:
  1229.         /*
  1230.          * Unknown format
  1231.          */
  1232.         b = 0;
  1233.         break;
  1234.     }
  1235.     if (b)
  1236.         cp = printInBase (cp, x1, b, fw, pad, sign);
  1237. }
  1238.  
  1239.  
  1240. /*
  1241.  * Print a number n in base b into string cp.
  1242.  * Minimum field width = fw, pad character = pad
  1243.  */
  1244. char *
  1245. printInBase (cp, n, b, fw, pad, sign)
  1246. register char *cp;
  1247. register long n;
  1248. register b;
  1249. register int fw, pad;
  1250. {
  1251.     register i, nd, c;
  1252.     int flag;
  1253.     int plmax;
  1254.     char d[33];
  1255.  
  1256.     c = 1;
  1257.     if (sign)
  1258.         flag = n < 0;
  1259.     else
  1260.         flag = 0;
  1261.     if (flag)
  1262.         n = (-n);
  1263.     if (b == 2)
  1264.         plmax = 32;
  1265.     else if (b == 8)
  1266.         plmax = 11;
  1267.     else if (b == 10)
  1268.         plmax = 10;
  1269.     else if (b == 16)
  1270.         plmax = 8;
  1271.     if (b == 10) {
  1272.         if (flag == 0)
  1273.             sign = 0;
  1274.         flag = 0;
  1275.     }
  1276.     for (i = 0; i < plmax; i++) {
  1277.         if (flag == 0)
  1278.             nd = (unsigned)n % b;
  1279.         else
  1280.             nd = n % b;
  1281.         if (flag) {
  1282.             nd = (b - 1) - nd + c;
  1283.             if (nd >= b) {
  1284.                 nd -= b;
  1285.                 c = 1;
  1286.             } else
  1287.                 c = 0;
  1288.         }
  1289.         d[i] = nd;
  1290.         if (flag == 0)
  1291.             n = (unsigned)n / b;
  1292.         else
  1293.             n = n / b;
  1294.         if ((n == 0) && (flag == 0))
  1295.             break;
  1296.     }
  1297.     if (i == plmax)
  1298.         i--;
  1299.     if (sign) {
  1300.         fw--;
  1301.         if (pad == '0')
  1302.             *cp++ = '-';
  1303.     }
  1304.     if (fw > i + 1) {
  1305.         for (fw -= i + 1; fw > 0; fw--)
  1306.             *cp++ = pad;
  1307.     }
  1308.     if (sign && pad != '0')
  1309.         *cp++ = '-';
  1310.     for (; i >= 0; i--)
  1311.         *cp++ = "0123456789ABCDEF"[d[i]];
  1312.     *cp = '\0';
  1313.     return cp;
  1314. }
  1315.  
  1316.  
  1317. /*
  1318.  * Delay a little while
  1319.  */
  1320. Delay ()
  1321. {
  1322.     long tic;
  1323.  
  1324.     for (tic = 0; tic < 50000; tic++)
  1325.         ;
  1326. }
  1327.  
  1328.  
  1329.