Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Tools

Debugging Motif Widgets


NOV92: DEBUGGING MOTIF WIDGETS

This article contains the following executables: WIDGET.ARC

Kamran is a software consultant with Mentor Programming Services in Sugarland, Texas. He has experience in telecommunications, graphics, real-time systems programming, Windows, and UNIX system-software development. He can be reached at 713-265-1539 or at khx@ se44.wg2.waii.com.


Debugging Motif widgets can be a daunting task because each Motif application brings its own unique set of problems. One approach to debugging a widget is to use a test driver to dissect the problem into individual parts and then analyze them. The driver confirms that each function serves as a black box in which the outputs perform as expected, given your range of inputs.

You could use a test driver, for example, to place a widget on a form by itself and see if it shows up with the right resources and behaves correctly. If the widgets appear on the screen correctly, you can feel confident about incorporating the test code into your application. If not, you should check error messages from the server before proceeding.

In this article, I'll present a test driver and discuss some pitfalls commonly encountered when debugging Motif widgets. Much of my discussion is based on a recent project involving a bar chart that needed changing at the last minute -- the client wanted the data to be displayed as a line chart. My solution was to extend the BarChart widget to a LineChart widget, which inherits all but the drawing functions of the BarChart widget. This included showing all forms of graphical data on a FIFO (first-in, first-out) basis (to display readings received on a sensor), scaling the widget's vertical axes, and increasing the number of bars to a predefined maximum. Since I was working from the BarChart widget's basic framework, most of my efforts dealt with debugging the LineChart widget. The source for the BarChart and LineChart widgets are available electronically; see "Availability," page 5.

The Test Driver

The test driver presented here puts one BarChart and one LineChart on a form as an example. Three push buttons are also provided: Toggle, Advance, and Done. The view toggles from a BarChart to a LineChart when you click the mouse button on Toggle. Clicking on Advance simulates a sensor feeding a canned set of values into both widgets and sets the view to the LineChart widget. If you press the button several times, you'll see a jagged waveform. The Done button simply ends the application. See Listing One (page 135) for the test-driver code.

The main program initializes the toolkit, creates an ApplicationShell, places a Form on itself, arranges the widgets on the Form, and finally goes into the main loop. During this process, it sets up resources for the widgets and creates dummy data.

The arguments for the LineChart and BarChart widgets themselves take up most of the code listing because of the large number of available options. The bulk of the arguments to the BarChart and LineChart widgets set the parameters for the data and its display function. Some parameters, such as foreground and background color, don't have to be set; they can be defaulted. However, I have included them to illustrate the flexibility in setting up these widgets.

I commented out the debug preprocessor flags that I used to debug the test driver. You can set them back on to get an idea of the program's flow. These flags are: DEBUG_SWAPPING_SCREENS, DEBUG_SI_COUNTER, and DEBUG_LIMITS.

I use the global variable siCounter to cycle through the arrays to produce the jagged waveform when the Advance button is pressed.

Note that I have used macros to locate push buttons on the Form. This greatly improves the listing's readability but produces really strange compiler bugs if you make a syntax error. The call to the macro is a lot simpler than block copying the same section of code several times.

The str2pix function provides a quick way to allocate colors in Motif: It accepts the color name as a string and returns the pixel value for it. I usually include this function in the set of library functions I used for development and testing.

The callback function ToggleCB() manages and unmanages the BarChart and LineChart widgets. If you put enough drawing-area widgets with pixmaps at the same location on a Form, and at the press of a button manage and unmanage these widgets in a predefined manner, you will be able to achieve graphics animation. You could drive this process by a timer function, using XtAppAddTimerCallback().

Look at All Variables

Start testing widget-display code by debugging the code for displaying anything in test driver routines before inserting that code into a widget. This may seem obvious, but it's not easy to convince yourself to write drivers for every display function. Nevertheless, it will save time later on.

In most cases, running the dbx debugger shouldn't cause problems, and it's helpful to see a stack trace after a core dump. Sometimes you can write and link in your own exit() function and set a breakpoint in it. Even if your toolkit is not generated with the debugging option on, you can still look at a widget's internal instance values. Just include the widget's private header file instead of its public file.

