From: deveau@oceanroutes.ns.ca ("Terry J. Deveau")
Newsgroups: comp.windows.x.motif
Subject: Re: widget pointer storage
Date: 15 Sep 92 17:22:11 GMT
Distribution: inet
Organization: Oceanroutes Canada Inc.

Dinesh Punjabi <dpunjabi@nyx.cs.du.edu> writes:

> I am new to this newsgroup and to motif for that matter. What is a good
> style for declaring Widgets. I mean, should I define Widgets as globals
> or static locals, etc. This is not a problem for small self-contained 
> programs, but I am getting involved in an  application that could make use
> of a very large number of widgets. I frequently reference widgets within
> callbacks and would appreciate any coding style related EMAIL feedback
> about this issue.

What I do is maintain a table of widget pointers by "OpCode", one OpCode
for each widget pointer that I might need to recall explicitlty (i.e.
that whould not automatically be supplied as a callback argument, or
could be found as a parent or child of some known widget pointer, etc.).
You are free to use any integers you like as OpCodes, as long as they
map one-to-one with the widgets you create.

The table grows dynamically as various widgets are created, so it is rarely
larger than necessary (it never shrinks;, although I create dialogs
dynamically, I don't usually destroy them - just unmanage them - so
time is saved if a user uses the same dialog more than once).

The function Window_Ptrs provides the table management facility.  It
can be called with various "actions".  Action "PREPARE_WINDOW" registers
the function which will actually create the widget and ties it to
an OpCode, this is called for all OpCodes during application initialization.

Action ADD_WINDOW is called by the widget creation function to register
the newly created widget pointer and tie it to the OpCode.  There is an
option to save both the widget pointer and the widget pointer of its parent
shell (by passing the shell widget pointer in the "function" argument
instead of the usuall NULL); if this is used, managing and unmanaging
will be done on the shell widget, but the regular widget pointer will
be returned by the other actions (below).

Action DISPLAY_WINDOW will cause the widget creation function (registered
previously) to be called (unless it has already been done), manage the
widget, and return the widget pointer.  RECALL_WINDOW does the same, except
it does not manage the widget.  HIDE_WINDOW also does the same, except that
it unmanages the widget.

Here is the code you will need (I've simplified it from functions which
handle some additional "actions" as well).

#include <stdio.h>
#include <malloc.h>

char *AddLink (char **head, char **tail, int next, int size)
{
/* The purpose of this function is to add one link to a growing linked-list. */
/* If *tail is initially NULL, a new list is created, with its head address */
/* saved in *head. The variable next must indicate the offset in bytes from */
/* the start of each list item where the pointer to the next list item is */
/* saved; the last item on the list has a NULL here. */

  char *ptr;

  ptr = malloc (size);
  if (ptr) {
    if (*tail) *(char **)(*tail+next) = ptr;
    else *head = ptr;
    *tail = ptr;
    *(char **)(ptr+next) = NULL; }
  return ptr;
}

/* Window_ptrs actions.

#define PREPARE_WINDOW          3
#define ADD_WINDOW              4
#define RECALL_WINDOW           5
#define DISPLAY_WINDOW          6
#define HIDE_WINDOW             8
   
struct SaveList {
  int OpCode;
  Widget WidgetAddr;
  Widget ShellAddr;
  void (*function)();
  struct SaveList *next; };

static struct SaveList *First = NULL, *Last = NULL;

int Window_Ptrs(action, OpCode, w, function)
int action;  /* action requested by calling program */
int OpCode;  /* window reference number */
Widget *w;    /* pointer to widget address for corresponding window */
void (*function)(); /* pointer to a window creation function (usually) */
{

  struct SaveList *Saved, *next;
  int status = 1, op;

    for (Saved=First; Saved; Saved=Saved->next) if (OpCode==Saved->OpCode) break;

    switch (action) {
      case PREPARE_WINDOW:      /* register window address */ 
        if (op = !Saved) 
          Saved = (struct SaveList *)AddLink (&First,&Last,
            &((struct SaveList *)NULL)->next, sizeof (struct SaveList));
        if (Saved) {
          Saved->OpCode = OpCode;
          Saved->WidgetAddr = *w;
          Saved->function = function; }
        else status = 0;
        break;          

      case ADD_WINDOW:  /* register window address */ 
        if (op = !Saved) 
          Saved = (struct SaveList *)AddLink (&First,&Last,
            &((struct SaveList *)NULL)->next, sizeof (struct SaveList));
        else if (Saved->function==NULL)
          fprintf (stderr,"ERROR: Window_Ptrs redefinition of OpCode %d !\n",OpCode);
        if (Saved) {
          Saved->OpCode = OpCode;
          Saved->WidgetAddr = *w;
          Saved->ShellAddr = (Widget)function;
          Saved->function = NULL; }
        else status = 0;
        break;          

      case DISPLAY_WINDOW:      /* display window */
        if (Saved) {
          if (Saved->function) Saved->function(Saved->WidgetAddr,Saved->OpCode);
          XtManageChild(Saved->WidgetAddr);
          if (Saved->ShellAddr) XtManageChild(Saved->ShellAddr);
          if (w) *w = Saved->WidgetAddr; }
        else status = 0;
        break;          

      case HIDE_WINDOW:         /* hide window */
        if (Saved) {
          if (Saved->function) Saved->function(Saved->WidgetAddr,Saved->OpCode);
          XtUnmanageChild(Saved->ShellAddr?Saved->ShellAddr:Saved->WidgetAddr);
          if (w) *w = Saved->WidgetAddr; }
        else status = 0;
        break;          

      case RECALL_WINDOW:       /* recall window address */
        if (Saved) {
          if (Saved->function) Saved->function(Saved->WidgetAddr,Saved->OpCode);
          if (w) *w = Saved->WidgetAddr; }
        else status = 0;
        break;          

      default:  /* invalid "action", replace with your error handler call */
        showErr(12,0,NULL,NULL);
        status = 0; } 


  return status;
}