Xlib Programming Manual (O'Reilly & Associates, Inc.) |
The X Programmer's Calculator (basecalc) was described in Chapter 14, "A Complete Application."
This appendix presents the complete code for basecalc, including the following files and routines that were not shown in Chapter 14, "A Complete Application."
The complete basecalc.h file
/* Window flags */
#define WTYP_OPER 0x01 /* Operator, +, -, =, etc */
#define WTYP_DIG 0x02 /* Digit 0-9, A-F */
#define WTYP_DISP 0x04 /* Display Window */
#define WTYP_CONV 0x08 /* Converter -- hex, oct, dec, bin */
#define WTYP_SPEC 0x10 /* Special, CE, CA, CD */
/* Operators */
#define OPR_ADD 1
#define OPR_SUB 2
#define OPR_MUL 3
#define OPR_DIV 4
#define OPR_MOD 5
#define OPR_OR 6
#define OPR_AND 7
#define OPR_XOR 8
#define OPR_SHL 9
#define OPR_SHR 10
#define OPR_CLRE 11
#define OPR_CLRD 12
#define OPR_CLRA 13
#define OPR_ASGN 14
#define OPR_NEG 15
#define OPR_NOT 16
#define OPR_UNS 17
/* Colors */
#define WHITE 0
#define BLACK 1
#define DARKGRAY 2
#define LIGHTGRAY 3
static XrmDatabase commandlineDB, rDB;
int pressedColor = WHITE;
int unpressedColor = BLACK;
int disabledColor = LIGHTGRAY;
int displayColor = WHITE;
char myDisplayName[256];
char *myFontName = "8x13";
char *calcName;
Display *display;
int screen_num;
Visual *visual;
Colormap colormap;
XFontStruct *theFont;
Cursor theCursor;
Window calcWin;
Window iconWin;
Window dispWin;
Pixmap lgrayPixmap;
Pixmap grayPixmap;
Pixmap iconPixmap;
int foreground;
int background;
GC fgGC;
GC bgGC;
/* Calculator variables */
int Base = 10; /* Default base, updated to command line
* or .Xdefaults */
int Winbase; /* windata offset for current base, set
* in InitCalc, used in ConvButton */
int Digit = 0;
long Value = 0; /* Current pressed value */
long Accum = 0; /* Current results */
Bool Unsigned = True; /* Default for U/S key */
int LastOpt = OPR_ADD; /* Initial previous operator */
int CalcReset = 0;
char Hexmeasure[] = " . . . . . . . ";
char Octmeasure[] = " . . . . . . . . . . ";
/* Startup options */
Bool iconOnly = False;
char Geostr[20];
char iconGeostr[20];
/* Command line options table; only resources are entered here...
* there is a pass over the remaining options after XrmParseCommand
* is let loose; we don't do anything with many of these resources,
* but the program is ready for expansion */
#define GEOMETRY "*geometry"
#define ICONGEOMETRY "*iconGeometry"
#define UNSIGNED "*unsigned"
#define BASE "*base"
#define ICONSTARTUP "*iconStartup"
static int opTableEntries = 25;
static XrmOptionDescRec opTable[] = {
{"-unsigned", UNSIGNED, XrmoptionNoArg, (caddr_t) "off"},
{"-x", BASE, XrmoptionNoArg, (caddr_t) "16"},
{"-hex", BASE, XrmoptionNoArg, (caddr_t) "16"},
{"-dec", BASE, XrmoptionNoArg, (caddr_t) "10"},
{"-oct", BASE, XrmoptionNoArg, (caddr_t) "8"},
{"-binary", BASE, XrmoptionNoArg, (caddr_t) "2"},
{"-geometry", GEOMETRY, XrmoptionSepArg, (caddr_t) NULL},
{"-iconGeometry", ICONGEOMETRY, XrmoptionSepArg, (caddr_t) NULL},
{"-iconic", ICONSTARTUP, XrmoptionNoArg, (caddr_t) "on"},
{"-background", "*background", XrmoptionSepArg, (caddr_t) NULL},
{"-bg", "*background", XrmoptionSepArg, (caddr_t) NULL},
{"-fg", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
{"-foreground", "*foreground", XrmoptionSepArg, (caddr_t) NULL},
{"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL},
{"-display", ".display", XrmoptionSepArg, (caddr_t) NULL},
/* Remainder not currently supported: */
{"-bd", "*borderColor", XrmoptionSepArg, (caddr_t) NULL},
{"-bordercolor", "*borderColor", XrmoptionSepArg, (caddr_t) NULL},
{"-borderwidth", ".borderWidth", XrmoptionSepArg, (caddr_t) NULL},
{"-bw", ".borderWidth", XrmoptionSepArg, (caddr_t) NULL},
{"-fn", "*font", XrmoptionSepArg, (caddr_t) NULL},
{"-font", "*font", XrmoptionSepArg, (caddr_t) NULL},
{"-name", ".name", XrmoptionSepArg, (caddr_t) NULL},
{"-title", ".title", XrmoptionSepArg, (caddr_t) NULL},
};
/* Keyboard equivalents */
struct KeyCode {
int kc_char;
char *kc_func;
int kc_len;
} KeyCodes[] = {
{ CERASE, "CD", 2 },
#ifdef SYSV
{ 027, "CE", 2 },
#else
{ CWERASE, "CE", 2 },
#endif SYSV
{ CKILL, "CE", 2 },
{ CINTR, "CA", 2 },
{ 0, 0, 0 },
};
char QuitChar = CQUIT;
#include "bitmaps/xcalc.icon"
#include "bitmaps/lgray"
#include "bitmaps/gray"
/* Placement variables */
XSizeHints sizehints = {
PMinSize | PMaxSize | PPosition | PSize | USSize,
400, 100, /* x, y */
300, 139, /* Width, height */
300, 139, /* min_width and min_height */
300, 139, /* max_width and max_height */
0, 0, /* Width and height increments, not set */
0, 0, 0, 0, /* Aspect ratio, not set */
};
XSizeHints iconsizehints = {
PMinSize | PMaxSize | PPosition | PSize,
150, 2,
icon_width, icon_height,
icon_width, icon_height,
icon_width, icon_height,
0, 0,
0, 0, 0, 0,
};
XWMHints wmhints = {
InputHint | StateHint | IconWindowHint,
True, /* Input model */
NormalState, /* Starts up in normal state */
0, /* Icon pixmap -- set later */
0, /* Icon window -- created later */
150, 2, /* Icon position of icon */
0, /* Icon mask pixmap -- not used */
};
/* Configuration of subwindows */
typedef struct _OpaqueFrame {
Window self; /* Window ID, filled in later */
int x, y; /* Where to create the window */
unsigned int width, height; /* Width and height */
} OpaqueFrame;
#define NBUTTONS 38
OpaqueFrame Buttons[NBUTTONS] = {
{ 0, 3, 5, 292, 18}, /* Display area */
{ 0, 10, 35, 19, 18}, /* c d e f */
{ 0, 37, 35, 19, 18},
{ 0, 63, 35, 19, 18},
{ 0, 91, 35, 19, 18},
{ 0, 10, 60, 19, 18}, /* 8 9 a b */
{ 0, 37, 60, 19, 18},
{ 0, 63, 60, 19, 18},
{ 0, 91, 60, 19, 18},
{ 0, 10, 85, 19, 18}, /* 4 5 6 7 */
{ 0, 37, 85, 19, 18},
{ 0, 63, 85, 19, 18},
{ 0, 91, 85, 19, 18},
{ 0, 10, 110, 19, 18}, /* 0 1 2 3 */
{ 0, 37, 110, 19, 18},
{ 0, 63, 110, 19, 18},
{ 0, 91, 110, 19, 18},
{ 0, 261, 110, 28, 18}, /* ca ce, cd, = */
{ 0, 187, 110, 28, 18},
{ 0, 224, 110, 28, 18},
{ 0, 131, 110, 46, 18},
{ 0, 131, 60, 19, 18}, /* + - * / % */
{ 0, 158, 60, 19, 18},
{ 0, 185, 60, 19, 18},
{ 0, 212, 60, 19, 18},
{ 0, 239, 60, 19, 18},
{ 0, 131, 85, 19, 18}, /* | & << >> ^ */
{ 0, 158, 85, 19, 18},
{ 0, 185, 85, 19, 18},
{ 0, 212, 85, 19, 18},
{ 0, 239, 85, 19, 18},
{ 0, 131, 35, 32, 18}, /* hex oct bin dec */
{ 0, 165, 35, 31, 18},
{ 0, 198, 35, 32, 18},
{ 0, 232, 35, 31, 18},
{ 0, 269, 35, 20, 18}, /* UNS */
{ 0, 269, 60, 20, 18}, /* NEG */
{ 0, 269, 85, 20, 18}, /* NOT */
};
struct windata {
int color; /* Color */
char *text; /* Pointer to the text string */
int x; /* x coordinate of text */
int y; /* y coordinate of text */
int value; /* 0-16 for number, symbol for operator */
int type; /* Number, operator, display */
} windata[NBUTTONS] = {
{ 1, " 0 ", 2, 3, 0, WTYP_DISP },
{ 0, "C", 5, 3, 12, WTYP_DIG },
{ 0, "D", 5, 3, 13, WTYP_DIG },
{ 0, "E", 5, 3, 14, WTYP_DIG },
{ 0, "F", 5, 3, 15, WTYP_DIG },
{ 0, "8", 5, 3, 8, WTYP_DIG },
{ 0, "9", 5, 3, 9, WTYP_DIG },
{ 0, "A", 5, 3, 10, WTYP_DIG },
{ 0, "B", 5, 3, 11, WTYP_DIG },
{ 0, "4", 5, 3, 4, WTYP_DIG },
{ 0, "5", 5, 3, 5, WTYP_DIG },
{ 0, "6", 5, 3, 6, WTYP_DIG },
{ 0, "7", 5, 3, 7, WTYP_DIG },
{ 0, "0", 5, 3, 0, WTYP_DIG },
{ 0, "1", 5, 3, 1, WTYP_DIG },
{ 0, "2", 5, 3, 2, WTYP_DIG },
{ 0, "3", 5, 3, 3, WTYP_DIG },
{ 0, "CA", 6, 3, OPR_CLRA, WTYP_SPEC },
{ 0, "CE", 6, 3, OPR_CLRE, WTYP_SPEC },
{ 0, "CD", 6, 3, OPR_CLRD, WTYP_SPEC },
{ 0, "=", 17, 2, OPR_ASGN, WTYP_OPER },
{ 0, "+", 5, 3, OPR_ADD, WTYP_OPER },
{ 0, "-", 5, 3, OPR_SUB, WTYP_OPER },
{ 0, "*", 5, 4, OPR_MUL, WTYP_OPER },
{ 0, "/", 5, 3, OPR_DIV, WTYP_OPER },
{ 0, "%", 5, 3, OPR_MOD, WTYP_OPER },
{ 0, "|", 5, 3, OPR_OR, WTYP_OPER },
{ 0, "&", 5, 3, OPR_AND, WTYP_OPER },
{ 0, ">>",1, 3, OPR_SHR, WTYP_OPER },
{ 0, "<<",0, 3, OPR_SHL, WTYP_OPER },
{ 0, "^", 5, 3, OPR_XOR, WTYP_OPER },
{ 0, "HEX", 2, 3, 16, WTYP_CONV },
{ 0, "DEC", 2, 3, 10, WTYP_CONV },
{ 0, "OCT", 2, 3, 8, WTYP_CONV },
{ 0, "BIN", 2, 3, 2, WTYP_CONV },
{ 0, "U", 5, 3, OPR_UNS, WTYP_SPEC },
{ 0, "`", 5, 3, OPR_NEG, WTYP_OPER },
{ 0, "~", 5, 3, OPR_NOT, WTYP_OPER },
};
Example D-2 is the complete source for the calculator application
described in Chapter 14, "A Complete Application."
Remaining code for basecalc
/* X Version 11 Integer Programmer's Calculator, written by
* Alan Greenspan, modified slightly by Adrian Nye */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#ifdef SYSV
#include <termio.h>
#else
#include <sgtty.h>
#include <sys/ttychars.h>
#endif SYSV
#include <ctype.h>
#include <pwd.h>
#include "basecalc.h"
/* Programmer's calculator with number base conversions */
main (argc, argv)
int argc;
register char *argv[];
{
/* So we can use the resource manager data merging functions */
XrmInitialize();
/* Parse command line first so we can open display,
* store any options in a database */
parseOpenDisp (&argc, argv);
/* Get server defaults, program defaults, .Xdefaults,
* command line, etc. and merge them */
mergeDatabases();
/* Extract values from database for use */
extractOpts ();
/* Load font, make pixmaps, set up arrays of windows */
initCalc ();
/* Get keyboard settings for interrupt, delete, etc. */
initTty ();
/* Make a standard cursor */
makeCursor ();
/* Set standard properties, create and map windows */
makeWindows (argc, argv);
/* Get events */
takeEvents ();
/* Bow out gracefully */
XCloseDisplay(display);
exit (1);
}
static char *getHomeDir( dest )
char *dest;
{
int uid;
extern char *getenv();
extern int getuid();
extern struct passwd *getpwuid();
struct passwd *pw;
register char *ptr;
if((ptr = getenv("HOME")) != NULL) {
(void) strcpy(dest, ptr);
} else {
if((ptr = getenv("USER")) != NULL) {
pw = getpwnam(ptr);
} else {
uid = getuid();
pw = getpwuid(uid);
}
if (pw) {
(void) strcpy(dest, pw->pw_dir);
} else {
*dest = '';
}
}
return dest;
}
/* Get program's and user's defaults */
mergeDatabases()
{
XrmDatabase homeDB, serverDB, applicationDB;
char filenamebuf[1024];
char *filename = &filenamebuf[0];
char *environment;
char *classname = "Basecalc";
char name[255];
(void) strcpy(name, "/usr/lib/X11/app-defaults/");
(void) strcat(name, classname);
/* Get application defaults file, if any */
applicationDB = XrmGetFileDatabase(name);
(void) XrmMergeDatabases(applicationDB, &rDB);
/* MERGE server defaults, these are created by xrdb,
* loaded as a property of the root window when the server
* initializes, and loaded into the display structure
* on XOpenDisplay; if not defined, use .Xdefaults */
if (XResourceManagerString(display) != NULL) {
serverDB = XrmGetStringDatabase(XResourceManagerString(display));
} else {
/* Open .Xdefaults file and merge into existing data base */
(void) getHomeDir(filename);
(void) strcat(filename, "/.Xdefaults");
serverDB = XrmGetFileDatabase(filename);
}
XrmMergeDatabases(serverDB, &rDB);
/* Open XENVIRONMENT file or, if not defined, the ~/.Xdefaults,
* and merge into existing data base */
if ((environment = getenv("XENVIRONMENT")) == NULL) {
int len;
environment = getHomeDir(filename);
(void) strcat(environment, "/.Xdefaults-");
len = strlen(environment);
(void) gethostname(environment+len, 1024-len);
}
homeDB = XrmGetFileDatabase(environment);
XrmMergeDatabases(homeDB, &rDB);
/* Command line takes precedence over everything */
XrmMergeDatabases(commandlineDB, &rDB);
}
/* Get command line options */
parseOpenDisp (argc, argv)
int *argc;
register char *argv[];
{
XrmValue value;
char *str_type[20];
myDisplayName[0] = '';
XrmParseCommand(&commandlineDB, opTable, opTableEntries, argv[0],
argc, argv);
/* Check for any arguments left */
if (*argc != 1) Usage();
/* Get display now, because we need it to get other databases*/
if (XrmGetResource(commandlineDB, "basecalc.display", "Basecalc.Display",
str_type, &value)== True) {
(void) strncpy(myDisplayName, value.addr, (int) value.size);
}
/* Open display */
if (!(display = XOpenDisplay(myDisplayName))) {
(void) fprintf(stderr, "%s: Can't open display '%s'\n",
argv[0], XDisplayName(myDisplayName));
exit(1);
}
screen_num = DefaultScreen(display);
visual = DefaultVisual(display, screen_num);
colormap = DefaultColormap(display, screen_num);
}
extractOpts()
{
char *str_type[20];
char buffer[20];
long flags;
XrmValue value;
int x, y, width, height;
XColor screen_def;
/* Get geometry (actually, this is currently ignored) */
if (XrmGetResource(rDB, "basecalc.geometry", "Basecalc.Geometry",
str_type, &value)== True) {
(void) strncpy(Geostr, value.addr, (int) value.size);
} else {
Geostr[0] = NULL;
}
if (XrmGetResource(rDB, "basecalc.iconGeometry", "Basecalc.IconGeometry",
str_type, &value)== True) {
(void) strncpy(iconGeostr, value.addr, (int) value.size);
} else {
iconGeostr[0] = NULL;
}
if (XrmGetResource(rDB, "basecalc.unsigned", "Basecalc.Unsigned",
str_type, &value)== True)
if (strncmp(value.addr, "False", (int) value.size) == 0)
Unsigned = False;
if (XrmGetResource(rDB, "basecalc.base", "Basecalc.Base", str_type,
&value)== True) {
(void) strncpy(buffer, value.addr, (int) value.size);
buffer[value.size] = NULL;
Base = atoi(buffer);
} else Base = 10;
if (XrmGetResource(rDB, "basecalc.foreground", "Basecalc.Foreground",
str_type, &value)== True) {
(void) strncpy(buffer, value.addr, (int) value.size);
if (XParseColor(display, colormap, buffer,
&screen_def) == 0) {
(void) fprintf(stderr, "basecalc: fg color specification %s \
invalid", buffer);
foreground = BlackPixel(display, screen_num);
} else {
if ((visual->class == StaticGray) || (visual->class ==
GrayScale))
foreground = BlackPixel(display, screen_num);
else if (XAllocColor(display, colormap, &screen_def) == 0) {
foreground = BlackPixel(display, screen_num);
(void) fprintf(stderr, "basecalc: couldn't allocate color: \
%s.\n", buffer);
}
else
foreground = screen_def.pixel;
}
} else {
foreground = BlackPixel(display, screen_num);
}
if (XrmGetResource(rDB, "basecalc.background", "Basecalc.Background",
str_type, &value)== True) {
(void) strncpy(buffer, value.addr, (int) value.size);
if (XParseColor(display, colormap, buffer,
&screen_def) == 0) {
(void) fprintf(stderr, "basecalc: bg color specification %s \
invalid", buffer);
background = WhitePixel(display, screen_num);
} else {
if ((visual->class == StaticGray) || (visual->class ==
GrayScale))
background = WhitePixel(display, screen_num);
else if (XAllocColor(display, colormap, &screen_def) == 0) {
background = WhitePixel(display, screen_num);
(void) fprintf(stderr, "basecalc: couldn't allocate color: \
%s.\n", buffer);
}
else
background = screen_def.pixel;
}
} else {
background = WhitePixel(display, screen_num);
}
/* One last check to make sure the colors are different! */
if (background == foreground) {
background = WhitePixel(display, screen_num);
foreground = BlackPixel(display, screen_num);
}
/* Could add a command line option for initial state:
* iconOnly[0] = NULL; */
/* Get window geometry information */
if (Geostr != NULL) {
flags = XParseGeometry(Geostr,
&x, &y, &width, &height);
if ((WidthValue|HeightValue) & flags)
Usage ();
if (XValue & flags) {
if (XNegative & flags)
x = DisplayWidth(display, screen_num) +
x - sizehints.width;
sizehints.flags |= USPosition;
sizehints.x = x;
}
if (YValue & flags) {
if (YNegative & flags)
y = DisplayHeight(display, screen_num) +
x - sizehints.width;
sizehints.flags |= USPosition;
sizehints.y = y;
}
}
/* Get icon geometry information */
if (iconGeostr != NULL) {
iconGeostr[0] = '=';
flags = XParseGeometry(iconGeostr,
&x, &y, &width, &height);
if ((WidthValue|HeightValue) & flags)
Usage ();
if (XValue & flags) {
if (XNegative & flags)
x = DisplayWidth(display, screen_num) +
x - iconsizehints.width;
iconsizehints.flags |= USPosition;
wmhints.flags |= IconPositionHint;
wmhints.icon_x = x;
iconsizehints.x = x;
}
if (YValue & flags) {
if (YNegative & flags)
y = DisplayHeight(display, screen_num) +
x - iconsizehints.width;
iconsizehints.flags |= USPosition;
wmhints.flags |= IconPositionHint;
wmhints.icon_y = y;
iconsizehints.y = y;
}
}
}
/* Print message to stderr and exit */
Usage ()
{
(void) fprintf (stderr,
"%s: [-iconic] [-unsigned] [-hex|x|dec|oct|binary] \
[-display <display>] [-geometry <geometrystring>] \
[-iconGeometry <icongeometrystring>\n",
calcName ? calcName : "basecalc");
exit (1);
}
/* Make a pixmap */
Pixmap
makePixmap(data, width, height)
char *data;
unsigned int width, height;
{
Pixmap pid;
pid = XCreatePixmapFromBitmapData(display, DefaultRootWindow(display),
data, width, height, foreground, background,
DefaultDepth(display, screen_num));
return(pid);
}
/* Initialize calculator options */
initCalc ()
{
register int win;
register int found = -1;
XGCValues values;
extern char lgray_bits[];
if ((theFont = XLoadQueryFont (display, myFontName)) == NULL) {
(void) fprintf(stderr, "basecalc: can't open font %s\n",
myFontName);
exit(-1);
}
/* Make the utility pixmaps */
grayPixmap = makePixmap(gray_bits, gray_width, gray_height);
lgrayPixmap = makePixmap(lgray_bits, lgray_width, lgray_height);
/* Make the utility gc's */
values.font = theFont->fid;
values.foreground = foreground;
fgGC = XCreateGC(display, DefaultRootWindow(display),
GCForeground|GCFont, &values);
values.foreground = background;
values.function = GXcopy;
bgGC = XCreateGC(display, DefaultRootWindow(display),
GCForeground|GCFont|GCFunction, &values);
/* Loop through buttons, setting disabled buttons to Color
* Light Gray; also find the window which corresponds to the
* starting display base; also add ascent to y position of text */
for (win = 1; win < NBUTTONS; win++) {
if (windata[win].type == WTYP_CONV &&
windata[win].value == Base) {
found = win;
} else
if (windata[win].type == WTYP_DIG &&
windata[win].value >= Base) {
windata[win].color = disabledColor;
}
else
if (windata[win].type == WTYP_SPEC &&
windata[win].value == OPR_UNS) {
if (Unsigned)
windata[win].text = "U";
else
windata[win].text = "S";
windata[win].color = pressedColor;
}
else
windata[win].color = unpressedColor;
windata[win].y += theFont->max_bounds.ascent;
}
windata[0].y += theFont->max_bounds.ascent;
if (found >= 0) {
Winbase = found;
windata[found].color = pressedColor;
} else {
(void) fprintf(stderr, "basecalc: can't use base %d\n", Base);
exit(-1);
}
windata[0].color = displayColor;
}
/* Get the user's tty special chars; this is currently 4.2 specific */
initTty ()
{
register struct KeyCode *KeyCodePtr;
register int fd;
#ifdef SYSV
struct termio term;
#else
struct sgttyb tty;
struct tchars tchars;
struct ltchars ltchars;
#endif SYSV
if (!isatty(0)) {
if ((fd = open ("/dev/console", 0)) < 0)
return;
} else
fd = 0;
#ifdef SYSV
(void) ioctl (fd, TCGETA, &term);
#else
(void) ioctl (fd, TIOCGETP, &tty);
(void) ioctl (fd, TIOCGETC, &tchars);
(void) ioctl (fd, TIOCGLTC, <chars);
#endif SYSV
if (fd)
(void) close (fd);
KeyCodePtr = KeyCodes;
#ifdef SYSV
KeyCodePtr++->kc_char = term.c_cc[VERASE];
KeyCodePtr++;
KeyCodePtr++->kc_char = term.c_cc[VKILL];
KeyCodePtr->kc_char = term.c_cc[VINTR];
QuitChar = term.c_cc[VQUIT];
#else
KeyCodePtr++->kc_char = tty.sg_erase;
KeyCodePtr++->kc_char = ltchars.t_werasc;
KeyCodePtr++->kc_char = tty.sg_kill;
KeyCodePtr->kc_char = tchars.t_intrc;
QuitChar = tchars.t_quitc;
#endif SYSV
}
/* Make the cursor */
makeCursor ()
{
theCursor = XCreateFontCursor (display, XC_hand1);
}
/* Set up the selection of events */
selectEvents ()
{
int win;
XSelectInput (display, calcWin, KeyPressMask|KeyReleaseMask);
XSelectInput (display, dispWin, ExposureMask);
for (win = 1; win < NBUTTONS; win++)
XSelectInput (display, Buttons[win].self,
ExposureMask|
ButtonPressMask|ButtonReleaseMask|
EnterWindowMask|LeaveWindowMask);
}
/* Get events and process them */
takeEvents ()
{
XEvent Event;
register int win;
register int Pressed = False;
register int InWindow = False;
char buffer[10];
register char *KeyChars = buffer;
register int WasKeyDown = False;
unsigned i, nbytes;
while (1) {
if (!WasKeyDown)
XNextEvent (display, &Event);
else
Event.type = KeyRelease;
/* Map keyboard events to Window events */
if (Event.type == KeyPress || Event.type == KeyRelease) {
nbytes = XLookupString (&Event, buffer,
sizeof(buffer), NULL, NULL);
if (Event.type == KeyPress) {
Event.type = ButtonPress;
WasKeyDown = 1;
} else {
for (i=0; i<60000; i++)
;
Event.type = ButtonRelease;
}
if ((Event.xbutton.window =
keyToWin (KeyChars, nbytes)) == None){
WasKeyDown = 0;
continue;
}
}
for (win=0; win < NBUTTONS; win++)
if (Buttons[win].self == Event.xbutton.window)
break;
switch (Event.type) {
case ButtonPress:
if (windata[win].color == disabledColor)
break;
Pressed = win;
if (!WasKeyDown)
InWindow = True;
windata[win].color = pressedColor;
drawButton (win, 0);
break;
case LeaveNotify:
if (Pressed != win)
break;
InWindow = False;
windata[win].color = unpressedColor;
drawButton (win, 0);
break;
case EnterNotify:
if (Pressed != win)
break;
InWindow = True;
windata[win].color = pressedColor;
drawButton (win, 0);
break;
case ButtonRelease:
if (windata[win].color == disabledColor ||
Pressed != win) {
WasKeyDown = False;
break;
}
Pressed = False;
windata[win].color = unpressedColor;
if (WasKeyDown || InWindow)
winPressed (win);
WasKeyDown = False;
InWindow = False;
drawButton (win, 0);
break;
case Expose:
drawButton (win, 1);
break;
}
XFlush(display);
}
}
/* Make the calculator windows */
makeWindows (argc, argv)
int argc;
char *argv[];
{
register int i;
XSetWindowAttributes attributes;
char *window_name = "Programmer's Calculator";
char *icon_name = "basecalc";
XClassHint class_hints;
XTextProperty windowName, iconName;
/* Define the border and background for the main window --
* black border and a patterned background */
attributes.border_pixel = foreground;
attributes.background_pixmap = grayPixmap;
/* Create the main window (calculator frame) as a child of
* the root window */
attributes.cursor = theCursor;
calcWin = XCreateWindow(display, DefaultRootWindow(display),
sizehints.x, sizehints.y, sizehints.width, sizehints.height,
1, DefaultDepth(display, screen_num), InputOutput,
CopyFromParent, CWBorderPixel|CWBackPixmap|CWCursor,
&attributes);
/* Create the icon window and associate it with the calculator */
iconPixmap = makePixmap(icon_bits, icon_width, icon_height);
attributes.border_pixel = foreground;
attributes.background_pixmap = iconPixmap;
iconWin = XCreateWindow(display, DefaultRootWindow(display),
iconsizehints.x, iconsizehints.y,
iconsizehints.width, iconsizehints.height,
1, DefaultDepth(display, screen_num), InputOutput,
CopyFromParent, CWBorderPixel|CWBackPixmap,
&attributes);
wmhints.icon_window = iconWin;
wmhints.initial_state = iconOnly ? IconicState : NormalState;
wmhints.input = True;
wmhints.flags |= InputHint | StateHint | IconWindowHint;
XSetWMHints(display, calcWin, &wmhints);
/* These calls store window_name and icon_name into XTextProperty
* structures and set their other fields properly */
if (XStringListToTextProperty(&window_name, 1, &windowName) == 0) {
(void) fprintf( stderr, "%s: structure allocation for windowName \
failed.\n", argv[0]);
exit(-1);
}
if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0) {
(void) fprintf( stderr, "%s: structure allocation for iconName \
failed.\n", argv[0]);
exit(-1);
}
class_hints.res_name = argv[0];
class_hints.res_class = "Basicwin";
XSetWMProperties(display, calcWin, &windowName, &iconName,
argv, argc, &sizehints, &wmhints,
&class_hints);
#endif
/* Create the buttons as subwindows */
attributes.background_pixmap = lgrayPixmap;
attributes.border_pixel = foreground;
for (i = 0; i < NBUTTONS; i++)
switch (windata[i].color) {
case WHITE:
Buttons[i].self = XCreateSimpleWindow(display, calcWin,
Buttons[i].x, Buttons[i].y,
Buttons[i].width, Buttons[i].height,
1, foreground, background);
break;
case BLACK:
Buttons[i].self = XCreateSimpleWindow(display, calcWin,
Buttons[i].x, Buttons[i].y,
Buttons[i].width, Buttons[i].height,
1, background, foreground);
break;
case LIGHTGRAY:
Buttons[i].self = XCreateWindow(display, calcWin,
Buttons[i].x, Buttons[i].y,
Buttons[i].width, Buttons[i].height,
1, CopyFromParent, InputOutput, CopyFromParent,
CWBorderPixel|CWBackPixmap, &attributes);
break;
}
/* The display window is distinguished */
dispWin = Buttons[0].self;
/* Initialize event catching */
selectEvents ();
/* Map the calculator and subwindows */
XMapSubwindows(display, calcWin);
XMapWindow(display, calcWin);
}
/* Draw a single button with its text */
drawButton (win, exposeEvent)
register int win;
{
register char *string;
register int x, y;
struct windata *winp;
char *measure;
XSetWindowAttributes attributes;
unsigned long valuemask;
GC gc;
winp = &windata[win];
x = winp->x;
y = winp->y;
string = winp->text;
switch (windata[win].color) {
case WHITE:
gc = fgGC;
attributes.background_pixel = background;
attributes.border_pixel = foreground;
valuemask = CWBackPixel|CWBorderPixel;
break;
case BLACK:
gc = bgGC;
attributes.background_pixel = foreground;
attributes.border_pixel = background;
valuemask = CWBackPixel|CWBorderPixel;
break;
case LIGHTGRAY:
gc = bgGC;
attributes.background_pixmap = lgrayPixmap;
attributes.border_pixel = foreground;
valuemask = CWBackPixmap|CWBorderPixel;
break;
}
if (!exposeEvent){
XChangeWindowAttributes(display, Buttons[win].self,
valuemask, &attributes);
XClearWindow(display, Buttons[win].self);
}
XDrawString (display, Buttons[win].self, gc, x, y, string,
strlen (string));
if (win == 0) {
switch (Base) {
case 10:
case 8:
measure = Octmeasure;
break;
default:
case 16:
case 2:
measure = Hexmeasure;
break;
}
XDrawString (display, dispWin, gc, 7, 6, measure, 31);
}
}
static unsigned int LastDisp = 1;
/* Do the operation corresponding to a key press */
winPressed (win)
{
register int type;
type = windata[win].type;
switch (type) {
case WTYP_CONV:
convButton (win);
displayVal (LastDisp == 1 ? Value : Accum);
break;
case WTYP_DIG:
digitButton (win);
displayVal (Value);
LastDisp = 1;
break;
case WTYP_OPER:
if (operButton (win) == 0) {
displayVal (Accum);
LastDisp = 2;
} else {
displayVal (Value);
LastDisp = 1;
}
break;
case WTYP_SPEC:
specButton (win);
displayVal (LastDisp == 1 ? Value : Accum);
LastDisp = 1;
}
}
/* Handle a conversion button */
convButton (win)
{
register int i, NewBase, Diff, Digit;
register int HiBase, LowBase;
NewBase = windata[win].value;
windata[Winbase].color = unpressedColor;
drawButton (Winbase, 0);
windata[win].color = pressedColor;
Diff = NewBase - Base;
if (Diff) {
if (NewBase > Base) {
LowBase = Base;
HiBase = NewBase;
} else {
LowBase = NewBase;
HiBase = Base;
}
for (i = 1; i < NBUTTONS; i++) {
if (windata[i].type == WTYP_DIG) {
Digit = windata[i].value;
if (Digit >= LowBase && Digit < HiBase) {
if (Diff < 0)
windata[i].color = disabledColor;
else
windata[i].color = unpressedColor;
drawButton (i, 0);
}
}
}
}
Winbase = win;
Base = NewBase;
}
/* Handle a digit button */
digitButton (win)
{
register unsigned long Temp;
if (CalcReset) {
CalcReset = 0;
Accum = 0;
Value = 0;
LastOpt = OPR_ADD;
}
Digit = windata[win].value;
if (Unsigned)
Temp = (unsigned)Value * (unsigned)Base + Digit;
else
Temp = Value * Base + Digit;
if ((unsigned)Temp/Base != (unsigned)Value) { /* Overflow? */
/* Flash the display since the character didn't register */
windata[0].color =
(displayColor == WHITE) ? BLACK : WHITE;
drawButton (0, 0);
XFlush(display);
Delay ();
windata[0].color = displayColor;
drawButton (0, 0);
return;
}
Value = Temp;
}
/* Handle a special operator */
specButton (win)
{
register int oper;
oper = windata[win].value;
switch (oper) {
case OPR_CLRD:
if (LastOpt == OPR_ASGN)
break;
Value = (unsigned)Value / Base;
break;
case OPR_CLRE:
Value = 0;
break;
case OPR_CLRA:
Accum = 0;
Value = 0;
LastOpt = OPR_ADD;
break;
case OPR_UNS:
Unsigned = !Unsigned;
windata[win].text = Unsigned ? "U" : "S";
windata[win].color = pressedColor;
drawButton (win, 0);
break;
}
}
/* Handle an operator */
operButton (win)
{
register int oper;
oper = LastOpt;
LastOpt = windata[win].value;
CalcReset = 0;
switch (LastOpt) {
case OPR_NEG:
Value = -Value;
if ((LastOpt = oper) == OPR_ASGN)
Accum = Value;
return 1;
case OPR_NOT:
Value = ~Value;
if ((LastOpt = oper) == OPR_ASGN)
Accum = Value;
return 1;
}
switch (oper) {
case OPR_ADD:
if (Unsigned)
Accum = (unsigned)Accum + (unsigned)Value;
else
Accum += Value;
break;
case OPR_SUB:
if (Unsigned)
Accum = (unsigned)Accum - (unsigned)Value;
else
Accum -= Value;
break;
case OPR_MUL:
if (Unsigned)
Accum = (unsigned)Accum * (unsigned)Value;
else
Accum *= Value;
break;
case OPR_DIV:
if (Value == 0)
break;
if (Unsigned)
Accum = (unsigned)Accum / (unsigned)Value;
else
Accum /= Value;
break;
case OPR_MOD:
if (Value == 0)
break;
if (Unsigned)
Accum = (unsigned)Accum % (unsigned)Value;
else
Accum %= Value;
break;
case OPR_OR:
Accum |= Value;
break;
case OPR_AND:
Accum &= Value;
break;
case OPR_SHR:
if (Unsigned)
Accum = (unsigned)Accum >> (unsigned)Value;
else
Accum >>= Value;
break;
case OPR_SHL:
if (Unsigned)
Accum = (unsigned)Accum << (unsigned)Value;
else
Accum <<= Value;
break;
case OPR_XOR:
Accum ^= Value;
break;
case OPR_ASGN:
break;
}
if (LastOpt == OPR_ASGN) {
Value = Accum;
CalcReset = 1;
return 1;
}
Value = 0;
return 0;
}
/* Display a number in the display window */
displayVal (number)
register long number;
{
register char *Fmt;
register char *cp;
register int i;
switch (Base) {
case 16:
Fmt = "%32x";
break;
case 10:
Fmt = "%32d";
break;
case 8:
Fmt = "%32o";
break;
case 2:
Fmt = "%032b";
break;
}
cp = windata[0].text;
for (i=32; --i >= 0; )
*cp++ = ' ';
*cp = '';
Sprintf (windata[0].text, Fmt, number);
drawButton (0, 0);
}
/* Translate a key code to a corresponding window */
keyToWin (str, n)
register char *str;
register unsigned n;
{
register int value = -1;
register struct KeyCode *KeyCodePtr;
register char ch;
register int i;
if (n > (unsigned) 0) {
ch = *str;
if (islower(ch) && isxdigit(ch))
value = 10 + ch - 'a';
else
if (isdigit(ch))
value = ch - '0';
if (value >= 0) {
for (i = 1; i < NBUTTONS; i++)
if (windata[i].type == WTYP_DIG &&
windata[i].value == value)
return Buttons[i].self;
} else {
/* Do some translations -- these should be driven
* from the user's terminal erase, kill, etc */
switch (ch) {
case 'U':
if (Unsigned)
return -1;
str = "S";
n = 1;
break;
case 'S':
if (!Unsigned)
return -1;
str = "U";
n = 1;
break;
case '\r':
case '\n':
str = "=";
n = 1;
break;
default:
if (ch == QuitChar) {
XCloseDisplay(display);
exit (1);
}
KeyCodePtr = KeyCodes;
while ((n = KeyCodePtr->kc_len) > (unsigned) 0) {
if (ch == KeyCodePtr->kc_char) {
str = KeyCodePtr->kc_func;
break;
}
KeyCodePtr++;
}
if (n == 0)
n = 1;
break;
}
for (i = 1; i < NBUTTONS; i++) {
if (windata[i].type != WTYP_DIG &&
strncmp (windata[i].text, str, (int) n) == 0)
return Buttons[i].self;
}
}
}
return None;
}
/*
* Specialized version of C Library sprintf.
*
* %u %d %o %x %b (binary) are recognized.
* %0W... - where 0 means pad with zeros otherwise blanks
* - if W, the minimum field width is larger than
* - the number
*/
Sprintf(cp, fmt, x1)
register char *cp;
register char *fmt;
unsigned x1;
{
register int c, b, sign;
register char *s;
register unsigned short fw;
char *printInBase();
char pad;
while ((c = *fmt++) != '%') {
if (c == '') {
*cp = c;
return; /* to displayVal */
}
*cp++ = c;
}
c = *fmt++;
if (c == '0') {
pad = '0';
c = *fmt++;
} else
pad = ' ';
/* Calculate minimum field width */
fw = 0;
while (c >= '0' && c <= '9') {
fw = fw * 10 + (c - '0');
c = *fmt++;
}
sign = 0;
switch (c) {
case 'x':
b = 16;
break;
case 'd':
if (!Unsigned)
sign = 1;
/* falls through into 'u' case */
case 'u':
b = 10;
break;
case 'o':
b = 8;
break;
case 'b':
b = 2;
break;
default:
/*
* Unknown format
*/
b = 0;
break;
}
if (b)
cp = printInBase (cp, x1, b, fw, pad, sign);
break;
/* Print a number n in base b into string cp;
* minimum field width = fw, pad character = pad */
char *
printInBase (cp, n, b, fw, pad, sign)
register char *cp;
register long n;
register b;
register int fw, pad;
{
register i, nd, c;
int flag;
int plmax;
char d[33];
c = 1;
if (sign)
flag = n < 0;
else
flag = 0;
if (flag)
n = (-n);
if (b==2)
plmax = 32;
else if (b==8)
plmax = 11;
else if (b==10)
plmax = 10;
else if (b==16)
plmax = 8;
if (b==10) {
if (flag == 0)
sign = 0;
flag = 0;
}
for (i=0;i<plmax;i++) {
if (flag == 0)
nd = (unsigned)n%b;
else
nd = n%b;
if (flag) {
nd = (b - 1) - nd + c;
if (nd >= b) {
nd -= b;
c = 1;
} else
c = 0;
}
d[i] = nd;
if (flag == 0)
n = (unsigned)n/b;
else
n = n/b;
if ((n==0) && (flag==0))
break;
}
if (i==plmax)
i--;
if (sign) {
fw--;
if (pad == '0')
*cp++ = '-';
}
if (fw > i+1) {
for (fw -= i+1; fw > 0; fw--)
*cp++ = pad;
}
if (sign && pad != '0')
*cp++ = '-';
for (;i>=0;i--)
*cp++ = "0123456789ABCDEF"[d[i]];
*cp = '';
return cp;
}
/* Delay a little while */
Delay ()
{
long tic;
for (tic = 0; tic < 50000; tic++)
;
}
Xlib Programming Manual (O'Reilly & Associates, Inc.) |