Creation

Creating objects is relatively easy, its just a matter of finding out the class name you want to make an object out of or pass in the class pointer of the private class.
struct Gadget *gad;
Class *privclass;

/* for public classes */
gad = NewObject( NULL, "strgclass", ... );

/* for private classes */
gad = NewObject( privclass, 0, ... );

/* defines are a handy shortcut instead of writing them out all the time */
#define ButtonObject NewObject( NULL, "buttongclass"
There are a few gotchas though. Some attributes can't be specified or can only be given during creation so you need to be careful about what you pass in. For example, the frbuttonclass won't use the GA_Width/GA_Height attributes during creation so you need to use a separate SetAttrs() call in order to adjust it properly.

struct Image *frame;
struct Gadget *gad;

frame = NewObject( NULL, "frameiclass", TAG_DONE );
if( frame )
{
	gad = NewObject( NULL, "frbuttonclass",
			GA_Left, 10,
			GA_Top, 10,
			GA_Width, 200, /* these won't do anything */
			GA_Height, 30,
			GA_Image, frame,
			GA_Text, "Hello World",
			TAG_DONE );
	if( gad )
	{
		/* you have to use a SetAttrs() in order for it to work */
		SetAttrs( gad, GA_Width, 200, GA_Height, 30, TAG_DONE );
		AddGadget( win, gad, -1 );
		RefreshGadgets( gad, win, 0 );
	}
}
Creating many objects can also be a pain since you should check each creation to make sure it was successful before you can use it. Doing this for every creation is quite tedious so its best to create several at a time and then check them in one 'if'.

/* use */

gad = NewObject( ... );
gad2 = NewObject( ... );
if( gad && gad2 )
{
}
/* DisposeObject() is smart enough to not dispose of a NULL
   so we can do this safely */
DisposeObject( gad );
DisposeObject( gad2 );

/* instead of */

if( gad = NewObject( ... ) )
{
	if( gad2 = NewObject( ... ) )
	{
		/* ... */
		DisposeObject( gad2 );
	}
	DisposeObject( gad );
}

Communication

BOOPSI gadgets are just like regular gadgets so they communicate through the IDCMP port with the same messages. They also have an extra message class called IDCMP_IDMCPUPDATE which allows gadgets to send attribute lists to the task. To set this up you need to set the ICA_TARGET attribute of the gadget to be ICTARGET_IDMCP and optionally you can map an attribute to ICSPECIAL_CODE so that the attribute's value is inserted into the Code field of the IntuiMessage. The gadget will also put the GA_ID attribute with the gadget's ID into the taglist so you can tell which gadget sent the message.


struct TagItem prop2idcmp[] = {
	{PGA_Top, ICSPECIAL_CODE}, /* we are mapping the PGA_Top to the 
	                         IntuiMessages Code field */
	{TAG_DONE}
};

void main()
{
	struct Window *win;
	
	if( win = OpenWindowTags( NULL,
				...,
				/* use IDCMP_IDCMPUPDATE to get taglists from gadgets */
				WA_IDCMP, IDCMP_IDCMPUPDATE|(otherflags),
				...,
				TAG_DONE ) )
	{
		struct Gadget *prop;
		
		prop = NewObject( NULL, "propgclass",
					...,
					GA_ID, 1, /* set the GadgetID so we can distinguish it from the others */
					ICA_MAP, prop2idcmp, /* pass in the map taglist */
					ICA_TARGET, ICTARGET_IDCMP, /* tell the gadget to send
					                           an IDCMP_IDCMPUPDATE message
					                           when a notify attribute changes */
					TAG_DONE );
		if( prop )
		{
			ULONG waitsigs, portsig;
			BOOL done = FALSE;
			struct IntuiMessage *imsg;
			ULONG gadgetid;
			
			AddGadget( win, prop, -1 );
			RefreshGadgets( prop, win, 0 );
			portsig = 1L << win->UserPort->mp_SigBit;
			while( !done )
			{
				waitsigs = Wait( portsig | SIGBREAKF_CTRL_C );
				if( waitsigs & portsig )
				{
					while( imsg = GetMsg( win->UserPort ) )
					{
						switch( imsg->Class )
						{
							case IDCMP_IDCMPUPDATE:
								/* the taglist will have a GA_ID with it's gadget ID
								   We use GetTagData() and set the default to 0 so
								   we know if something went wrong and we got a message
								   without a GA_ID */
								gadgetid = GetTagData( GA_ID, 0, imsg->IAddress );
								switch( gadgetid )
								{
									case 1:
										/* its the prop gad, do something */
										printf( "prop top %ld\n", imsg->Code );
										break;
									default:
										break;
								}
								break;
						}
						ReplyMsg( imsg );
					}
				}
				if( waitsigs & SIGBREAKF_CTRL_C )
					done = TRUE;
			}
			RemoveGadget( win, prop );
		}
		DisposeObject( prop );
		CloseWindow( win );
	}
}

Maintained by Tim Stack(stack@cs.utah.edu)
Last Changed on 27-Dec-1997, 09:51