To step through the test code in a debugger and examine the internals of the widgets themselves, replace the line #include LineChart.h with the code in Example 1. Remember to avoid setting a breakpoint in a routine which might stop the server. This would usually be in a drawing routine or sometimes even a callback routine. This is because expose events are sent when a widget's drawing area is uncovered, and the widget is set to receive such events. In many cases, my server locked up when I tried to set a breakpoint in a redraw function. Use printf statements judiciously in such cases. Also, remember to terminate output strings with "\n" or you may not see any debug output until the system has to flush its output buffer.

Example 1: Use these lines to step through the source code.

  #include "BarChartP.h"
  #include "BarChart.h"
  #include "LineChartP.h"
  #include "LineChart.h"

You may even use the XtWarning function call to display the status of variables during execution. This function uses a string as an input, so it's probably better to use a local string and do an sprintf all nonstring variables. The declaration for XtWarning is void XtWarning(String message);.

My debugging solution was to make extensive use of multiple printf statements and the preprocessor's #define statements. For clarity and brevity, I've removed the long lines of such statements from the listings. For example, I used a #defined switch DEBUG_LIMITS for printing status messages for all limits on the current drawing statements.

For severe errors which caused my application to die without even a decent error message, I used the XtSetErrorHandler() function. This function returns nothing and requires as input a pointer to a function, which in turn receives no parameters and returns nothing, too. The declaration is void XtSetErrorHandler(void (*ErrorFunction)());.

This ErrorFunction can be set to display the status of all global variables whenever an error occurs. Keep in mind though that errors are fatal and that the application exits after such an occasion, whereas warnings do not terminate program execution. I've found this function to be less useful than a set of well-placed printf and XtWarning statements.

It's up to the application programmer to confirm that the widget's parent is willing to accept children. Intrinsics do not require that the parent accepting children be composite. Adding a widget to a noncomposite widget and not following the instructions in the parent's documentation will not cause any errors, but also will not allow the widget to be visible.

Another annoying, though not fatal bug is the following error message, which is issued when you try to place a widget on a Form widget: "Bailed out of edge synchronization after 10,000 iterations. Check for contradictory constraints on children of this form." The exact message may be different, depending on how your libraries have been compiled. Also, the widgets you attempt to place on the screen may not be where you want them. This error indicates that you may be requesting incorrect attachments of this widget to the Form.

If an application generates only Xlib errors, try to isolate error messages by running it with the -synchronous switch option. This will make it run slower, but you'll see error messages as they happen and not when the server flushes its queue.

Also, callback functions that appear more than once in a widget's callback list are called the number of times they appear. Just make sure you know the number of times you've added a callback function to a widget, and you should be all right.

Sometimes an application requires the input focus from the pointer or the keyboard using XSetInputFocus(). This will cause an error if the widget is invisible by the time the server gets the message. An example is the rare (but still probable) case of a widget checking whether it is visible during the call to set the input focus, and the user covering the widget up by the time the server gets the message. The only real cure is to grab the server, get the focus, then ungrab the server. This is done via the XtAcceptFocus() call which calls XSync(), installs a dummy error handler which ignores any BadMatch calls, calls the handler, then finally calls XSync() again to reinstall the previous error handler.

The drawing area for a normal widget always has its (x = 0, y = 0) origin at the top-left corner. Most end users expect the origin to be on the bottom-left side. Be sure to document which convention you use and stick to it. To transpose the y coordinate to the bottom-left corner, simply subtract the y value from the maximum height of the widget.

The listing for the BarChart widget (available electronically) includes the code for displaying negative and positive data, and we can set the resources to specify what limits to pose on either axes. See the Resize method in the listings. Keep in mind that each widget is actually an X Window; therefore, all rules that apply to an X Window generally apply to a widget as well. For example, a widget of 0 width or height will crash an application, so always give a minimum default height and width. Note that in the Initialization and SetValues functions, I explicitly force a minimum height and width on the widget and just issue a warning.

Most XtGet/SetValue parameters are documented ambiguously. In some cases, you get a copy of the data in a widget; in others, you get a pointer to "sacred" data in the widget. Be careful. Print out the pointer addresses returned to you by successive calls to the widget and compare them. If the addresses are different, then a copy is being returned, and the data pointed to will have to be freed. If the addresses are the same, chances are that the value returned is a pointer to some internal structure within the widget, and should not be freed.

By the way, the Intrinsics do not have any type-conversion format for all the parameters set in the XtSetValues or XtGetValues functions. The functions copy numbers of bytes to and from the addresses pointed to. If the data pointed to cannot hold the number of bytes that the Intrinsics thinks it has to write, then data around the fields may be corrupted. If your machine supports only longword boundary packing of members, you may sometimes be spared this problem.

