|
|
1.1 root 1: /* $Header: Command.c,v 1.3 87/09/12 12:42:17 swick Exp $ */
2: #ifndef lint
3: static char *sccsid = "@(#)Command.c 1.13 2/25/87";
4: #endif lint
5:
6: /*
7: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
8: *
9: * All Rights Reserved
10: *
11: * Permission to use, copy, modify, and distribute this software and its
12: * documentation for any purpose and without fee is hereby granted,
13: * provided that the above copyright notice appear in all copies and that
14: * both that copyright notice and this permission notice appear in
15: * supporting documentation, and that the name of Digital Equipment
16: * Corporation not be used in advertising or publicity pertaining to
17: * distribution of the software without specific, written prior permission.
18: *
19: *
20: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26: * SOFTWARE.
27: */
28:
29:
30: #include <stdio.h>
31: #include <strings.h>
32: #include "Xlib.h"
33: #include "Intrinsic.h"
34: #include "Command.h"
35: #include "Atoms.h"
36:
37: /* Private Definitions */
38:
39: typedef void (*CommandProc)();
40:
41: typedef struct _WidgetDataRec {
42: Display *dpy; /* widget display connection */
43: Window mywin; /* widget window */
44: Position x, y; /* Location of widget. */
45: Dimension borderWidth; /* border width in pixels */
46: Dimension width, height; /* width/height in pixels */
47: Dimension ibw, ibh; /* internal border width/height in pixels */
48: char *text; /* button text */
49: Pixel fgpixel; /* color index for text */
50: Pixel bgpixel; /* color index for background */
51: Pixel brpixel; /* color for border */
52: Boolean sensitive; /* user actions processed */
53: Boolean highlighted; /* are we border highlighted? */
54: Boolean set; /* are we text highlighted */
55: Boolean notifying; /* are we in the notify proc? */
56: Boolean needsfreeing; /* were we destroyed by the notify proc? */
57: int eventlevels; /* recursion levels of event processing */
58: XFontStruct *fontstruct; /* font for text */
59: Dimension twidth, theight;/* text width/height */
60: XtJustify justify; /* text justification */
61: CommandProc proc; /* command procedure to invoke on notify */
62: caddr_t tag; /* widget client data */
63: GC normgc; /* gc for normal display */
64: GC invgc; /* gc for inverted display */
65: GC graygc; /* gc for grayed-out text */
66: XtEventsPtr eventTable; /* Table for translation manager. */
67: TranslationPtr state; /* Translation manager state handle. */
68: } WidgetDataRec, *WidgetData;
69:
70: static WidgetDataRec globaldata;
71: extern void Dummy();
72: static WidgetDataRec globalinit = {
73: NULL, /* Display dpy; */
74: NULL, /* Window mywin; */
75: 0, 0, /* Position x, y; */
76: 1, /* Dimension borderWidth; */
77: 0, 0, /* Dimension width, height; */
78: 4, 2, /* Dimension ibw, ibh; */
79: NULL, /* char *text; */
80: NULL, /* Pixel fgpixel; */ /* init proc */
81: NULL, /* Pixel bgpixel; */ /* init proc */
82: NULL, /* Pixel brpixel; */ /* init proc */
83: TRUE, /* int sensitive; */
84: FALSE, /* int highlighted; */
85: FALSE, /* int set; */
86: FALSE, /* int notifying; */
87: FALSE, /* int needsfreeing; */
88: 0, /* int eventlevels; */
89: NULL, /* XFontStruct *fontstruct; */ /* init proc */
90: 0, 0, /* int twidth, theight; */
91: XtjustifyCenter, /* text justification */
92: Dummy, /* void (*Proc) (); */
93: NULL, /* caddr_t tag; */
94: NULL, /* GC normgc; */
95: NULL, /* GC invgc; */
96: NULL, /* GC graygc; */
97: NULL, /* XtEventsPtr eventTable; */ /* init proc */
98: NULL, /* caddr_t state; */
99: };
100:
101: /* Private Data */
102:
103: static Resource resources[] = {
104: {XtNwindow, XtCWindow, XrmRWindow,
105: sizeof(Window), (caddr_t)&globaldata.mywin, (caddr_t)NULL},
106: {XtNx, XtCX, XrmRInt,
107: sizeof(int), (caddr_t)&globaldata.x, (caddr_t)NULL},
108: {XtNy, XtCY, XrmRInt,
109: sizeof(int), (caddr_t)&globaldata.y, (caddr_t)NULL},
110: {XtNborderWidth, XtCBorderWidth, XrmRInt,
111: sizeof(int), (caddr_t)&globaldata.borderWidth, (caddr_t)NULL},
112: {XtNwidth, XtCWidth, XrmRInt,
113: sizeof(int), (caddr_t)&globaldata.width, (caddr_t)NULL},
114: {XtNheight, XtCHeight, XrmRInt,
115: sizeof(int), (caddr_t)&globaldata.height, (caddr_t)NULL},
116: {XtNinternalWidth, XtCWidth, XrmRInt,
117: sizeof(int), (caddr_t)&globaldata.ibw, (caddr_t)NULL},
118: {XtNinternalHeight, XtCHeight, XrmRInt,
119: sizeof(int), (caddr_t)&globaldata.ibh, (caddr_t)NULL},
120: {XtNlabel, XtCLabel, XrmRString,
121: sizeof(char *), (caddr_t)&globaldata.text, (caddr_t)NULL},
122: {XtNforeground, XtCColor, XrmRPixel,
123: sizeof(int), (caddr_t)&globaldata.fgpixel, (caddr_t)&XtDefaultFGPixel},
124: {XtNbackground, XtCColor, XrmRPixel,
125: sizeof(int), (caddr_t)&globaldata.bgpixel, (caddr_t)&XtDefaultBGPixel},
126: {XtNborder, XtCColor, XrmRPixel, sizeof(int),
127: (caddr_t)&globaldata.brpixel, (caddr_t)&XtDefaultFGPixel},
128: {XtNfont, XtCFont, XrmRFontStruct,
129: sizeof(XFontStruct *), (caddr_t)&globaldata.fontstruct, (caddr_t)NULL},
130: {XtNjustify, XtCJustify, XtRJustify,
131: sizeof(XtJustify), (caddr_t)&globaldata.justify, (caddr_t)NULL},
132: {XtNfunction, XtCFunction, XtRFunction,
133: sizeof(CommandProc), (caddr_t)&globaldata.proc, (caddr_t)NULL},
134: {XtNparameter, XtCParameter, XrmRPointer,
135: sizeof(caddr_t), (caddr_t)&globaldata.tag, (caddr_t)NULL},
136: {XtNsensitive, XtCBoolean, XrmRBoolean, sizeof(Boolean),
137: (caddr_t)&globaldata.sensitive, NULL},
138: {XtNeventBindings, XtCEventBindings, XtREventBindings, sizeof(caddr_t),
139: (caddr_t)&globaldata.eventTable, NULL},
140: };
141: static char *defaultEventBindings[] = {
142: "<ButtonPress>left: set\n",
143: "<ButtonRelease>left: notify unset\n",
144: "<EnterWindow>: highlight\n",
145: "<LeaveWindow>: unhighlight unset\n",
146: NULL
147: };
148:
149: /****************************************************************
150: *
151: * Private Procedures
152: *
153: ****************************************************************/
154:
155: /* !!! STATIC !!! */
156: static Boolean initialized = FALSE; /* initialization flag */
157:
158: static XContext widgetContext;
159:
160: static void CommandInitialize ()
161: {
162: if (initialized)
163: return;
164: initialized = TRUE;
165: widgetContext = XUniqueContext();
166:
167: globalinit.eventTable = XtParseEventBindings(defaultEventBindings);
168: }
169:
170: /*ARGSUSED*/
171: static void Dummy(p) /* default call back proc */
172: caddr_t p;
173: {
174: (void) printf("dummy call back for Command\n");
175: }
176:
177: static void Ignore()
178: {}
179:
180:
181: /*
182: * Given a display and window, get the widget data.
183: */
184:
185: static WidgetData DataFromWindow(dpy, window)
186: Display *dpy;
187: Window window;
188: {
189: WidgetData result;
190: if (XFindContext(dpy, window, widgetContext, (caddr_t *)&result))
191: return NULL;
192: return result;
193: }
194:
195: /*
196: * Calculate how wide and high the text will be when displayed.
197: */
198:
199: static void SetTextWidthAndHeight(data)
200: WidgetData data;
201: {
202: data->theight = data->fontstruct->max_bounds.ascent +
203: data->fontstruct->max_bounds.descent;
204: data->twidth = XTextWidth(data->fontstruct, data->text,
205: strlen(data->text));
206: }
207:
208:
209: /*
210: * Build the gc's for the widget.
211: */
212:
213: #define gray_width 32
214: #define gray_height 32
215:
216: static BuildGcs(data)
217: WidgetData data;
218: {
219: unsigned long valuemask;
220: XGCValues values;
221: Pixmap gray;
222: static short gray_bits[] = {
223: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
224: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
225: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
226: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
227: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
228: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
229: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
230: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
231: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
232: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
233: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
234: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
235: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
236: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
237: 0xaaaa, 0xaaaa, 0x5555, 0x5555,
238: 0xaaaa, 0xaaaa, 0x5555, 0x5555
239: };
240: if (XFindContext(data->dpy, (Window) NULL, widgetContext,
241: (caddr_t *)&gray)) {
242: XImage ximage;
243: GC pgc;
244: XGCValues gcv;
245:
246: gcv.foreground = 1;
247: gcv.background = 0;
248: gray = XCreatePixmap(data->dpy, data->mywin,
249: gray_width, gray_height,
250: DefaultDepth(data->dpy, DefaultScreen(data->dpy)));
251:
252: /*
253: Instead of calling the GCManager, since it doesn't handle depths,
254: and stipples are always XYBitmap, depth == 1, use XCreateGC
255: directly.
256: */
257: pgc = XCreateGC(data->dpy, gray, GCForeground | GCBackground, &gcv);
258:
259: /*
260: pgc = XtGetGC(data->dpy, widgetContext, gray,
261: GCForeground | GCBackground, &gcv);
262: */
263: ximage.height = gray_height;
264: ximage.width = gray_width;
265: ximage.xoffset = 0;
266: ximage.format = XYBitmap;
267: ximage.data = (char *)gray_bits;
268: ximage.byte_order = ImageByteOrder(data->dpy);
269: ximage.bitmap_unit = BitmapUnit(data->dpy);
270: ximage.bitmap_bit_order = BitmapBitOrder(data->dpy);
271: ximage.bitmap_pad = BitmapPad(data->dpy);
272: ximage.bytes_per_line = gray_width / 8;
273: ximage.depth = 1;
274:
275: XPutImage(data->dpy, gray, pgc, &ximage, 0, 0, 0, 0,
276: gray_width, gray_height);
277: (void)XSaveContext(data->dpy, (Window) NULL, widgetContext,
278: (caddr_t)gray);
279: XFreeGC(data->dpy, pgc); /* if the GCManager used, don't do this */
280: }
281:
282: valuemask = GCForeground | GCBackground | GCFont | GCFillStyle;
283: values.font = data->fontstruct->fid;
284: values.foreground = data->bgpixel;
285: values.background = data->fgpixel;
286: values.fill_style = FillSolid;
287: data->invgc = XtGetGC(data->dpy, widgetContext, data->mywin,
288: valuemask, &values);
289: values.foreground = data->fgpixel;
290: values.background = data->bgpixel;
291: data->normgc = XtGetGC(data->dpy, widgetContext, data->mywin,
292: valuemask, &values);
293: valuemask |= GCStipple;
294: values.fill_style = FillStippled;
295: values.stipple = gray;
296: data->graygc = XtGetGC(data->dpy, widgetContext, data->mywin,
297: valuemask, &values);
298: }
299:
300:
301: /*
302: *
303: * Repaint the widget window
304: *
305: */
306:
307: static void Redisplay(data)
308: WidgetData data;
309: {
310: int textx, texty;
311: Window w = data->mywin;
312:
313:
314: /*
315: * Calculate Text x,y given window width and text width
316: * to the specified justification
317: */
318:
319: if (data->needsfreeing) return;
320:
321: if (data->justify == XtjustifyLeft)
322: textx = 2;
323: else if (data->justify == XtjustifyRight)
324: textx = data->width - data->twidth - 2;
325: else
326: textx = ((data->width - data->twidth) / 2);
327: if (textx < 0) textx = 0;
328: texty = (data->height - data->theight) / 2 +
329: data->fontstruct->max_bounds.ascent;
330:
331: XFillRectangle(data->dpy, w,
332: ((data->highlighted || data->set)
333: ? data->normgc : data->invgc),
334: 0, 0, data->width, data->height);
335:
336: if (data->highlighted || data->set)
337: XFillRectangle(data->dpy, w,
338: data->set ? data->normgc : data->invgc,
339: textx, (int) ((data->height - data->theight) / 2),
340: data->twidth, data->theight);
341:
342: XDrawString(data->dpy, w,
343: data->set ? data->invgc : (data->sensitive ? data->normgc : data->graygc),
344: textx, texty, data->text, strlen(data->text));
345: }
346:
347: extern void Destroy();
348:
349: /*
350: *
351: * Generic widget event handler
352: *
353: */
354:
355: static XtEventReturnCode EventHandler(event, eventdata)
356: XEvent *event;
357: caddr_t eventdata;
358: {
359: WidgetData data = (WidgetData) eventdata;
360: XtActionTokenPtr actionList;
361: CommandProc proc;
362:
363: data->eventlevels++;
364: switch (event->type) {
365: case ConfigureNotify:
366: data->x = event->xconfigure.x;
367: data->y = event->xconfigure.y;
368: data->width = event->xconfigure.width;
369: data->height = event->xconfigure.height;
370: data->borderWidth = event->xconfigure.border_width;
371: /* Redisplay(data);*/
372: break;
373:
374: case DestroyNotify: Destroy(data); break;
375:
376: case Expose:
377: if (event->xexpose.count == 0)
378: Redisplay(data);
379: break;
380: default:
381: if (!data->sensitive) break;
382: actionList =
383: (XtActionTokenPtr) XtTranslateEvent(event, data->state);
384: for ( ; actionList != NULL; actionList = actionList->next) {
385: if (actionList->type == XttokenAction) {
386: proc = (CommandProc) XtInterpretAction(
387: data->dpy, data->state,
388: actionList->value.action);
389: (*(proc))(data);
390: }
391: }
392: break;
393: }
394: data->eventlevels--;
395: if (data->needsfreeing && data->eventlevels == 0) {
396: XtClearEventHandlers(data->dpy, data->mywin);
397: (void) XDeleteContext(data->dpy, data->mywin, widgetContext);
398: XtFree((char*)data->text);
399: XtFree((char *) data);
400: }
401:
402: return (XteventHandled);
403: }
404:
405: /*
406: *
407: * Widget hilight event handler
408: *
409: */
410:
411: static void Highlight(data)
412: WidgetData data;
413: {
414: data->highlighted = TRUE;
415: Redisplay(data);
416: }
417:
418: /*
419: *
420: * Widget un-hilight event handler
421: *
422: */
423:
424: static void UnHighlight(data)
425: WidgetData data;
426: {
427: data->highlighted = FALSE;
428: Redisplay(data);
429: }
430:
431: /*
432: *
433: * Widget set event handler
434: *
435: */
436:
437: static void Set(data)
438: WidgetData data;
439: {
440: data->set = TRUE;
441: Redisplay(data);
442: }
443:
444: /*
445: *
446: * Widget un-set event handler
447: *
448: */
449:
450: static void UnSet(data)
451: WidgetData data;
452: {
453: data->set = FALSE;
454: Redisplay(data);
455: }
456:
457: /*
458: *
459: * Widget notify event handler
460: *
461: */
462:
463: static void Notify(data)
464: WidgetData data;
465: {
466: data->notifying = TRUE;
467: XFlush(data->dpy);
468: data->proc(data->tag);
469: data->notifying = FALSE;
470: }
471:
472: /*
473: *
474: * Destroy the widget; the window's been destroyed already.
475: *
476: */
477:
478: static void Destroy(data)
479: WidgetData data;
480: {
481: data->needsfreeing = TRUE;
482: }
483:
484: /****************************************************************
485: *
486: * Public Procedures
487: *
488: ****************************************************************/
489:
490: Window XtCommandCreate(dpy, parent, args, argCount)
491: Display *dpy;
492: Window parent;
493: ArgList args;
494: int argCount;
495: {
496: WidgetData data;
497: XrmNameList names;
498: XrmClassList classes;
499: Drawable root;
500: Position x, y;
501: unsigned int depth;
502: unsigned long valuemask;
503: XSetWindowAttributes wvals;
504:
505: static XtActionsRec actionsTable[] = {
506: {"set", (caddr_t)Set},
507: {"unset", (caddr_t)UnSet},
508: {"highlight", (caddr_t)Highlight},
509: {"unhighlight", (caddr_t)UnHighlight},
510: {"notify", (caddr_t)Notify},
511: {NULL, NULL}
512: };
513:
514: if (!initialized) CommandInitialize ();
515:
516: data = (WidgetData) XtMalloc (sizeof (WidgetDataRec));
517:
518: /* Set Default Values */
519: globaldata = globalinit;
520: globaldata.dpy = dpy;
521: XtGetResources(dpy, resources, XtNumber(resources), args, argCount, parent,
522: "command", "Command", &names, &classes);
523: *data = globaldata;
524:
525: data->state = (TranslationPtr) XtSetActionBindings(
526: data->dpy,
527: data->eventTable, actionsTable, (caddr_t) Ignore);
528:
529: if (data->fontstruct == NULL)
530: data->fontstruct = globalinit.fontstruct =
531: XLoadQueryFont(data->dpy, "variable");
532:
533: if (data->text == NULL)
534: data->text = XrmNameToAtom(names[XrmNameListLength(names) - 1]);
535: data->text = strcpy( XtMalloc ((unsigned) strlen(data->text) + 1),
536: data->text);
537:
538: /* obtain text dimensions and calculate the window size */
539: SetTextWidthAndHeight(data);
540: if (data->width == 0) data->width = data->twidth + 2*data->ibw;
541: if (data->height == 0) data->height = data->theight + 2*data->ibh;
542:
543: wvals.background_pixel = data->bgpixel;
544: wvals.border_pixel = data->brpixel;
545: wvals.bit_gravity = CenterGravity;
546:
547: valuemask = CWBackPixel | CWBorderPixel | CWBitGravity;
548:
549: if (data->mywin != NULL) {
550: /* set global data from window parameters */
551: if (XGetGeometry(data->dpy, data->mywin, &root, &x, &y,
552: &(data->width), &(data->height), &(data->borderWidth),
553: &depth)) {
554: XReparentWindow(data->dpy, data->mywin, parent, data->x,data->y);
555: XChangeWindowAttributes(data->dpy, data->mywin,
556: valuemask, &wvals);
557: } else
558: data->mywin = NULL;
559: }
560: if (data->mywin == NULL)
561: data->mywin = XCreateWindow(data->dpy, parent, data->x, data->y,
562: data->width, data->height, data->borderWidth,
563: 0, InputOutput, (Visual *)CopyFromParent,
564: valuemask, &wvals);
565:
566: BuildGcs(data);
567:
568: XtSetNameAndClass(data->dpy, data->mywin, names, classes);
569: XrmFreeNameList(names);
570: XrmFreeClassList(classes);
571:
572: (void)XSaveContext(data->dpy, data->mywin, widgetContext, (caddr_t) data);
573:
574: /* set handler for expose, resize, and message events */
575: /* HACK -- translation mgr should somehow do the event selection, not us! */
576: XtSetEventHandler (data->dpy, data->mywin, (XtEventHandler)EventHandler,
577: StructureNotifyMask | ExposureMask | ButtonPressMask
578: | ButtonReleaseMask | EnterWindowMask
579: | LeaveWindowMask | KeyPressMask,
580: (caddr_t)data);
581:
582: return (data->mywin);
583: }
584:
585:
586: /*
587: * Get Attributes
588: */
589:
590: void XtCommandGetValues(dpy, window, args, argCount)
591: Display *dpy;
592: Window window;
593: ArgList args;
594: int argCount;
595: {
596: WidgetData data;
597: data = DataFromWindow(dpy, window);
598: if (data) {
599: globaldata = *data;
600: XtGetValues(resources, XtNumber(resources), args, argCount);
601: }
602: }
603:
604:
605:
606: /*
607: * Set Attributes
608: */
609:
610: void XtCommandSetValues(dpy, window, args, argCount)
611: Display *dpy;
612: Window window;
613: ArgList args;
614: int argCount;
615: {
616: WidgetData data;
617: data = DataFromWindow(dpy, window);
618: if (data == NULL) return;
619:
620: globaldata = *data;
621: XtSetValues(resources, XtNumber(resources), args, argCount);
622:
623: if (strcmp (data->text, globaldata.text)
624: || data->fontstruct != globaldata.fontstruct) {
625: XtGeometryReturnCode reply;
626: WindowBox reqbox, replybox;
627:
628: globaldata.text = strcpy(
629: XtMalloc ((unsigned) strlen(globaldata.text) + 1),
630: globaldata.text);
631: XtFree ((char *) data->text);
632:
633: /* obtain text dimensions and calculate the window size */
634: SetTextWidthAndHeight(&globaldata);
635: reqbox.width = globaldata.twidth + 2*globaldata.ibw;
636: reqbox.height = globaldata.theight + 2*globaldata.ibh;
637: reply = XtMakeGeometryRequest(globaldata.dpy, globaldata.mywin, XtgeometryResize,
638: &reqbox, &replybox);
639: if (reply == XtgeometryAlmost) {
640: reqbox = replybox;
641: (void) XtMakeGeometryRequest(globaldata.dpy, globaldata.mywin, XtgeometryResize,
642: &reqbox, &replybox);
643: }
644: }
645:
646: if (data->fgpixel != globaldata.fgpixel ||
647: data->bgpixel != globaldata.bgpixel ||
648: data->fontstruct != globaldata.fontstruct) BuildGcs(&globaldata);
649: *data = globaldata;
650: if (!data->sensitive) data->set = data->highlighted = FALSE;
651: Redisplay (data);
652: }
653:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.