The Plotutils Package - X Programming

Go to the first, previous, next, last section, table of contents.

### Advanced X Window System programming

Applications that run under the X Window System are normally built using Xt, the X Toolkit. In Xt, an application is constructed from `widgets' such as text entry fields, buttons, sliders, drawing areas, etc. When the application starts up, each widget is configured to respond appropriately to `events', which include key presses and mouse clicks. After the widgets are configured, control is transferred to the Xt event loop.

GNU `libplot` can be used within the Xt event loop to draw vector graphics. For this, it would use one or more X Drawable Plotters. An X Drawable Plotter is a Plotter that can plot into an off-screen pixmap or an on-screen window, such as a window associated with a widget.

The following sample application shows how an X Drawable Plotter would be used. The application draws a `C' curve, as defined in a previous section, in a popped-up window. The usual Xt command-line options may be used: the window background color is specified with the ``-bg'` option, the window geometry with ``-geometry'`, etc. The curve is initially drawn in red, but clicking once with the mouse will redraw it in green. A second mouse click will redraw it in red, and so forth. The application will terminate when ``q'` is typed.

    #include <stdio.h>
    #include <plot.h>
    #include <X11/Xlib.h>
    #include <X11/Intrinsic.h>
    #include <X11/Shell.h>
    #include <X11/StringDefs.h>
    #include <X11/Core.h>

    int green = 0;                  /* draw in green, not red? */

    #define MAXORDER 12
    void draw_c_curve (double dx, double dy, int order)
    {
      if (order >= MAXORDER)
        pl_fcontrel (dx, dy);       /* continue path along (dx, dy) */
      else
        {
          draw_c_curve (0.5 * (dx - dy), 0.5 * (dx + dy), order + 1);
          draw_c_curve (0.5 * (dx + dy), 0.5 * (dy - dx), order + 1);
        }
    }

    void Redraw (Widget w, XEvent *ev, String *params, Cardinal *n_params)
    {
      /* draw C curve */
      pl_erase ();
      pl_pencolorname (green ? "green" : "red");
      pl_fmove (600.0, 300.0);
      draw_c_curve (0.0, 400.0, 0);
      pl_endpath ();
    }

    void Toggle (Widget w, XEvent *ev, String *params, Cardinal *n_params)
    {
      green = (green ? 0 : 1);
      Redraw (w, ev, params, n_params);
    }

    void Quit (Widget w, XEvent *ev, String *params, Cardinal *n_params)
    {
      exit (0);
    }

    /* mapping of events to actions */
    static const String translations =
    "<Expose>:      redraw()\n\
    <Btn1Down>:     toggle()\n\
    <Key>q:         quit()";

    /* mapping of actions to subroutines */
    static XtActionsRec actions[] =
    {
      {"redraw",            Redraw},
      {"toggle",            Toggle},
      {"quit",              Quit},
    };

    /* default parameters for widgets */
    static String default_resources[] =
    {
      "Example*geometry:      250x250",
      (String)NULL
    };

    int main (int argc, char *argv[])
    {
      Arg wargs[10];                /* storage of widget args */
      Display *display;             /* X display */
      Widget shell, canvas;         /* toplevel widget; child */
      Window window;                /* child widget's window */
      XtAppContext app_con;         /* application context */
      int handle, i;
      char *bg_colorname = "white";

      /* take background color from command line */
      for (i = 0; i < argc - 1; i++)
        if (strcmp (argv[i], "-bg") == 0)
          bg_colorname = argv[i + 1];

      /* create toplevel shell widget */
      shell = XtAppInitialize (&app_con,
                               (String)"Example", /* app class */
                               NULL,              /* options */
                               (Cardinal)0,       /* num of options */
                               &argc,             /* command line */
                               argv,              /* command line */
                               default_resources,
                               NULL,              /* ArgList */
                               (Cardinal)0        /* num of Args */
                               );

      /* set default widget parameters (including window size) */
      XtAppSetFallbackResources (app_con, default_resources);

      /* map actions to subroutines */
      XtAppAddActions (app_con, actions, XtNumber (actions));

      /* create canvas widget as child of shell widget; realize both */
      XtSetArg(wargs[0], XtNargc, argc);
      XtSetArg(wargs[1], XtNargv, argv);
      canvas = XtCreateManagedWidget ((String)"", coreWidgetClass,
                                      shell, wargs, (Cardinal)2);
      XtRealizeWidget (shell);

      /* for the canvas widget, map events to actions */
      XtSetArg (wargs[0], XtNtranslations,
                XtParseTranslationTable (translations));
      XtSetValues (canvas, wargs, (Cardinal)1);

      /* initialize GNU libplot */
      display = XtDisplay (canvas);
      pl_parampl ("XDRAWABLE_DISPLAY", display);
      window = XtWindow (canvas);
      pl_parampl ("XDRAWABLE_DRAWABLE1", &window);
      pl_parampl ("BG_COLOR", bg_colorname);
      handle = pl_newpl ("Xdrawable", NULL, NULL, stderr);
      pl_selectpl (handle);
      pl_openpl ();
      pl_fspace (0.0, 0.0, 1000.0, 1000.0);
      pl_flinewidth (0.25);

      /* transfer control to X Toolkit event loop (doesn't return) */
      XtAppMainLoop (app_con);

      return 1;
    }

Even if you are not familiar with X Window System programming, the structure of this application should be clear. It defines three callbacks: `Redraw`, `Toggle`, and `Quit`. They are invoked respectively in response to (1) a window expose event or mouse click, (2) a mouse click, and (3) a typed ``q'`. The first drawing of the `C' curve (in red) takes place because the window receives an initial expose event.

This example could be extended to take window resizing into account. Actually, X Drawable Plotters are usually used to draw vector graphics in off-screen pixmaps rather than on-screen windows. Pixmaps, unlike windows, are never resized.

Go to the first, previous, next, last section, table of contents.