aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2014-09-20 00:16:30 +0000
committerDimitri Sokolyuk <demon@dim13.org>2014-09-20 00:16:30 +0000
commit22751b71809fca1bf028adcfb4157b0ffd84543a (patch)
tree1da4372e9395974f1e89002ccf6665f861f7c14f
initial import of demomonitor example
-rw-r--r--BarDisplay.c209
-rw-r--r--BarDisplay.h19
-rw-r--r--BarDisplayP.h31
-rw-r--r--DemoMonitor2
-rw-r--r--Graph.c317
-rw-r--r--Graph.h22
-rw-r--r--GraphDisplay.c134
-rw-r--r--GraphDisplay.h7
-rw-r--r--GraphDisplayP.h35
-rw-r--r--GraphP.h33
-rw-r--r--Makefile11
-rw-r--r--README2
-rw-r--r--demomonitor.c134
13 files changed, 956 insertions, 0 deletions
diff --git a/BarDisplay.c b/BarDisplay.c
new file mode 100644
index 0000000..7deba69
--- /dev/null
+++ b/BarDisplay.c
@@ -0,0 +1,209 @@
+#include <stdio.h>
+#include <string.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "BarDisplayP.h"
+#include "GraphP.h"
+
+#define Offset(field) XtOffsetOf(BarDisplayRec, barDisplay.field)
+static XtResource resources[] = {
+ { XtNspace, XtCSpace, XtRDimension, sizeof(Dimension),
+ Offset(space), XtRImmediate, (XtPointer) 5 },
+ { XtNdefaultGraphWidth, XtCDefaultGraphWidth,
+ XtRDimension, sizeof(Dimension),
+ Offset(default_graph_width), XtRImmediate, (XtPointer) 200 },
+ { XtNformat, XtCFormat, XtRString, sizeof(String),
+ Offset(format), XtRString, "%g" },
+};
+#undef Offset
+
+static void Initialize();
+static void Redisplay();
+static void ComputeSize();
+static Boolean SetValues();
+
+#define Superclass (&graphDisplayClassRec)
+BarDisplayClassRec barDisplayClassRec = {
+ /* object */
+ {
+ /* superclass */ (WidgetClass) Superclass,
+ /* class_name */ "BarDisplay",
+ /* widget_size */ sizeof(BarDisplayRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* obj1 */ NULL,
+ /* obj2 */ NULL,
+ /* obj3 */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* obj4 */ 0,
+ /* obj5 */ 0,
+ /* obj6 */ 0,
+ /* obj7 */ 0,
+ /* destroy */ NULL,
+ /* obj8 */ NULL,
+ /* obj9 */ NULL,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* obj10 */ NULL,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback offsets */ NULL,
+ /* obj12 */ NULL,
+ /* obj13 */ NULL,
+ /* obj14 */ NULL,
+ /* extension */ NULL,
+ },
+ /* graphDisplay */
+ {
+ /* compute_size */ ComputeSize,
+ /* expose */ Redisplay,
+ /* extension */ NULL,
+ },
+ /* barDisplay */
+ {
+ /* extension */ NULL,
+ },
+};
+
+WidgetClass barDisplayObjectClass = (WidgetClass) &barDisplayClassRec;
+
+static void
+Initialize(Widget request,
+ Widget new,
+ ArgList args,
+ Cardinal * num_args)
+{
+ BarDisplayObject bd = (BarDisplayObject) new;
+
+ bd->barDisplay.format = XtNewString(bd->barDisplay.format);
+}
+
+static Boolean
+SetValues(Widget old,
+ Widget req,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ BarDisplayObject oldbd = (BarDisplayObject) old;
+ BarDisplayObject newbd = (BarDisplayObject) new;
+
+#define NE(field) (oldbd->barDisplay.field != newbd->barDisplay.field)
+
+ if (NE(space) || NE(format)) {
+ if (XtIsRealized(XtParent((Widget)newbd)))
+ XClearArea(XtDisplayOfObject(new),
+ XtWindowOfObject(new), 0, 0, 0, 0, True);
+#undef NE
+ }
+
+ return False;
+}
+
+static void
+ComputeLabelDimensions(BarDisplayObject bd,
+ Dimension *label_w,
+ Dimension *total_w,
+ Dimension *height)
+{
+ XFontStruct *fs = bd->graphDisplay.font;
+ int i;
+ int width;
+ GraphWidget parent = (GraphWidget) XtParent((Widget) bd);
+ char buf[100];
+
+ *label_w = *total_w = 0;
+ if (parent->graph.labels != NULL) {
+ for (i = 0; i < parent->graph.num_entries; i++) {
+ width = XTextWidth(fs, parent->graph.labels[i],
+ strlen(parent->graph.labels[i]));
+ if (width > *label_w)
+ *label_w = width;
+ }
+ }
+
+ for (i = 0; i < parent->graph.num_entries; i++) {
+ snprintf(buf, sizeof(buf), bd->barDisplay.format,
+ (float)parent->graph.values[i] / parent->graph.scale);
+ width = XTextWidth(fs, buf, strlen(buf));
+ if (width > *total_w)
+ *total_w = width;
+ }
+
+ *total_w += *label_w;
+ *height = fs->max_bounds.ascent + fs->max_bounds.descent;
+}
+
+static void
+ComputeSize(GraphWidget w)
+{
+ BarDisplayObject bd = (BarDisplayObject) w->composite.children[0];
+ Dimension label_width, total_width, label_height;
+
+ ComputeLabelDimensions(bd, &label_width, &total_width, &label_height);
+
+ if (w->core.width == 0) {
+ w->core.width = 4 * bd->barDisplay.space + total_width +
+ bd->barDisplay.default_graph_width;
+ }
+
+ if (w->core.height == 0) {
+ w->core.height = w->graph.num_entries * (bd->barDisplay.space +
+ label_height) + bd->barDisplay.space;
+ }
+}
+
+static void
+Redisplay(GraphWidget w,
+ XEvent *event,
+ Region region)
+{
+ BarDisplayObject bd = (BarDisplayObject) w->composite.children[0];
+ Dimension label_width, total_width, label_height;
+ Boolean displayBars;
+ int i;
+ int x, y, bar_width;
+ char buf[100];
+ int *values = w->graph.values;
+ String *labels = w->graph.labels;
+
+ ComputeLabelDimensions(bd, &label_width, &total_width, &label_height);
+
+ bar_width = w->core.width - total_width - 4 * bd->barDisplay.space;
+ displayBars = (bar_width > (int)bd->barDisplay.space);
+
+ y = bd->barDisplay.space;
+ for (i = 0; i < w->graph.num_entries; i++) {
+ if (labels != NULL) {
+ XDrawString(XtDisplay(w), XtWindow(w),
+ bd->graphDisplay.gc,
+ bd->barDisplay.space,
+ y + bd->graphDisplay.font->max_bounds.ascent,
+ labels[i], strlen(labels[i]));
+ x = label_width + 2 * bd->barDisplay.space;
+ } else
+ x = 0;
+
+ if (displayBars) {
+ XFillRectangle(XtDisplay(w), XtWindow(w),
+ bd->graphDisplay.gc, x, y,
+ bar_width * values[i] / w->graph.max_value,
+ bd->graphDisplay.font->max_bounds.ascent);
+ x += bar_width * values[i] / w->graph.max_value +
+ bd->barDisplay.space;
+ }
+
+ snprintf(buf, sizeof(buf), bd->barDisplay.format,
+ (float) values[i] / w->graph.scale);
+ XDrawString(XtDisplay(w), XtWindow(w), bd->graphDisplay.gc,
+ x, y + bd->graphDisplay.font->max_bounds.ascent,
+ buf, strlen(buf));
+ y += label_height + bd->barDisplay.space;
+ }
+}
diff --git a/BarDisplay.h b/BarDisplay.h
new file mode 100644
index 0000000..2f4e0a4
--- /dev/null
+++ b/BarDisplay.h
@@ -0,0 +1,19 @@
+#ifndef _BarDisplay_h
+#define _BarDisplay_h
+
+#include "GraphDisplay.h"
+
+#if 0
+#define XtNspace "space"
+#define XtCSpace "Space"
+#endif
+#define XtNdefaultGraphWidth "defaultGraphWidth"
+#define XtCDefaultGraphWidth "DefaultGraphWidth"
+#define XtNformat "format"
+#define XtCFormat "Format"
+
+
+extern WidgetClass barDisplayObjectClass;
+typedef struct _BarDisplayRec *BarDisplayObject;
+
+#endif
diff --git a/BarDisplayP.h b/BarDisplayP.h
new file mode 100644
index 0000000..ea8359c
--- /dev/null
+++ b/BarDisplayP.h
@@ -0,0 +1,31 @@
+#ifndef _BarDisplayP_h
+#define _BarDisplayP_h
+
+#include "BarDisplay.h"
+#include "GraphDisplayP.h"
+
+typedef struct {
+ Dimension space;
+ Dimension default_graph_width;
+ String format;
+} BarDisplayPart;
+
+typedef struct _BarDisplayRec {
+ ObjectPart object;
+ GraphDisplayPart graphDisplay;
+ BarDisplayPart barDisplay;
+} BarDisplayRec;
+
+typedef struct {
+ XtPointer extension;
+} BarDisplayClassPart;
+
+typedef struct _BarDisplayClassRec {
+ ObjectClassPart object_class;
+ GraphDisplayClassPart graphDisplay_class;
+ BarDisplayClassPart barDisplay_class;
+} BarDisplayClassRec, *BarDisplayObjectClass;
+
+extern BarDisplayClassRec barDisplayClassRec;
+
+#endif
diff --git a/DemoMonitor b/DemoMonitor
new file mode 100644
index 0000000..23c5592
--- /dev/null
+++ b/DemoMonitor
@@ -0,0 +1,2 @@
+*graph.labels: User\nSystem\nIdle
+*graph.maxValue: 100
diff --git a/Graph.c b/Graph.c
new file mode 100644
index 0000000..260c5d7
--- /dev/null
+++ b/Graph.c
@@ -0,0 +1,317 @@
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "GraphP.h"
+#include "GraphDisplayP.h"
+
+#define Offset(field) XtOffsetOf(GraphRec, graph.field)
+static XtResource resources[] = {
+ { XtNnumEntries, XtCNumEntries, XtRInt, sizeof(int),
+ Offset(num_entries), XtRImmediate, (XtPointer) 0 },
+ { XtNlabels, XtCLabels, XtRStringTable, sizeof(String *),
+ Offset(labels), XtRImmediate, (XtPointer) NULL },
+ { XtNvalues, XtCValues, XtRPointer, sizeof(int *),
+ Offset(values), XtRImmediate, (XtPointer) NULL },
+ { XtNmaxValue, XtCMaxValue, XtRInt, sizeof(int),
+ Offset(max_value), XtRImmediate, (XtPointer) 100 },
+ { XtNscale, XtCScale, XtRInt, sizeof(int),
+ Offset(scale), XtRImmediate, (XtPointer) 1 },
+};
+#undef Offset
+
+static void ClassInitialize();
+static void Initialize();
+static void Redisplay();
+static void Destroy();
+static void Resize();
+static void Realize();
+static void InsertChild();
+static Boolean SetValues();
+
+static CompositeClassExtensionRec compositeExtension = {
+ /* next_extension */ NULL,
+ /* recort_type */ NULLQUARK,
+ /* version */ XtCompositeExtensionVersion,
+ /* record_size */ sizeof(CompositeClassExtensionRec),
+ /* accepts_objects */ True,
+};
+
+#define Superclass (&compositeClassRec)
+GraphClassRec graphClassRec = {
+ /* core */
+ {
+ /* superclass */ (WidgetClass) Superclass,
+ /* class_name */ "Graph",
+ /* widget_size */ sizeof(GraphRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ True,
+ /* compress_exposure */ XtExposeCompressMultiple,
+ /* compress_enterleave */ True,
+ /* visible_interest */ False,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ NULL,
+ /* display_accelerator */ NULL,
+ /* extension */ NULL,
+ },
+ /* composite */
+ {
+ /* geometry_manager */ NULL,
+ /* change_managed */ NULL,
+ /* insert_child */ InsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ &compositeExtension,
+ },
+ /* graph */
+ {
+ /* extension */ NULL,
+ },
+};
+
+WidgetClass graphWidgetClass = (WidgetClass) &graphClassRec;
+
+static Boolean
+CvtStringToStringList(Display *dpy,
+ XrmValuePtr args,
+ Cardinal *num_args,
+ XrmValuePtr from,
+ XrmValuePtr to,
+ XtPointer *data)
+{
+ int i, count = 1;
+ char *ch, *start = from->addr;
+ static String *list;
+ int len;
+
+ if (*num_args != 0) {
+ XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
+ "cvtStringToStringList", "wrongParameters",
+ "XtToolkitError",
+ "String to string list conversion needs no extra arguments",
+ NULL, NULL);
+ }
+
+ if (to->addr != NULL && to->size < sizeof(String *)) {
+ to->size = sizeof(String *);
+ return False;
+ }
+
+ if (start == NULL || *start == '\0')
+ list = NULL;
+ else {
+ for (ch = start; *ch != '\0'; ch++) {
+ if (*ch == '\n')
+ count++;
+ }
+
+ list = (String *)XtCalloc(count + 1, sizeof(String));
+ for (i = 0; i < count; i++) {
+ for (ch = start; *ch != '\n' && *ch != '\0'; ch++)
+ ;
+ len = ch - start;
+ list[i] = XtMalloc(len + 1);
+ strncpy(list[i], start, len);
+ list[i][len] = '\0';
+ start = ch + 1;
+ }
+ }
+ if (to->addr == NULL)
+ to->addr = (caddr_t)&list;
+ else
+ *(String **)to->addr = list;
+ to->size = sizeof(String *);
+
+ return True;
+}
+
+static void
+StringListDestructor(XtAppContext app,
+ XrmValuePtr to,
+ XtPointer converter_data,
+ XrmValuePtr args,
+ Cardinal *num_args)
+{
+ String *list = (String *)to->addr;
+ String *entry;
+
+ for (entry = list; entry != NULL; entry++)
+ XtFree((XtPointer)entry);
+
+ XtFree((XtPointer)list);
+}
+
+static void
+ClassInitialize()
+{
+ XtSetTypeConverter(XtRString, XtRStringTable,
+ CvtStringToStringList, NULL, 0,
+ XtCacheAll|XtCacheRefCount, StringListDestructor);
+}
+
+static void
+Initialize(Widget request,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ GraphWidget gw = (GraphWidget) new;
+ int *values;
+ int i;
+ String label;
+
+ values = (int *)XtCalloc(gw->graph.num_entries, sizeof(int));
+ for (i = 0; i < gw->graph.num_entries; i++)
+ values[i] = gw->graph.values[i];
+ gw->graph.values = values;
+
+ if (gw->graph.labels != NULL)
+ for (i = 0; i < gw->graph.num_entries; i++)
+ label = gw->graph.labels[i];
+}
+
+static Boolean
+SetValues(Widget old,
+ Widget req,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ GraphWidget oldgraph = (GraphWidget) old;
+ GraphWidget newgraph = (GraphWidget) new;
+ int *values;
+ String label;
+ int i;
+
+#define NE(field) (newgraph->graph.field != oldgraph->graph.field)
+#define EQ(field) (newgraph->graph.field == oldgraph->graph.field)
+
+ if (NE(values)) {
+ values = (int *)XtCalloc(newgraph->graph.num_entries, sizeof(int));
+ XtFree((XtPointer)oldgraph->graph.values);
+ for (i = 0; i < newgraph->graph.num_entries; i++)
+ values[i] = newgraph->graph.values[i];
+ newgraph->graph.values = values;
+ return True;
+ }
+
+ if (NE(num_entries) && (EQ(labels) || EQ(values))) {
+ XtAppErrorMsg(XtWidgetToApplicationContext(new),
+ "counterError", "numEntries", "WidgetError",
+ "Number of graph entries changed but not labels of values",
+ NULL, NULL);
+ }
+
+ if (NE(labels) && newgraph->graph.labels != NULL)
+ for (i = 0; i < newgraph->graph.num_entries; i++)
+ label = newgraph->graph.labels[i];
+
+ return NE(num_entries) || NE(labels) || NE(max_value);
+#undef NE
+}
+
+static void
+Destroy(Widget w)
+{
+ GraphWidget gw = (GraphWidget) w;
+
+ XtFree((XtPointer)gw->graph.values);
+}
+
+static void
+InsertChild(Widget w)
+{
+ String params[2];
+ Cardinal num_params;
+ CompositeWidget parent = (CompositeWidget) XtParent(w);
+ GraphDisplayObjectClass childClass;
+
+ if (!XtIsSubclass(w, graphDisplayObjectClass)) {
+ params[0] = XtClass(w)->core_class.class_name;
+ params[1] = XtClass(parent)->core_class.class_name;
+ num_params = 2;
+ XtAppErrorMsg(XtWidgetToApplicationContext(w),
+ "childError", "number", "WidgetError",
+ "Children of class %s cannot be added to %n widgets",
+ params, &num_params);
+ }
+
+ if (parent->composite.num_children != 0) {
+ params[0] = XtClass(parent)->core_class.class_name;
+ num_params = 1;
+ XtAppErrorMsg(XtWidgetToApplicationContext(w),
+ "childError", "number", "WidgetError",
+ "%s widgets can only take one child",
+ params, &num_params);
+ }
+
+ (*((CompositeWidgetClass)(graphWidgetClass->
+ core_class.superclass))->composite_class.insert_child)(w);
+
+ childClass = (GraphDisplayObjectClass)XtClass(w);
+ if (childClass->graphDisplay_class.compute_size != NULL)
+ (*childClass->graphDisplay_class.compute_size)(parent);
+}
+
+static void
+Realize(Widget w,
+ XtValueMask *valueMask,
+ XSetWindowAttributes *attributes)
+{
+ GraphWidget gw = (GraphWidget) w;
+ String params[2];
+ Cardinal num_params;
+
+ if (gw->composite.num_children != 1) {
+ params[0] = XtClass(w)->core_class.class_name;
+ num_params = 1;
+ XtAppErrorMsg(XtWidgetToApplicationContext(w),
+ "childError", "number", "WidgetError",
+ "%s widgets must have exactly one child",
+ params, &num_params);
+ }
+
+ (*graphWidgetClass->core_class.superclass->core_class.realize)(w,
+ valueMask, attributes);
+}
+
+static void
+Redisplay(Widget w,
+ XEvent *event,
+ Region region)
+{
+ GraphWidget gw = (GraphWidget) w;
+ GraphDisplayObject d = (GraphDisplayObject) gw->composite.children[0];
+ GraphDisplayObjectClass childClass;
+
+ childClass = (GraphDisplayObjectClass)XtClass((Widget)d);
+ if (childClass->graphDisplay_class.expose != NULL)
+ (*childClass->graphDisplay_class.expose)(w, event, region);
+}
+
+static void
+Resize(Widget w)
+{
+ if (XtIsRealized(w)) {
+ XClearWindow(XtDisplay(w), XtWindow(w));
+ (*(XtClass(w)->core_class.expose))(w, NULL, NULL);
+ }
+}
+
diff --git a/Graph.h b/Graph.h
new file mode 100644
index 0000000..d4da9b2
--- /dev/null
+++ b/Graph.h
@@ -0,0 +1,22 @@
+#ifndef _Graph_h
+#define _Graph_h
+
+// #include <X11/Intrinsic.h>
+
+#define XtNnumEntries "numEntries"
+#define XtCNumEntries "NumEntries"
+#define XtNlabels "labels"
+#define XtCLabels "Labels"
+#define XtNvalues "values"
+#define XtCValues "Values"
+#define XtNmaxValue "maxValue"
+#define XtCMaxValue "MaxValue"
+#define XtNscale "scale"
+#define XtCScale "Scale"
+
+extern WidgetClass graphWidgetClass;
+
+typedef struct _GraphRec *GraphWidget;
+typedef struct _GraphClassRec *GraphWidgetClass;
+
+#endif
diff --git a/GraphDisplay.c b/GraphDisplay.c
new file mode 100644
index 0000000..950667b
--- /dev/null
+++ b/GraphDisplay.c
@@ -0,0 +1,134 @@
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include "GraphDisplayP.h"
+
+#define Offset(field) XtOffsetOf(GraphDisplayRec, graphDisplay.field)
+static XtResource resources[] = {
+ { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ Offset(font), XtRString, (XtPointer)XtDefaultFont },
+ { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ Offset(foreground), XtRString, (XtPointer)XtDefaultForeground },
+};
+#undef Offset
+
+static void ClassPartInitialize();
+static void Initialize();
+static void Destroy();
+static Boolean SetValues();
+
+#define Superclass (&objectClassRec)
+GraphDisplayClassRec graphDisplayClassRec = {
+ /* object */
+ {
+ /* superclass */ (WidgetClass) Superclass,
+ /* class_name */ "GraphDisplay",
+ /* widget_size */ sizeof(GraphDisplayRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize */ ClassPartInitialize,
+ /* class_inited */ False,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* obj1 */ NULL,
+ /* obj2 */ NULL,
+ /* obj3 */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* obj4 */ 0,
+ /* obj5 */ 0,
+ /* obj6 */ 0,
+ /* obj7 */ 0,
+ /* destroy */ Destroy,
+ /* obj8 */ 0,
+ /* obj9 */ 0,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* obj10 */ NULL,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback offsets */ NULL,
+ /* obj12 */ NULL,
+ /* obj13 */ NULL,
+ /* obj14 */ NULL,
+ /* extension */ NULL,
+ },
+ /* graphDisplay */
+ {
+ /* compute_size */ NULL,
+ /* expose */ NULL,
+ /* extension */ NULL,
+ },
+};
+
+WidgetClass graphDisplayObjectClass = (WidgetClass) &graphDisplayClassRec;
+
+static void
+ClassPartInitialize(WidgetClass widgetClass)
+{
+ GraphDisplayObjectClass wc = (GraphDisplayObjectClass) widgetClass;
+ GraphDisplayObjectClass super =
+ (GraphDisplayObjectClass) wc->object_class.superclass;
+
+ if (wc->graphDisplay_class.compute_size == InheritComputeSize)
+ wc->graphDisplay_class.compute_size =
+ super->graphDisplay_class.compute_size;
+ if (wc->graphDisplay_class.expose == XtInheritExpose)
+ wc->graphDisplay_class.expose =
+ super->graphDisplay_class.expose;
+}
+
+static GC
+GetGC(GraphDisplayObject gd)
+{
+ XGCValues values;
+
+ values.foreground = gd->graphDisplay.foreground;
+ values.font = gd->graphDisplay.font->fid;
+
+ return XtGetGC(XtParent((Widget)gd), GCForeground|GCFont, &values);
+}
+
+static void
+Initialize(Widget request,
+ Widget new,
+ ArgList args,
+ Cardinal * num_args)
+{
+ GraphDisplayObject gd = (GraphDisplayObject) new;
+
+ gd->graphDisplay.gc = GetGC(gd);
+}
+
+static Boolean
+SetValues(Widget old,
+ Widget req,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ GraphDisplayObject oldgd = (GraphDisplayObject) old;
+ GraphDisplayObject newgd = (GraphDisplayObject) new;
+
+#define NE(field) (newgd->field != oldgd->field)
+
+ if (NE(graphDisplay.foreground) || NE(graphDisplay.font->fid)) {
+ XtReleaseGC(new, oldgd->graphDisplay.gc);
+ newgd->graphDisplay.gc = GetGC(newgd);
+ }
+
+ if (XtIsRealized(XtParent((Widget)newgd)))
+ XClearArea(XtDisplayOfObject(new),
+ XtWindowOfObject(new), 0, 0, 0, 0, True);
+#undef NE
+
+ return False;
+}
+
+static void
+Destroy(Widget w)
+{
+ GraphDisplayObject gd = (GraphDisplayObject) w;
+
+ XtReleaseGC(XtParent(w), gd->graphDisplay.gc);
+}
diff --git a/GraphDisplay.h b/GraphDisplay.h
new file mode 100644
index 0000000..2b05541
--- /dev/null
+++ b/GraphDisplay.h
@@ -0,0 +1,7 @@
+#ifndef _GraphDisplay_h
+#define _GraphDisplay_h
+
+extern WidgetClass graphDisplayObjectClass;
+typedef struct _GraphDisplayRec *GraphDisplayObject;
+
+#endif
diff --git a/GraphDisplayP.h b/GraphDisplayP.h
new file mode 100644
index 0000000..f4b85ec
--- /dev/null
+++ b/GraphDisplayP.h
@@ -0,0 +1,35 @@
+#ifndef _GraphDisplayP_h
+#define _GraphDisplayP_h
+
+// #include <X11/CoreP.h>
+#include "GraphDisplay.h"
+
+typedef struct {
+ Pixel foreground;
+ XFontStruct *font;
+ GC gc;
+} GraphDisplayPart;
+
+typedef struct _GraphDisplayRec {
+ ObjectPart object;
+ GraphDisplayPart graphDisplay;
+} GraphDisplayRec;
+
+typedef void (*ComputeSizeProc)();
+
+typedef struct {
+ ComputeSizeProc compute_size;
+ XtExposeProc expose;
+ XtPointer extension;
+} GraphDisplayClassPart;
+
+typedef struct _GraphDisplayClassRec {
+ ObjectClassPart object_class;
+ GraphDisplayClassPart graphDisplay_class;
+} GraphDisplayClassRec, *GraphDisplayObjectClass;
+
+extern GraphDisplayClassRec graphDisplayClassRec;
+
+#define InheritComputeSize ((ComputeSizeProc) _XtInherit)
+
+#endif
diff --git a/GraphP.h b/GraphP.h
new file mode 100644
index 0000000..f6af739
--- /dev/null
+++ b/GraphP.h
@@ -0,0 +1,33 @@
+#ifndef _GraphP_h
+#define _GraphP_h
+
+// #include <X11/CoreP.h>
+#include "Graph.h"
+
+typedef struct {
+ int num_entries;
+ String *labels;
+ int *values;
+ int max_value;
+ int scale;
+} GraphPart;
+
+typedef struct _GraphRec {
+ CorePart core;
+ CompositePart composite;
+ GraphPart graph;
+} GraphRec;
+
+typedef struct {
+ XtPointer extension;
+} GraphClassPart;
+
+typedef struct _GraphClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ GraphClassPart graph_class;
+} GraphClassRec;
+
+extern GraphClassRec graphClassRec;
+
+#endif
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..33e6ed2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+PROG= demomonitor
+SRCS= demomonitor.c Graph.c GraphDisplay.c BarDisplay.c
+NOMAN=
+LIBS= xt
+PCCF!= pkg-config --cflags ${LIBS}
+CFLAGS+=${PCCF}
+PCLD!= pkg-config --libs ${LIBS}
+LDADD+= ${PCLD}
+DEBUG+= -Wall -ggdb
+
+.include <bsd.prog.mk>
diff --git a/README b/README
new file mode 100644
index 0000000..d4968d4
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+DemoMonitor example from `X Window System Toolkit: the complete programmers's
+guide and specification' by Paul J. Asente and Ralph R. Swick
diff --git a/demomonitor.c b/demomonitor.c
new file mode 100644
index 0000000..ae60dc6
--- /dev/null
+++ b/demomonitor.c
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include "Graph.h"
+#include "BarDisplay.h"
+
+XtAppContext app;
+Widget graph;
+int *fields;
+
+void Timer();
+void CreateGraphWidget();
+void GetGraphData();
+void quit();
+
+typedef struct {
+ int timeout;
+ int num_fields;
+ String command;
+} OptionsRec;
+
+OptionsRec options;
+
+#define Offset(field) XtOffsetOf(OptionsRec, field)
+XtResource resources[] = {
+ { "interval", "Interval", XtRInt, sizeof(int),
+ Offset(timeout), XtRImmediate, (XtPointer) 5 },
+ { "numFields", "NumFields", XtRInt, sizeof(int),
+ Offset(num_fields), XtRImmediate, (XtPointer) 3 },
+ { "command", "Command", XtRString, sizeof(String),
+ Offset(command), XtRString,
+ "vmstat 1 2 | awk '{if (NR == 4) print $(NF-2), $(NF-1), $(NF)}'"}
+};
+#undef Offset
+
+XrmOptionDescRec optionsDesc[] = {
+ { "-interval", "*interval", XrmoptionSepArg, (XtPointer) NULL },
+};
+
+String fallback_resources[] = {
+ "*graph.labels: User\\nSystem\\nIdle",
+ "*graph.maxValue: 100",
+ NULL
+};
+
+XtActionsRec actionsList[] = {
+ { "quit", quit },
+};
+
+void
+quit()
+{
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ Widget toplevel;
+
+ toplevel = XtAppInitialize(&app, "DemoMonitor",
+ optionsDesc, XtNumber(optionsDesc), &argc, argv,
+ fallback_resources, NULL, 0);
+ XtAppAddActions(app, actionsList, XtNumber(actionsList));
+ XtOverrideTranslations(toplevel,
+ XtParseTranslationTable("<Key>q: quit()"));
+
+ XtGetApplicationResources(toplevel, (XtPointer)&options,
+ resources, XtNumber(resources), NULL, 0);
+ fields = (int *)XtCalloc(options.num_fields, sizeof(int));
+
+ CreateGraphWidget(toplevel);
+ XtRealizeWidget(toplevel);
+ XtAppAddTimeOut(app, options.timeout * 1000, Timer, NULL);
+ XtAppMainLoop(app);
+
+ return 0;
+}
+
+void
+CreateGraphWidget(Widget parent)
+{
+ Arg args[10];
+ int n;
+
+ GetGraphData();
+
+ n = 0;
+ XtSetArg(args[n], XtNnumEntries, options.num_fields); n++;
+ XtSetArg(args[n], XtNvalues, fields); n++;
+ graph = XtCreateManagedWidget("graph", graphWidgetClass, parent,
+ args, n);
+ XtCreateWidget("bar", barDisplayObjectClass, graph, NULL, 0);
+}
+
+void
+Timer(XtPointer client_data, XtIntervalId *id)
+{
+ Arg args[10];
+ int n;
+
+ GetGraphData();
+
+ n = 0;
+ XtSetArg(args[n], XtNvalues, fields); n++;
+ XtSetValues(graph, args, n);
+
+ XtAppAddTimeOut(app, options.timeout * 1000, Timer, NULL);
+}
+
+void
+GetGraphData()
+{
+ int status;
+ FILE *f;
+ int i;
+
+ f = popen(options.command, "r");
+
+ for (i = 0; i < options.num_fields; i++) {
+ status = fscanf(f, "%d", &fields[i]);
+ if (status != 1) {
+ XtAppWarningMsg(app, "noData", "getGraphData",
+ "DemoLoadError", "Not enough fields in data",
+ NULL, NULL);
+ for (; i < options.num_fields; i++)
+ fields[i] = 0;
+ break;
+ }
+ }
+
+ pclose(f);
+}