By the same token, Dimension and Cardinal types are unsigned. Do not attempt to subtract two Dimensions without checking for wraparound.

Mind Your Memory

As I tested the LineChart widget, I realized that the XtRealloc function sometimes muddled up the pointers in an array of pointers. It turned out that if I called XtRealloc once to get some pointers, then called XtMalloc for the data, and then called XtRealloc again to reallocate two or more elements to an existing array, some of my pointers in the older array were not updated. The older array now pointed to the newly reallocated array of pointers! For reasons still unknown to me, this didn't occur if I reallocated in multiples of 16. So now, I check whether I have enough space. If not, I reallocate 16 more elements and adjust the size.

It's important to free up memory used in the widget. If your application runs out of memory for some innocuous call, see if you are using GetAttributes (for example, a GetText() function) and not freeing the data pointer's data.

My code also confirmed that the number of calls to the server is inversely proportional to the program's execution speed. Therefore, you should attempt to use as few calls to the server as possible. For example, I use one call to XDrawLines() instead of multiple calls to XDrawLine(). It's a bit of a pain to set up, but the gains in execution are well worth it.

When writing a widget, you can either make a copy of the data and save it internally or simply point to the data being passed in. I prefer copying the data in and saving it, even though this requires you to copy and maintain a copy of this data. Of course, the merit of using the pointer is that data for the widget is volatile. That is, it might point to an area in shared memory (perhaps where another process is writing in values). The savings in overhead are debatable, and keeping the data available is definitely a problem.

Destruction of a widget is a two-phase process. First, the Intrinsics marks the widgets to be destroyed. When all the references to the widget(s) waiting to be destroyed have been removed, the storage for these widgets is deallocated. Thus, the areas for a widget that have been malloced are not necessarily freed between the time the widget is destroyed and the time execution reaches the top of the loop. In other words, do not reuse data pointed by -- or located in -- a widget after calling a destroy function and before returning to the top of the loop. Doing so may cause you to see widget data still present after a destroy call when single stepping through code in a debugger.

After a widget is destroyed, your pointers to the widget will not necessarily point to NULL; you must reset the pointers yourself.

Further Changes to the Listings

The BarChart and LineChart code is only a scaffolding for you to work from and build on. You could always add scales and crossbars to further annotate the data or use more than one auxItems array to display more than two lines. This would be particularly useful if Boolean attributes were added for checking whether the data is to be displayed or not.

Alternatively, the redraw routine could be modified to display the LineCharts as a scatter plot, with a Boolean attribute of, say, ConnectDots. If ConnectDots is True, lines are drawn between all data points via the XDrawLines function; if it is False, only points are shown via the XDrawPoints function call and the points are therefore not connected. Similarly, we could use inheritance to display data using the values in the Aux array.

The convenience functions could be rewritten so as not to assume small arrays of data. This is inefficient for large arrays, and I will probably use a circular buffer in the future. However, the drawing and resizing functions will then have to work off the head and tail pointers.

Should you decide to write more convenience functions, use static variables for all convenience-function data that you do not want the world to see. Using globals in widgets is not a good idea, because widgets generally reside in libraries, and it's easy to simply link in another synonymous variable instead.

The LineChart and BarChart widgets could inherit from a base "meta class" -- a container class not used for displaying. The BarChart and LineChart widgets could then inherit the common elements of this meta class.



_DEBUGGING MOTIF WIDGETS_
by Kamran Husain


[LISTING ONE]
<a name="0293_000a">

/* This code is given as an example of sorts for you to write your own Motif
** application. Compile this program with the line:
**  acc -g test.c -o testme LineChart.o BarChart.o -lXm -lXt -lX11 -lm
**  where
**      acc - is the ANSI compiler at your site
**      -g  - is the debug option (optional)
**        -o  - specifies the output executable filename
**      -lXm - is the Motif Library
**      -lXt - is the Intrinsics Library
**      -lX11 - is the X11 Library
**      -lm - math library.
**      LineChart.o and BarChart.o are object files from the
**      sources available electronically from Dr Dobbs.
** If you want to step thru this code in a debugger and examine the internals
** of the Widgets themselves, replace the next #include "LineChart.h" line
** outside the comments with
**  #include "BarChartP.h"
**  #include "BarChart.h"
**  #include "LineChartP.h"
**  #include "LineChart.h"
*/

