Overriding OM SET()

From MorphOS Library

Revision as of 15:37, 3 January 2011 by Krashan (talk | contribs) (New article.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Grzegorz Kraszewski


The OM_SET() method receives an opSet structure as its message. The structure is defined in the <intuition/classusr.h> header.

struct opSet
{
  ULONG              MethodID;            /* always OM_SET (0x103) */
  struct TagItem    *ops_AttrList;
  struct GadgetInfo *ops_GInfo;
};

The most important field is ops_AttrList. It is a pointer to a taglist containing attributes and values to be set. The ops_GInfo field is an obsolete legacy thing and is not used by modern components like MUI or Reggae. The method implementation should iterate the taglist and set all attributes recognized. The operation of setting an attribute may be just setting some field in an object instance data, it may also trigger some actions (like for example object redrawing). It is recommended however that complex actions are implemented as methods rather than attribute changes. A reference implementation of OM_SET() may look like this:

IPTR MyClassSet(Class *cl, Object *obj, struct opSet *msg)
{
  struct TagItem *tag, *tagptr;
  IPTR tagcount = 0;

  tagptr = msg->ops_AttrList;

  while (tag = NextTagItem(&tagptr))
  {
    switch (tag->ti_Tag)
    {
      case SOME_TAG:
        /* attribute setting actions for SOME_TAG */
        tagcount++;
      break;

      /* more tags here */
    }
  }

  tagcount += DoSuperMethodA(cl, obj, (Msg)msg);
  return tagcount;
}

The taglist iteration is done with NextTagItem() function from utility.library. The function returns pointer to a next tag each time it is called and keeps the current position in tagptr. The advantage of this function is automatic handling of special tag values (TAG_MORE, TAG_IGNORE, TAG_SKIP), they are not returned, but their actions are performed instead.

The OM_SET() function returns the total number of recognized tags. It is implemented with tagcounter. It gets incremented on every tag recognized and finally number of tags recognized by superclass(es) is added.

Common bugs in OM_SET() implementation are: ignoring tag counting and calling super method in the default case of switch statement. The second bug causes the supermethod to be called multiple times, once for every tag not handled by the subclass.



In some rare cases a subclass may want to override an attribute completely, so it is not passed to superclasses. It can be done by replacing the tag (not value!) by TAG_IGNORE. There is one caveat however. It most cases in C and C++, the taglist is built dynamically on the stack from variable arguments of a function like SetAttrs(). It is possible however, that a taglist is a static object (for example a global one, or created in an allocated chunk of free memory). In this case changing a tag is a permanent operation, which may have unexpected results. This remark also applies for changing a value of a tag before passing it to a superclass. A safe solution is to clone the taglist with CloneTagItems() function from utility.library. Then changes are made in the copy and this copy is passed to superclass. The copy is then freed with FreeTagItems(). The disadvantage of this solution is that cloning a taglist may fail due to lack of free memory and this possibility must be handled somehow.