/* Some standard include files here. */
#include <X11/X.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <Xm/Xm.h>
#include <Xm/PushB.h>
#include <Xm/Form.h>
#include "LineChart.h"

/* A macro to facilitate button placement on a form. The x,y are the top left
** corner on the form. The w is the right position relative to the form's left
** side the h is the bottom position relative to the form's top side */
#define MAKE_BTN_ON_FORM(form,btn,x,y,w,h,str) \
    n = 0;  \
    XtSetArg(wars[n], XmNleftAttachment, XmATTACH_POSITION ); n++; \
    XtSetArg(wars[n], XmNtopAttachment, XmATTACH_POSITION ); n++; \
    XtSetArg(wars[n], XmNbottomAttachment, XmATTACH_POSITION ); n++; \
    XtSetArg(wars[n], XmNrightAttachment, XmATTACH_POSITION ); n++; \
    XtSetArg(wars[n], XmNrightPosition, (x+w)); n++; \
    XtSetArg(wars[n], XmNleftPosition, (x)); n++; \
    XtSetArg(wars[n], XmNtopPosition, (y)); n++; \
    XtSetArg(wars[n], XmNbottomPosition, (h+y)); n++; \
    btn = XmCreatePushButton(form,str,wars,n); \
    XtManageChild(btn)
/*  Remove the comments below to enable some debug levels.
    #define DEBUG_SWAPPING_SCREENS
    #define DEBUG_LIMITS
    #define DEBUG_SI_COUNTER
*/
#define  ScrnWidth 500
#define  ScrnHt    400
#define MAXITEMS 10
Widget mainShell,       /* Application shell   */
       mainForm,        /* Master form         */
      plotLChart,       /* Line Chart Widget   */
      plotBChart,       /* Bar Chart Widget    */
      otherPBtn,        /* Toggle Push Button  */
      advancePBtn,  /* Advance Data in Lists Push Button */
      donePBtn;     /* Exit Push Button    */
/* Pixels are stored in these. */
unsigned long WhiteColor,
            BlackColor,
            BlueColor,
            RedColor,
            GreenColor;

/* Storage Area for the dummy data.
   int dummyOne[MAXITEMS]  = { -10. -5, 0, 15, 20, 15 ,0, -5, -10, -5 };
   int dummyTwo[MAXITEMS]  = { 4, 13, 13, 10 ,11, 9, 4, -11, -13, -11 };
*/
static int siCounter = MAXITEMS - 1;
int one[MAXITEMS];
int two[MAXITEMS];
/*  Declare the functions and callbacks here. Note that I do not use any
**  parameters into the callbacks. Please refer to the Motif manual for
**  details on these parameters if you need to use them. */
void exitCB();
int  toggleCB();
int  advanceCB();
void createDummyData(int count, int *oneptr, int *twoptr);
unsigned long str2pix(char *spec, Widget w);
int main(int argc, char *argv[])
{
    Arg wars[24];       /* for argument passing     */
    XGCValues  gcv; /* for creation for GC      */
    XtGCMask  gcmask;   /* for GC flags             */
    char strName[24];   /* Dummy storage area       */
    int FormHt = 88;    /* On the main form         */
    int margin = 10;    /* Distance between buttons */
    int dw = 20;        /* Width of each button     */
    int dh = 10;        /* Height of each button    */
    int h1 = margin;    /* temporary var initialize */
    int h2;             /* temporary variables      */
    int DispHt, DispWd, ivalue, n, i, imax, imin, imid;
    /* Initialize toolkit */
    mainShell = XtInitialize(argv[0],"Demo", NULL, NULL, &argc, argv) ;
    n =0;
    XtSetArg(wars[n], XmNwidth, ScrnWidth); n++;
    XtSetArg(wars[n], XmNheight, ScrnHt); n++;
    XtSetArg(wars[n], XmNiconic, False ); n++;
    XtSetArg(wars[n], XmNiconName, "TestMe"); n++;
    XtSetValues(mainShell,wars,n);
    XtRealizeWidget(mainShell);
    /* Place the Form on the Shell. */
    n=0;
    XtSetArg(wars[n], XmNwidth, ScrnWidth); n++;
    XtSetArg(wars[n], XmNheight, ScrnHt); n++;
    mainForm = XmCreateForm(mainShell,"mainForm",wars,n);
    XtManageChild( mainForm );
    /* Use macros to place PushButtons on Form. Attach callbacks too. */
MAKE_BTN_ON_FORM(mainForm,otherPBtn,h1,FormHt,dw,dh,"Toggle");
     h2 = h1 + margin + dw;
MAKE_BTN_ON_FORM(mainForm,advancePBtn,h2,FormHt,dw,dh,"Advance");
     h2 +=  margin + dw;
MAKE_BTN_ON_FORM(mainForm,donePBtn,h2,FormHt,dw,dh,"Done");
    XtAddCallback(otherPBtn,XmNactivateCallback, toggleCB, NULL);
    XtAddCallback(advancePBtn,XmNactivateCallback, advanceCB, NULL);
    XtAddCallback(donePBtn,XmNactivateCallback, exit, NULL);
    createDummyData(MAXITEMS, one, two);
    /* Calculate extents of this dummy data. */
    imax = -100; imin = 100;
    for (i=0; i< MAXITEMS;i++)
        {
        ivalue  = one[i];
        if (imax < ivalue) imax = ivalue;
        if (imin > ivalue) imin = ivalue;
        ivalue  = two[i];
        if (imax < ivalue) imax = ivalue;
        if (imin > ivalue) imin = ivalue;
        }
    imid = imin + 1;
#ifdef DEBUG_LIMITS
    /* Tell the user where you are. */
    printf("\n Min = %d  Mid = %d  Max = %d", imin,imid,imax);
#endif
    /* Allocate the colors here. */
    WhiteColor = str2pix("White", mainForm);
     BlackColor = str2pix("Black", mainForm);
     BlueColor = str2pix("Blue", mainForm);
     RedColor = str2pix("Red", mainForm);
     GreenColor = str2pix("Green", mainForm);
    sprintf(strName,"%d,%d",imax,imin);
    /* Define and declare the Line Chart Widget. */
    n = 0;
    XtSetArg(wars[n], XmNheight, DispHt); n++;
    XtSetArg(wars[n], XmNwidth, DispWd); n++;
    XtSetArg(wars[n], XmNleftAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNrightAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNtopAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNbottomAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNleftPosition, 5 ); n++;
    XtSetArg(wars[n], XmNrightPosition, 95); n++;
    XtSetArg(wars[n], XmNtopPosition, 5 ); n++;
    XtSetArg(wars[n], XmNbottomPosition, 75 ); n++;
    XtSetArg(wars[n], XmNforeground, BlackColor); n++;
    XtSetArg(wars[n], XmNbackground, WhiteColor); n++;
    XtSetArg(wars[n], XtNitems, one); n++;
    XtSetArg(wars[n], XtNauxItems, two); n++;
    XtSetArg(wars[n], XtNitemCount, MAXITEMS); n++;
    XtSetArg(wars[n], XtNmaxItemCount, MAXITEMS); n++;
    XtSetArg(wars[n], XtNmaxValue, imax); n++;
    XtSetArg(wars[n], XtNmidValue, imid); n++;
    XtSetArg(wars[n], XtNminValue, imin); n++;
    XtSetArg(wars[n], XtNzeroColor, BlueColor); n++;
    XtSetArg(wars[n], XtNpositiveColor, BlueColor); n++;
    XtSetArg(wars[n], XtNnegativeColor, RedColor); n++;
    plotLChart = XtCreateWidget("LineChartType",
        XvlinechartWidgetClass, mainForm, wars, n);
    imid = (imax + imin) / 2;
#ifdef DEBUG_LIMITS
    printf("\n Min = %d  Mid = %d  Max = %d", imin,imid,imax);
#endif
    /* Define and declare the Bar Chart Widget. */
    n = 0;
    XtSetArg(wars[n], XmNheight, DispHt); n++;
    XtSetArg(wars[n], XmNwidth, DispWd); n++;
    XtSetArg(wars[n], XmNforeground, BlackColor); n++;
    XtSetArg(wars[n], XmNbackground, WhiteColor); n++;
    XtSetArg(wars[n], XmNleftAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNrightAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNtopAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNbottomAttachment, XmATTACH_POSITION ); n++;
    XtSetArg(wars[n], XmNleftPosition, 5 ); n++;
    XtSetArg(wars[n], XmNrightPosition, 95); n++;
    XtSetArg(wars[n], XmNtopPosition, 5 ); n++;
    XtSetArg(wars[n], XmNbottomPosition, 75 ); n++;
    XtSetArg(wars[n], XtNitems, one); n++;
    XtSetArg(wars[n], XtNauxItems, two); n++;
    XtSetArg(wars[n], XtNitemCount, MAXITEMS); n++;
    XtSetArg(wars[n], XtNmaxItemCount, MAXITEMS); n++;
    XtSetArg(wars[n], XtNmaxValue, imax); n++;
    XtSetArg(wars[n], XtNmidValue, imid); n++;
    XtSetArg(wars[n], XtNminValue, imin); n++;
    XtSetArg(wars[n], XtNmaxShowValue, imax); n++;
    XtSetArg(wars[n], XtNminShowValue, imin); n++;
    XtSetArg(wars[n], XtNzeroColor, BlueColor); n++;
    XtSetArg(wars[n], XtNpositiveColor, BlueColor); n++;
    XtSetArg(wars[n], XtNnegativeColor, RedColor); n++;
    plotBChart = XtCreateManagedWidget("BarChartDisplay",
        XvbarchartWidgetClass, mainForm, wars, n);
    /* Show the widgets on the form and go into a loop */
    XtManageChild(mainForm);
    XtRealizeWidget(mainShell);
    XtMainLoop();
}
/* Terminate the application. */
void exitCB()
{
exit(0);
}
/* It's easier to use a flag here instead of calling XtIsManaged() on every
** widget. This flag could index a circular list of Widgets and thus your
** ToggleCB() function would go something like:
**  ...
**  XtUnmanage(YourList[ToggleFlag]);
**  ToggleFlag++;
**  if (ToggleFlag >= LengthOfList) ToggleFlag =0;
**  XtManage(YourList[ToggleFlag]);
**  ...
** where "YourList" is an array of widgets of length "LengthOfList". */
static ToggleFlag = 1;
/* Callback for function to toggle the type of display. */
int  toggleCB()
{
if (ToggleFlag)
    {
#ifdef  DEBUG_SWAPPING_SCREENS
printf("\n Debug statement goes here ");
#endif
    XtUnmanageChild(plotBChart);
    XtManageChild(plotLChart);
    ToggleFlag = 0;
    }
    else {
#ifdef  DEBUG_SWAPPING_SCREENS
printf("\n Debug statement goes here ");
#endif
    XtManageChild(plotBChart);
    XtUnmanageChild(plotLChart);
    ToggleFlag = 1;
    }
}
/* Convenience to load in colors for the application. Returns pixel value
** given the following inputs: char *spec;      color name
**                         Widget w;        a widget pointer
*/
unsigned long str2pix(char *spec, Widget w)
{
    Colormap cmap;
    XColor color_struct;        /* For this color     */
    Display  *dpy;          /* Curent display     */
    static void *ht = NULL;     /* hash table pointer */
    /* Get Display  */
    dpy = XtDisplay(w);
    /*  Get color map */
    cmap = XDefaultColormap(dpy, DefaultScreen(dpy));
    /* Parse the color specification */
    if (!XParseColor(dpy, cmap, spec, &color_struct))
        {
        printf("Invalid color name (%s)\n",spec);
        exit(1);
        }
    /* Try to allocate the color */
    if (!XAllocColor(dpy, cmap, &color_struct))
        {
        printf("Cannot allocate color in colormap\n");
        exit(1);
        }
    /* Return the allocated color */
    return(color_struct.pixel);
}
/* Cycle the data thru itself when button is pressed on "Advance" */
int  advanceCB()
{
if (siCounter <  1) siCounter = MAXITEMS;
#ifdef DEBUG_SI_COUNTER
printf("\n siCounter = %d", siCounter);
#endif
siCounter--;
XvBarChartAddItem(plotLChart, one[siCounter]);
XvBarChartAddItem(plotBChart, two[siCounter]);
}
/* Create some data in an array. */
void createDummyData(int count, int *oneptr, int *twoptr)
{
int i;
for (i = 0; i < count/2; i++)
    {
    oneptr[i] = (i * 2) + 10;
    twoptr[i] = (i * 3) + 5;
    }
for (i = count/2; i < count; i++)
    {
    oneptr[i] = (i * 2) - 10;
    twoptr[i] = (i * 3) - 5;
    }
}










Copyright © 1992, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.