Some compiler warnings removed.
[cake.git] / workbench / classes / datatypes / amigaguide / amigaguideclass.c
blobffd8aca8e6a5f4dd6a25150d8828f7883aad1881
1 /*
2 ** $PROJECT: amigaguide.datatype
3 **
4 ** $VER: amigaguideclass.c 50.1 (13.06.03)
5 **
6 ** $AUTHOR: Stefan Ruppert <stefan@ruppert-it.de>
7 **
8 */
10 /* ------------------------------- includes ------------------------------- */
12 #include "classbase.h"
13 #include <libraries/diskfont.h>
15 /* ------------------------------ prototypes ------------------------------ */
17 ULONG om_new(Class *cl, Object *obj, struct opSet *msg);
18 ULONG om_dispose(Class *cl, Object *obj, Msg msg);
19 ULONG _om_set(Class *cl, Object *obj, struct opSet *msg);
20 ULONG _om_update(Class *cl, Object *obj, struct opSet *msg);
22 ULONG gm_render(Class *cl, Object *obj, struct gpRender *msg);
23 ULONG gm_layout(Class *cl, Object *obj, struct gpLayout *msg);
24 ULONG gm_input(Class *cl, Object *obj, struct gpInput *msg);
26 ULONG dtm_asynclayout(Class *cl, Object *obj, struct gpLayout *msg);
27 ULONG dtm_trigger(Class *cl, Object *obj, struct dtTrigger *msg);
30 static void ActivateAGObject(Class *cl, Object *obj, struct GadgetInfo *ginfo,
31 struct AmigaGuideObject *agobj);
33 /* ------------------------------ constants ------------------------------- */
35 static const struct NavigatorButton navbuttons[] =
37 {"Contents", STM_CONTENTS, NBF_DISABLED},
38 {"Index", STM_INDEX, NBF_DISABLED},
39 {"Help", STM_HELP, 0},
40 {"Retrace", STM_RETRACE, NBF_DISABLED},
41 {"< Browse", STM_BROWSE_PREV, NBF_DISABLED},
42 {"> Browse", STM_BROWSE_NEXT, NBF_DISABLED},
43 {NULL, 0, 0}
46 static const struct DTMethod triggermethods[] =
48 {"Contents", "CONTENTS", STM_CONTENTS},
49 {"Index", "INDEX", STM_INDEX},
50 {"Help", "HELP", STM_HELP},
51 {"Retrace", "RETRACE", STM_RETRACE},
52 {"< Browse", "PREVIOUS", STM_BROWSE_PREV},
53 {"> Browse", "NEXT", STM_BROWSE_NEXT},
54 {"Next Field", NULL, STM_NEXT_FIELD},
55 {"Prev Field", NULL, STM_PREV_FIELD},
56 {"Activate Field", NULL, STM_ACTIVATE_FIELD},
57 {NULL, NULL, 0}
60 static const struct TagItem navmap[] =
62 {NA_Command, AGNA_Command},
63 {TAG_END,0}
66 static const ULONG supported_methods[] =
68 DTM_COPY,
69 DTM_SELECT,
70 DTM_CLEARSELECTED,
71 DTM_WRITE,
72 DTM_PRINT,
73 DTM_TRIGGER,
74 DTM_GOTO,
75 ~0,
78 /* -------------------------- user library init --------------------------- */
80 BOOL UserClassBaseOpen(struct ClassBase *cb)
82 cb->cb_Navigator = MakeNavigatorClass(cb);
83 cb->cb_NodeClass = MakeNodeClass(cb);
84 if(cb->cb_Navigator != NULL &&
85 cb->cb_NodeClass != NULL)
87 return TRUE;
90 return FALSE;
93 int UserClassBaseClose(struct ClassBase *cb)
95 if(cb->cb_Navigator != NULL)
96 if(FreeNavigatorClass(cb, cb->cb_Navigator))
97 cb->cb_Navigator = NULL;
98 if(cb->cb_NodeClass != NULL)
99 if(FreeNodeClass(cb, cb->cb_NodeClass))
100 cb->cb_NodeClass = NULL;
102 return TRUE;
105 #ifdef __AROS__
106 #include <aros/symbolsets.h>
108 ADD2INITLIB(UserClassBaseOpen, -1);
109 ADD2EXPUNGELIB(UserClassBaseClose, -1);
110 #endif /* __AROS__ */
112 /* ------------------------------ functions ------------------------------- */
114 static
115 void MakeNavGadget(Class *cl, Object *obj, struct IBox *domain)
117 CLASSBASE;
118 INSTDATA;
120 if(data->ag_Gadget != NULL)
121 return;
123 data->ag_Gadget =
124 NewObject(cb->cb_Navigator,NULL,
125 ((CAST_GAD(obj)->Flags & GFLG_RELRIGHT) == GFLG_RELRIGHT) ? GA_RelRight : GA_Left, domain->Left,
126 ((CAST_GAD(obj)->Flags & GFLG_RELBOTTOM) == GFLG_RELBOTTOM) ? GA_RelBottom : GA_Top, domain->Top,
127 GA_RelWidth, CAST_GAD(obj)->Width,
128 GA_Height, 10,
129 NA_Buttons, (ULONG) data->ag_Buttons,
130 NA_Target, (ULONG) obj,
131 ICA_MAP, (ULONG) navmap,
132 ICA_TARGET, (ULONG) obj,
133 TAG_DONE);
136 /****** amigaguide.datatype/OM_NEW *******************************************
138 NAME
139 OM_NEW -- create an amigaguide datatype object
141 INPUT
142 struct opSet
144 ULONG MethodID;
145 struct TagItem *ops_AttrList;
146 struct GadgetInfo *ops_GInfo;
149 FUNCTION
150 This method creates and initializes an amigaguide datatype object.
151 Currently only DTST_FILE source type is supported. All tags for
152 OM_SET method can be passed to the method. Additionally the following
153 tags are only used during initialization.
155 TAGS
156 DTA_NodeName -- (STRPTR) name of the node to load initially.
158 DTA_ARexxPortName -- (STRPTR) base name for the ARexx port.
160 SEE ALSO
161 datatypes.library/NewDTObjectA(), OM_DISPOSE, OM_SET, --arexx--
163 ******************************************************************************
167 ULONG om_new(Class *cl, Object *obj, struct opSet *msg)
169 ULONG rv;
170 INSTDATA;
172 STRPTR nodename = "main";
173 ULONG sourcetype;
174 BPTR handle;
176 struct TagItem *tstate = msg->ops_AttrList;
177 struct TagItem *tag;
179 rv = DoSuperMethodA(cl, obj, (Msg)msg);
180 if (rv == 0)
181 return rv;
182 else
184 obj = (Object *)rv;
185 data = (struct AmigaGuideData *)INST_DATA(cl, obj);
188 /* initialize the instance data */
189 data->ag_Pool = CreatePool(MEMF_CLEAR | MEMF_ANY, AG_PUDDLE_SIZE, AG_PUDDLE_SIZE);
191 /* prepare lists */
192 NewList(&data->ag_Files);
193 NewList(&data->ag_Visited);
195 InitSemaphore(&data->ag_ASyncLayout);
197 data->ag_ARexxPortName = "AMIGAGUIDE";
199 /* lets use this object for the actual one until one node
200 could be loaded. Therefore we don't need to check some
201 conditions if a node is loaded or not. */
202 data->ag_Actual = obj;
203 data->ag_InitialNode = CopyAGString(cl, obj, nodename);
204 data->ag_Creator = FindTask(NULL);
206 /* process attributes that only belongs to this class
207 and intialization phase. */
208 while((tag = NextTagItem((const struct TagItem **)&tstate)) != NULL)
210 switch(tag->ti_Tag)
212 case DTA_NodeName:
213 nodename = (STRPTR) tag->ti_Data;
214 break;
215 case DTA_ARexxPortName:
216 data->ag_ARexxPortName = (STRPTR) tag->ti_Data;
217 break;
221 data->ag_File = AllocAGFile(cl, obj);
222 if(data->ag_File == NULL)
223 rv = (ULONG) NULL;
224 else
226 /* set attributes provided by the user */
227 _om_set(cl, obj, msg);
229 /* now get the source type only DTST_FILE is supported.
230 Then start scanning the AmigaGuide file */
231 if(GetDTAttrs(obj,
232 DTA_SourceType, (ULONG) &sourcetype,
233 DTA_Handle, (ULONG) &handle,
234 TAG_DONE) != 2)
236 rv = (ULONG) NULL;
237 } else
239 switch(sourcetype)
241 case DTST_FILE:
242 data->ag_File->agf_Handle = handle;
243 data->ag_File->agf_Lock = DupLockFromFH(handle);
244 ScanFile(cl, obj, data->ag_File);
246 if(data->ag_File->agf_OnOpen != NULL)
247 if(SendRexxCommand(cl, obj, data->ag_File->agf_OnOpen, AGRX_RX) != RC_OK)
248 rv = (ULONG) NULL;
249 break;
250 default:
251 DB(("sourcetype unsupported : %ld\n",sourcetype));
252 rv = (ULONG) NULL;
256 /* now create navigation bar */
257 if(rv != (ULONG) NULL)
259 struct IBox domain;
261 if(GetDTDomain(cl, obj, &domain))
263 data->ag_Buttons = AllocAGVec(cl, obj, sizeof(navbuttons));
264 if(data->ag_Buttons != NULL)
266 memcpy(data->ag_Buttons, navbuttons, sizeof(navbuttons));
268 MakeNavGadget(cl, obj, &domain);
272 /* create external process for this object */
273 if(CreateAGProcess(cl, obj) != data->ag_Process)
274 rv = (ULONG) NULL;
278 if (rv == (ULONG)NULL)
279 CoerceMethod(cl, obj, OM_DISPOSE);
281 return rv;
285 /****** amigaguide.datatype/OM_DISPOSE ***************************************
287 NAME
288 OM_DISPOSE -- dispose an amigaguide datatype object
290 INPUT
291 none
293 FUNCTION
294 This method disposes an amigaguide datatype object. It deallocates
295 any resource obtained by the amigaguide object.
297 SEE ALSO
298 datatypes.library/DisposeDTObject(), OM_NEW
300 ******************************************************************************
304 ULONG om_dispose(Class *cl,Object *obj,Msg msg)
306 INSTDATA;
307 ULONG rv;
308 struct AmigaGuideObject *ago;
309 struct AmigaGuideFile *agf;
311 DeleteAGProcess(cl, obj);
313 /* close and unlock files, memory will be free's by DeletePool() */
314 while((agf = (struct AmigaGuideFile *) RemHead(&data->ag_Files)) != NULL)
316 if(agf->agf_Handle != NULL)
317 if(agf->agf_Flags.CloseHandle)
318 Close(agf->agf_Handle);
320 if(agf->agf_Lock != NULL)
321 UnLock(agf->agf_Lock);
324 while((ago = (struct AmigaGuideObject *) RemHead(&data->ag_Visited)) != NULL)
326 FreeAGObject(cl, obj, ago);
329 /* cleanup navigator gadget */
330 if(data->ag_Gadget != NULL)
331 DisposeObject(data->ag_Gadget);
333 /* cleanup our data here */
334 if(data->ag_Pool != NULL)
335 DeletePool(data->ag_Pool);
337 rv = DoSuperMethodA(cl,obj,msg);
339 return rv;
342 /****** amigaguide.datatype/OM_GET *******************************************
344 NAME
345 OM_GET -- gets an amigaguide datatype object attribute
347 INPUT
348 struct opGet
350 ULONG MethodID;
351 ULONG opg_AttrID;
352 ULONG *opg_Storage;
355 FUNCTION
356 This method gets an amigaguide datatype object attribute. See the
357 following TAGS section for directly supported (overwritten) attributes
358 by the datatype. All attributes of super classes are supported as
359 well.
361 TAGS
362 DTA_Title -- (STRPTR) name of the amigaguide document.
364 DTA_NominalHoriz -- (ULONG) nominal width of the document in pixel.
365 See @width AmigaGuide command.
367 DTA_NominalVert -- (ULONG) nominal height of the document in pixel.
368 See @height AmigaGuide command.
370 DTA_Methods -- (ULONG *) array of supported datatype methods.
372 SEE ALSO
373 datatypes.library/GetDTAttrsA(), OM_SET
375 ******************************************************************************
379 ULONG om_get(Class *cl,Object *obj,struct opGet *msg)
381 ULONG rv;
382 INSTDATA;
384 rv = 1;
385 switch(msg->opg_AttrID)
387 case DTA_Title:
388 *msg->opg_Storage = (ULONG) data->ag_File->agf_Name;
389 break;
390 case DTA_NominalHoriz:
392 WORD x=0,y=0;
393 GetFontDimension(cl, obj, data->ag_File->agf_Font, &x, &y);
394 *msg->opg_Storage = data->ag_File->agf_Width*x;
396 break;
397 case DTA_NominalVert:
399 WORD x=0,y=0;
400 GetFontDimension(cl, obj, data->ag_File->agf_Font, &x, &y);
401 *msg->opg_Storage = data->ag_File->agf_Height*y;
403 break;
404 case DTA_ARexxPortName:
405 *msg->opg_Storage = (ULONG) data->ag_RexxName;
406 break;
407 case DTA_TriggerMethods:
408 *msg->opg_Storage = (ULONG) triggermethods;
409 break;
411 case AGNA_Contents:
412 if(data->ag_File->agf_TOC != NULL)
413 *msg->opg_Storage = (ULONG) data->ag_File->agf_TOC;
414 else
415 *msg->opg_Storage = (ULONG) "main";
416 break;
417 case AGNA_Help:
418 if(data->ag_File->agf_Help != NULL)
419 *msg->opg_Storage = (ULONG) data->ag_File->agf_Help;
420 else
421 *msg->opg_Storage = (ULONG) "sys/amigaguide.guide";
422 break;
423 case AGNA_Index:
424 *msg->opg_Storage = (ULONG) data->ag_File->agf_Index;
425 break;
426 case DTA_Methods:
427 if(data->ag_Actual == obj)
428 *msg->opg_Storage = (ULONG) supported_methods;
429 else
430 /* get methods from sub object. */
431 if(DoMethodA(data->ag_Actual, (Msg) msg) == 0)
432 rv = 0;
433 break;
434 default:
435 rv = DoSuperMethodA(cl,obj,(Msg) msg);
438 return rv;
441 ULONG _om_update(Class *cl, Object *obj, struct opSet *msg)
443 ULONG rv = 0;
445 struct TagItem *tstate = msg->ops_AttrList;
446 struct TagItem *tag;
448 /* process attributes that only belongs to this class */
449 while((tag = NextTagItem((const struct TagItem **)&tstate)) != NULL)
451 switch(tag->ti_Tag)
453 case AGNA_Command:
454 DoTrigger(cl, obj, msg->ops_GInfo, tag->ti_Data, NULL);
455 break;
459 return rv;
462 /****** amigaguide.datatype/OM_SET *******************************************
464 NAME
465 OM_SET -- sets an amigaguide datatype object attribute
467 INPUT
468 struct opSet
470 ULONG MethodID;
471 struct TagItem *ops_AttrList;
472 struct GadgetInfo *ops_GInfo;
475 FUNCTION
476 This method sets the passed amigaguide datatype object attributes. See
477 the following TAGS section for directly supported (overwritten)
478 attributes by the datatype. All attributes of super classes are
479 supported as well.
481 TAGS
482 AGA_Secure, AGDTA_Secure -- (BOOL) if TRUE no program or ARexx script
483 will be launched by the amigaguide datatype. Defaults to FALSE.
485 SEE ALSO
486 datatypes.library/SetDTAttrsA(), OM_GET
488 ******************************************************************************
493 ULONG _om_set(Class *cl,Object *obj,struct opSet *msg)
495 INSTDATA;
496 ULONG rv = 0;
498 struct TagItem *tstate = msg->ops_AttrList;
499 struct TagItem *tag;
501 /* process attributes that only belongs to this class */
502 while((tag = NextTagItem((const struct TagItem **)&tstate)) != NULL)
504 switch(tag->ti_Tag)
506 case AGDTA_Secure:
507 case AGA_Secure:
508 data->ag_Flags.Secure = tag->ti_Data ? TRUE : FALSE;
509 break;
510 case AGDTA_HelpGroup:
511 /* TODO: help group set attr? */
512 break;
513 case DTA_Sync:
514 /* now redraw the object */
515 rv = 1;
516 break;
517 case ICA_TARGET:
518 data->ag_ICTarget = (Object *) tag->ti_Data;
519 break;
520 case ICA_MAP:
521 data->ag_ICMap = (struct TagItem *) tag->ti_Data;
522 break;
525 DA(msg->MethodID == OM_SET, ("OM_SET: %lx=0x%lx\n", tag->ti_Tag, tag->ti_Data));
526 DA(msg->MethodID == OM_UPDATE, ("OM_UPDATE: %lx=0x%lx\n", tag->ti_Tag, tag->ti_Data));
529 if(data->ag_Flags.Redraw)
530 rv++;
532 if(data->ag_Actual != obj)
534 rv += DoMethodA(data->ag_Actual, (Msg) msg);
536 return rv;
540 ULONG gm_layout(Class *cl, Object *obj, struct gpLayout *msg)
542 INSTDATA;
543 ULONG rc;
545 /* remember window pointer to be used by ARexx commands */
546 if(data->ag_Window == NULL)
547 data->ag_Window = msg->gpl_GInfo->gi_Window;
549 rc = DoSuperMethodA(cl,obj,(Msg) msg);
551 DB(("inital layout %ld\n", msg->gpl_Initial));
553 if(data->ag_Gadget == NULL)
555 struct IBox domain;
556 if(GetDTDomain(cl, obj, &domain))
557 MakeNavGadget(cl, obj, &domain);
560 if(data->ag_Gadget != NULL)
561 DoMethodA(CAST_OBJ(data->ag_Gadget),(Msg) msg);
563 if(GetDTDomain(cl, obj, &data->ag_SubObjDomain))
565 if(data->ag_Gadget != NULL)
566 data->ag_NavHeight = CAST_GAD(data->ag_Gadget)->Height + AG_NAV_DISTANCE;
568 data->ag_SubObjDomain.Top += data->ag_NavHeight;
569 data->ag_SubObjDomain.Height -= data->ag_NavHeight;
572 if(data->ag_Actual != obj)
574 rc += DoMethodA(data->ag_Actual, (Msg) msg);
575 /* adjust initial layout domain attributes */
576 if(msg->gpl_Initial)
578 SetAttrs(data->ag_Actual,
579 GA_Top, CAST_GAD(obj)->TopEdge + data->ag_NavHeight,
580 GA_RelHeight, CAST_GAD(obj)->Height - data->ag_NavHeight,
581 TAG_DONE);
585 if(!data->ag_Flags.InAsyncLayout)
587 /* if we aren't in our external process send layout msg. */
588 if(data->ag_Process != (struct Process *) FindTask(NULL))
590 struct DTSpecialInfo *si= CAST_GAD(obj)->SpecialInfo;
592 ObtainSemaphore(&data->ag_ASyncLayout);
593 if(si->si_Flags & DTSIF_LAYOUT)
595 si->si_Flags |= DTSIF_NEWSIZE;
596 /* terminate layout process */
597 Signal(&data->ag_Process->pr_Task, SIGBREAKF_CTRL_C);
598 } else
600 if(SendAGLayout(cl, obj, msg))
601 si->si_Flags |= DTSIF_LAYOUT;
603 ReleaseSemaphore(&data->ag_ASyncLayout);
604 } else
606 struct gpLayout layout = *msg;
608 layout.MethodID = DTM_ASYNCLAYOUT;
609 DoMethodA(obj, (Msg) &layout);
611 if(data->ag_Flags.GotoLine)
613 /* set possible new vertical top position (goto line). */
614 SetAttrs(obj, DTA_TopVert, data->ag_ActualObject->ago_TopVert, TAG_DONE);
615 /* and also tell others... */
616 NotifyAttrs(obj, msg->gpl_GInfo, 0,
617 GA_ID, CAST_GAD(obj)->GadgetID,
618 DTA_TopVert, data->ag_ActualObject->ago_TopVert,
619 TAG_DONE);
620 data->ag_Flags.GotoLine = FALSE;
625 return rc;
628 ULONG gm_render(Class *cl, Object *obj, struct gpRender *msg)
630 INSTDATA;
631 struct DTSpecialInfo *si= CAST_GAD(obj)->SpecialInfo;
632 ULONG rv = 0;
634 /* do not render in busy state */
635 if(si->si_Flags & DTSIF_LAYOUT)
637 DB(("gm_render(): in layout\n"));
638 data->ag_Flags.Redraw = TRUE;
639 return rv;
642 if(!AttemptSemaphore(&si->si_Lock))
644 DB(("gm_render(): lock failed\n"));
645 } else
647 /* first draw navigator gadget */
648 Object *nav = CAST_OBJ(data->ag_Gadget);
649 if(nav != NULL)
651 ULONG drawmode = msg->gpr_Redraw;
652 ULONG draw = data->ag_Flags.Redraw || drawmode == GREDRAW_REDRAW;
654 if(drawmode == GREDRAW_UPDATE)
655 if(DoMethod(nav, NVM_CHANGED))
656 draw = TRUE;
658 if(draw)
660 struct IBox *domain = &data->ag_SubObjDomain;
661 struct RastPort *rp = msg->gpr_RPort;
662 struct GadgetInfo *ginfo = msg->gpr_GInfo;
663 WORD y = domain->Top - AG_NAV_DISTANCE;
664 struct gpRender render;
666 render.MethodID = GM_RENDER;
667 render.gpr_GInfo = ginfo;
668 render.gpr_RPort = rp;
669 render.gpr_Redraw= drawmode;
671 DoMethodA(CAST_OBJ(nav), (Msg) &render);
673 SetAPen(rp, ginfo->gi_DrInfo->dri_Pens[SHINEPEN]);
674 Move(rp, domain->Left , y);
675 Draw(rp, domain->Left + domain->Width - 1, y);
676 SetAPen(rp, ginfo->gi_DrInfo->dri_Pens[SHADOWPEN]);
677 Move(rp, domain->Left , ++y);
678 Draw(rp, domain->Left + domain->Width - 1, y);
682 /* now lets draw the actual displayed object */
683 if(data->ag_Actual != obj)
685 rv = DoMethodA(data->ag_Actual, (Msg) msg);
688 rv = 1;
690 data->ag_Flags.Redraw = FALSE;
691 ReleaseSemaphore(&si->si_Lock);
694 return rv;
697 /****** amigaguide.datatype/GM_HANDLEINPUT ***********************************
699 NAME
700 GM_HANDLEINPUT -- handles input events
702 INPUT
703 struct gpInput
705 ULONG MethodID;
706 struct GadgetInfo *gpi_GInfo;
707 struct InputEvent *gpi_IEvent;
708 LONG *gpi_Termination;
709 struct
711 WORD X;
712 WORD Y;
713 } gpi_Mouse;
714 struct TabletData *gpi_TabletData;
717 FUNCTION
718 This method handles incoming input events. Checks if the event resides
719 in the navigation bar and executes any action if so. Otherwise it
720 forwards the incoming events to its viewed node or datatype object.
721 In case of an AmigaGuide node it handles any mouse event to enable
722 link activation through the mouse.
724 SEE ALSO
726 ******************************************************************************
730 ULONG gm_input(Class *cl, Object *obj, struct gpInput *msg)
732 INSTDATA;
733 struct DTSpecialInfo *si= CAST_GAD(obj)->SpecialInfo;
734 ULONG rv = GMR_MEACTIVE;
736 /* do not handle input in busy state */
737 if(si->si_Flags & DTSIF_LAYOUT)
739 rv = GMR_NOREUSE;
740 } else if(!AttemptSemaphore(&si->si_Lock))
742 rv = GMR_NOREUSE;
743 } else
745 struct InputEvent *ie = msg->gpi_IEvent;
746 struct Gadget *nav = (struct Gadget *) data->ag_Gadget;
748 switch(ie->ie_Class)
750 case IECLASS_RAWMOUSE:
751 if(nav != NULL && ((msg->gpi_Mouse.Y < nav->Height &&
752 !data->ag_Flags.InDocInput) ||
753 data->ag_Flags.InNavInput))
755 /* check if gadget is even active. This is needed to deactivate the gadget, if
756 * the user makes a great step with the mouse, so that msg->gpi_Mouse.Y > nav->Height !
758 rv = DoMethodA(CAST_OBJ(nav),(Msg) msg);
760 data->ag_Flags.InNavInput = (rv == GMR_MEACTIVE) ? TRUE : FALSE;
761 } else if(data->ag_Actual != obj)
763 /* adjust mouse y coordinate so the sub-object doesn't need to
764 * know about the navigation bar height.
766 msg->gpi_Mouse.Y -= (nav->Height + AG_NAV_DISTANCE);
768 rv = DoMethodA(data->ag_Actual, (Msg) msg);
770 data->ag_Flags.InDocInput = (rv == GMR_MEACTIVE) ? TRUE : FALSE;
772 break;
774 ReleaseSemaphore(&si->si_Lock);
777 return rv;
780 ULONG dtm_removedtobject(Class *cl, Object *obj, Msg msg)
782 INSTDATA;
784 /* clear window pointer which is used in the external process
785 using DoDTMethod() to get a valid GInfo structure. */
786 data->ag_Window = NULL;
788 #if 0
789 CLASSBASE;
790 if(data->ag_Gadget != NULL)
792 DisposeObject(data->ag_Gadget);
793 data->ag_Gadget = NULL;
795 #endif
797 return DoSuperMethodA(cl, obj, msg);
800 ULONG dtm_asynclayout(Class *cl, Object *obj, struct gpLayout *msg)
802 INSTDATA;
803 struct DTSpecialInfo *si = (struct DTSpecialInfo *) CAST_GAD(obj)->SpecialInfo;
804 struct DTSpecialInfo *sosi = (struct DTSpecialInfo *) CAST_GAD(data->ag_Actual)->SpecialInfo;
805 struct IBox domain;
806 LONG topv,totv,unitv;
807 LONG toph,toth,unith;
808 STRPTR title = "amigaguide.datatype";
810 GetDTDomain(cl, obj, &domain);
812 ObtainSemaphore(&si->si_Lock);
814 /* indicate sub object that we are in layout */
815 sosi->si_Flags |= DTSIF_LAYOUT;
817 /* try to load initial node */
818 if(data->ag_Actual == obj)
820 data->ag_Flags.InAsyncLayout = TRUE;
821 GotoObject(cl, obj, msg->gpl_GInfo, data->ag_InitialNode, 0);
822 data->ag_Flags.InAsyncLayout = FALSE;
825 /* layout the actual sub object. */
826 if(data->ag_Actual != obj)
828 BOOL initial = msg->gpl_Initial;
829 ULONG mid = msg->MethodID;
831 /* if ag_Flags.InitialLayout is set to TRUE, the sub-object
832 * needs an initial layout! */
833 if(data->ag_Flags.InitialLayout)
835 msg->gpl_Initial = TRUE;
836 data->ag_Flags.InitialLayout = FALSE;
839 /* we are in asynclayout, so make really sure, overwriting proclayout id! */
840 msg->MethodID = DTM_ASYNCLAYOUT;
841 DoMethodA(data->ag_Actual, (Msg) msg);
842 msg->MethodID = mid;
844 if(!initial)
845 msg->gpl_Initial = FALSE;
848 if(GetDTAttrs(data->ag_Actual,
849 DTA_TopVert, (ULONG) &topv,
850 DTA_TotalVert, (ULONG) &totv,
851 DTA_TopHoriz, (ULONG) &toph,
852 DTA_TotalHoriz, (ULONG) &toth,
853 DTA_VertUnit, (ULONG) &unitv,
854 DTA_HorizUnit, (ULONG) &unith,
855 TAG_DONE) == 6)
857 unitv = (unitv == 0) ? 1 : unitv;
858 unith = (unith == 0) ? 1 : unith;
860 if(GetDTAttrs(data->ag_Actual, DTA_Title, (ULONG) &title, TAG_DONE) == 0)
861 if(GetDTAttrs(data->ag_Actual, DTA_Name, (ULONG) &title, TAG_DONE) == 0)
862 title = "unknown";
863 /* these values must be set explicitly
864 * possible error in datatypesclass ?
866 si->si_VisVert = (domain.Height - data->ag_NavHeight) / unitv;
867 si->si_VisHoriz = domain.Width / unith;
869 DB(("topvert %ld, visvert %ld, totvert %ld\n",
870 topv, si->si_VisVert, totv));
871 if(msg->gpl_Initial)
873 /* fix for a different version of the datatypesclass, normally
874 * this should be done by the datatypesclass itself */
875 si->si_TopVert = -1;
876 si->si_TopHoriz = -1;
877 } else
879 #if 1
880 /* TODO: if wrapping is on this value maybe wrong after an layout */
881 /* remember last vertical top value */
882 si->si_TopVert = topv;
883 si->si_TopHoriz = toph;
884 #endif
887 #if 1
888 si->si_TotVert = totv;
889 si->si_TotHoriz = toth;
890 #endif
892 DB(("before async notify...\n"));
894 NotifyAttrs(obj, msg->gpl_GInfo, 0,
895 GA_ID, CAST_GAD(obj)->GadgetID,
897 DTA_TopVert, topv,
898 DTA_TotalVert, totv,
899 DTA_VertUnit, unitv,
900 DTA_VisibleVert,si->si_VisVert,
902 DTA_TopHoriz, toph,
903 DTA_TotalHoriz, toth,
904 DTA_HorizUnit, unith,
905 DTA_VisibleHoriz,si->si_VisHoriz,
907 DTA_Title, title,
909 DTA_Busy, FALSE,
910 DTA_Sync, TRUE,
911 TAG_DONE);
914 /* layout done... */
915 sosi->si_Flags &= ~DTSIF_LAYOUT;
917 ReleaseSemaphore(&si->si_Lock);
919 return totv;
922 /****** amigaguide.datatype/DTM_TRIGGER **************************************
924 NAME
925 DTM_TRIGGER -- triggers some functions on the AmigaGuide object.
927 INPUT
928 struct dtTrigger
930 ULONG MethodID;
931 struct GadgetInfo *dtt_GInfo;
932 ULONG dtt_Function;
933 APTR dtt_Data;
936 FUNCTION
937 This method triggers the following functions specified via the
938 dtt_Function field of the message. NOTE that you have to mask out
939 the real STM_#? function from the field by applying the function
940 mask (dtt_Function & STMG_METHOD_MASK):
942 STM_RETRACE -- Go to the previous viewed node. Same as pressing the
943 "Retrace" button
945 STM_HELP -- Go to the help node. Same as pressing the "Help" button
947 STM_INDEX -- Go to the index node. Same as pressing the "Index" button
949 STM_CONTENTS -- Go to the contents/main node. Same as pressing the
950 "Contents" button
952 STM_BROWSE_PREV -- Go to the previous logical node in the database.
953 Same as pressing the "< Browse" button
955 STM_BROWSE_NEXT -- Go to the next logical node in the database. Same
956 as pressing the "> Browse" button
958 STM_COMMAND -- Execute the command found in the dtt_Data field.
959 Currently only null-terminated strings are supported. To make this
960 function save it only operates on data found in dtt_Data if
961 (dtt_Function & STMF_DATA_MASK) == STMD_STRPTR. The following
962 commands are supported:
964 link <nodename> -- Goto to the named node.
965 system <command> -- Execute the given command.
966 rxs <arexx-string> -- Executes the given ARexx string.
967 rx <arexx-script> -- Executes the given ARexx macro script.
969 STM_PREV_FIELD -- if the current node has links select previous link.
971 STM_NEXT_FIELD -- if the current node has links select next link.
973 STM_ACTIVATE_FIELD -- if a link is selected activate it, by sending
974 a STM_COMMAND trigger method.
976 SEE ALSO
977 DTM_GOTO
979 ******************************************************************************
984 ULONG dtm_trigger(Class *cl, Object *obj, struct dtTrigger *msg)
986 INSTDATA;
987 ULONG rv = 0;
989 /* make sure any trigger command is only executed in our external
990 * process context!
992 if(data->ag_Process != (struct Process *) FindTask(NULL))
994 SendAGTrigger(cl, obj, msg);
995 return 0;
998 DB(("do trigger command (proc=\"%s\") function=%lx\n",
999 FindTask(NULL)->tc_Node.ln_Name, msg->dtt_Function));
1001 switch(msg->dtt_Function & STMF_METHOD_MASK)
1003 case STM_RETRACE:
1004 if(data->ag_ActualObject->ago_Node.ln_Succ->ln_Succ != NULL)
1006 struct AmigaGuideObject *old = (struct AmigaGuideObject *) RemHead(&data->ag_Visited);
1007 DB(("old is %lx (%s)\n", old, old->ago_Node.ln_Name));
1008 data->ag_Flags.GotoLine = TRUE;
1009 ActivateAGObject(cl, obj, msg->dtt_GInfo,
1010 (struct AmigaGuideObject *) data->ag_Visited.lh_Head);
1011 FreeAGObject(cl, obj, old);
1013 break;
1014 case STM_COMMAND:
1016 ULONG cmdtype = CMDTYPE_UNKNOWN;
1017 STRPTR dest = "";
1018 STRPTR destend = NULL;
1019 LONG line = 0;
1020 UBYTE chr = '"';
1022 DB(("got trigger command\n"));
1023 switch(msg->dtt_Function & STMF_DATA_MASK)
1025 case STMD_STRPTR: {
1026 STRPTR type, typeend;
1027 STRPTR ptr = (STRPTR) msg->dtt_Data;
1029 DB(("string is %s\n", ptr));
1030 type = ptr;
1031 while(*ptr != '\0' && *ptr != ' ' && *ptr != '\t')
1032 ++ptr;
1033 typeend = ptr;
1034 ptr = eatws(ptr);
1035 if(*ptr != '"')
1037 dest = ptr;
1038 while(*ptr != '\0' && *ptr != ' ' && *ptr != '\t')
1039 ++ptr;
1040 destend = ptr;
1041 chr = *destend;
1042 ptr = eatws(ptr);
1043 /* get line number to goto. */
1044 if(*ptr != '\0')
1045 StrToLong(ptr, &line);
1046 *destend = '\0';
1047 } else
1049 dest = ++ptr;
1050 while(*ptr != '\0' && *ptr != '"')
1051 ptr++;
1052 destend = ptr;
1053 chr = *destend;
1054 if(*ptr == '"')
1056 ptr = eatws(ptr+1);
1057 /* get line number to goto. */
1058 if(*ptr != '\0')
1059 StrToLong(ptr, &line);
1061 *destend = '\0';
1064 if(!Strnicmp(type, "link", typeend-type))
1065 cmdtype = CMDTYPE_LINK;
1066 else if(!Strnicmp(type, "system", typeend-type))
1067 cmdtype = CMDTYPE_SYSTEM;
1068 else if(!Strnicmp(type, "rxs", typeend-type) && (typeend-type) == 3)
1069 cmdtype = CMDTYPE_RXS;
1070 else if(!Strnicmp(type, "rx", typeend-type))
1071 cmdtype = CMDTYPE_RX;
1072 } break;
1075 DB(("cmdtype %ld (dest=\"%s\") %ld\n", cmdtype, dest, line));
1076 if(*dest != '\0')
1077 switch(cmdtype)
1079 case CMDTYPE_LINK:
1080 rv = GotoObject(cl, obj, msg->dtt_GInfo, dest, line);
1081 break;
1082 case CMDTYPE_SYSTEM:
1083 SystemCommand(cl, obj, dest);
1084 break;
1085 case CMDTYPE_RXS:
1086 SendRexxCommand(cl, obj, dest, AGRX_RXS);
1087 break;
1088 case CMDTYPE_RX:
1089 SendRexxCommand(cl, obj, dest, AGRX_RX);
1090 break;
1091 default:
1092 DB(("unknown command\n"));
1094 if(destend != NULL)
1095 *destend = chr;
1097 break;
1098 case STM_HELP:
1099 rv = GotoObjectTag(cl, obj, msg->dtt_GInfo, AGNA_Help);
1100 break;
1101 case STM_CONTENTS:
1102 rv = GotoObjectTag(cl, obj, msg->dtt_GInfo, AGNA_Contents);
1103 break;
1104 case STM_INDEX:
1105 rv = GotoObjectTag(cl, obj, msg->dtt_GInfo, AGNA_Index);
1106 break;
1107 case STM_BROWSE_PREV:
1108 rv = GotoObjectTag(cl, obj, msg->dtt_GInfo, AGNA_Previous);
1109 /* no object found try previous node in linked list */
1110 if(rv == 0)
1112 if(data->ag_ActualObject->ago_AGNode->agn_Node.ln_Pred->ln_Pred != NULL)
1113 rv = GotoObject(cl, obj, msg->dtt_GInfo, data->ag_ActualObject->ago_AGNode->agn_Node.ln_Pred->ln_Name, 0);
1115 break;
1116 case STM_BROWSE_NEXT:
1117 rv = GotoObjectTag(cl, obj, msg->dtt_GInfo, AGNA_Next);
1118 /* no object found try next node in linked list */
1119 if(rv == 0)
1121 if(data->ag_ActualObject->ago_AGNode->agn_Node.ln_Succ->ln_Succ != NULL)
1122 rv = GotoObject(cl, obj, msg->dtt_GInfo, data->ag_ActualObject->ago_AGNode->agn_Node.ln_Succ->ln_Name, 0);
1124 break;
1125 default:
1126 rv = DoMethodA(data->ag_Actual, (Msg) msg);
1129 return rv;
1132 static
1133 void UpdateNavigator(Class *cl, Object *obj, struct GadgetInfo *ginfo)
1135 INSTDATA;
1136 struct AmigaGuideObject *agobj = data->ag_ActualObject;
1138 struct npChangeStatus chg;
1139 struct NavigatorStatus cmds[6];
1140 STRPTR toc = NULL;
1141 STRPTR index = NULL;
1142 STRPTR prev = NULL;
1143 STRPTR next = NULL;
1144 STRPTR help = NULL;
1146 GetDTAttrs(data->ag_Actual,
1147 AGNA_Contents, (ULONG) &toc,
1148 AGNA_Index, (ULONG) &index,
1149 AGNA_Previous, (ULONG) &prev,
1150 AGNA_Next, (ULONG) &next,
1151 AGNA_Help, (ULONG) &help,
1152 TAG_DONE);
1154 if(help == NULL)
1156 BOOL nodetype;
1157 BPTR lock = GetFileLock(cl, obj, "sys/amigaguide.guide", &nodetype);
1158 if(lock != NULL)
1160 UnLock(lock);
1161 help = "sys/amigaguide.guide";
1162 SetAttrs(data->ag_Actual,
1163 AGNA_Help, (ULONG) help,
1164 TAG_DONE);
1167 cmds[0].ns_Command = STM_CONTENTS;
1168 cmds[0].ns_Status = (toc == NULL && !Stricmp(agobj->ago_Node.ln_Name, "main")) ? NVS_DISABLE : NVS_ENABLE;
1169 cmds[1].ns_Command = STM_INDEX;
1170 cmds[1].ns_Status = (index == NULL || !Stricmp(agobj->ago_Node.ln_Name, index)) ? NVS_DISABLE : NVS_ENABLE;
1171 cmds[2].ns_Command = STM_RETRACE;
1172 cmds[2].ns_Status = (agobj->ago_Node.ln_Succ->ln_Succ == NULL) ? NVS_DISABLE : NVS_ENABLE;
1173 cmds[3].ns_Command = STM_BROWSE_PREV;
1174 cmds[3].ns_Status = (prev == NULL && (agobj->ago_AGNode == NULL || agobj->ago_AGNode->agn_Node.ln_Pred->ln_Pred == NULL)) ? NVS_DISABLE : NVS_ENABLE;
1175 cmds[4].ns_Command = STM_BROWSE_NEXT;
1176 cmds[4].ns_Status = (next == NULL && (agobj->ago_AGNode == NULL || agobj->ago_AGNode->agn_Node.ln_Succ->ln_Succ == NULL)) ? NVS_DISABLE : NVS_ENABLE;
1177 cmds[5].ns_Command = STM_HELP;
1178 cmds[5].ns_Status = (help == NULL) ? NVS_DISABLE : NVS_ENABLE;
1180 chg.MethodID = NVM_CHANGESTATUS;
1181 chg.np_GInfo = ginfo;
1182 chg.np_NumCommands = 6;
1183 chg.np_Commands = cmds;
1185 if(DoMethodA(CAST_OBJ(data->ag_Gadget), (Msg) &chg))
1187 NotifyAttrs(obj, ginfo, 0,
1188 GA_ID, CAST_GAD(obj)->GadgetID,
1189 DTA_Sync, TRUE,
1190 TAG_DONE);
1194 static
1195 void ActivateAGObject(Class *cl, Object *obj, struct GadgetInfo *ginfo,
1196 struct AmigaGuideObject *agobj)
1198 INSTDATA;
1199 struct gpLayout layout;
1200 struct IBox *domain;
1202 data->ag_Actual = agobj->ago_Object;
1203 data->ag_ActualObject = agobj;
1205 /* if the current object is an amigaguide node set the appropriate
1206 file structure into the global data section to find nodes within
1207 this AmigaGuide file again. */
1208 if(agobj->ago_AGNode != NULL)
1209 data->ag_File = agobj->ago_AGNode->agn_File;
1211 /* adjust state of navigation bar */
1212 UpdateNavigator(cl, obj, ginfo);
1214 /* clear object domain */
1216 struct RastPort *rp;
1218 domain = &data->ag_SubObjDomain;
1219 rp = ObtainGIRPort(ginfo);
1220 if(rp != NULL)
1222 EraseRect(rp, domain->Left, domain->Top,
1223 domain->Left+domain->Width-1,
1224 domain->Top+domain->Height-1);
1225 ReleaseGIRPort(rp);
1229 /* now lets layout our and its sub object. */
1230 layout.MethodID = GM_LAYOUT;
1231 layout.gpl_GInfo = ginfo;
1232 layout.gpl_Initial = FALSE;
1233 DoMethodA(obj, (Msg) &layout);
1237 /****** amigaguide.datatype/DTM_GOTO *****************************************
1239 NAME
1240 DTM_GOTO -- goto the given node/object.
1242 INPUT
1243 struct dtGoto
1245 ULONG MethodID;
1246 struct GadgetInfo *dtg_GInfo;
1247 STRPTR dtg_NodeName;
1248 struct TagItem *dtg_AttrList;
1251 FUNCTION
1252 This method tries to load and view the node or object specified in the
1253 dtg_NodeName field. This field can also contain a file name for a file
1254 to be viewed within the AmigaGuide object. And this also may have an
1255 additionally added node name. For example if you want to open an
1256 external AmigaGuide file called index.guide and you want to open the
1257 node named "B" for index entries starting with the letter "B" you can
1258 just pass index.guide/B to the method via the dtg_NodeName field. Also
1259 the tags listed in the TAGS section are passed to the newly created
1260 datatype object.
1262 TAGS
1263 DTA_TopVert -- vertical (line) position to go to.
1265 RETURN
1266 1 -- if object could be loaded
1267 0 -- if object could not be found
1268 -1 -- if some error occured during loading
1270 SEE ALSO
1271 DTM_TRIGGER
1273 ******************************************************************************
1278 ULONG dtm_goto(Class *cl, Object *obj, struct dtGoto *msg)
1280 CLASSBASE;
1281 INSTDATA;
1282 ULONG rv = 0;
1283 struct DataType *dt;
1284 struct AmigaGuideNode *agnode;
1285 struct AmigaGuideObject *agobj = NULL;
1286 Object *dtobj = NULL;
1287 LONG err = 0;
1289 UBYTE fontname[MAXFONTNAME];
1290 struct TextAttr ta;
1291 struct TextAttr *textattr = NULL;
1292 BOOL aginternal = TRUE;
1294 if(msg->dtg_NodeName == NULL || *msg->dtg_NodeName == '\0')
1296 NotifyAttrs(obj, msg->dtg_GInfo, 0,
1297 GA_ID, CAST_GAD(obj)->GadgetID,
1298 DTA_Busy, FALSE,
1299 DTA_ErrorString, "goto empty node name",
1300 DTA_ErrorNumber, ERROR_REQUIRED_ARG_MISSING,
1301 DTA_ErrorLevel, 1,
1302 TAG_DONE);
1303 return -1;
1306 if(data->ag_File->agf_Font != NULL)
1308 ta.ta_Name = fontname;
1309 DB(("parse font %s\n", data->ag_File->agf_Font));
1310 ParseFontLine(cl, obj, data->ag_File->agf_Font, &ta);
1311 textattr = &ta;
1314 DB(("try loading object \"%s\"\n", msg->dtg_NodeName));
1316 /* currently protected input.device task */
1317 if(FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS)
1319 DB(("goto object \"%s\" within input task\n", msg->dtg_NodeName));
1320 return 1;
1323 /* TODO: check this work around...
1324 * don't notify loading title if its the main and initial node. There
1325 * are some asynchron notification problems. Sometimes this notification
1326 * is send to MultiView after the complete async layout method has
1327 * completed including all notifications (DTA_Busy == FALSE). Which is
1328 * then overwritten by this notification...
1330 if(!data->ag_Flags.InAsyncLayout)
1332 mysprintf(cb, data->ag_Message, sizeof(data->ag_Message),
1333 "Loading %s ...", msg->dtg_NodeName);
1335 NotifyAttrs(obj, msg->dtg_GInfo, 0,
1336 GA_ID, CAST_GAD(obj)->GadgetID,
1337 DTA_Busy, TRUE,
1338 DTA_Title, data->ag_Message,
1339 TAG_DONE);
1341 agnode = GetAGNode(cl, obj, data->ag_File, msg->dtg_NodeName);
1342 if(agnode == NULL)
1344 STRPTR file = CopyAGString(cl, obj, msg->dtg_NodeName);
1345 aginternal = FALSE;
1346 if(file != NULL)
1348 BOOL nodetype = FALSE;
1349 BPTR lock = GetFileLock(cl, obj, file, &nodetype);
1351 DB(("node \"%s\" not found (lock=%lx)\n", file, lock));
1353 if(lock != NULL)
1355 if((dt = ObtainDataTypeA(DTST_FILE, (APTR) lock, NULL)) != NULL)
1357 if(nodetype == TRUE && !Strnicmp(dt->dtn_Header->dth_Name, "AmigaGuide", 10))
1359 struct AmigaGuideFile *agf = (struct AmigaGuideFile *) data->ag_Files.lh_Head;
1361 /* search current list of opened AG files */
1362 while(agf->agf_Node.ln_Succ != NULL)
1364 if(SameLock(agf->agf_Lock, lock) == LOCK_SAME)
1366 /* found a previously opened AG file, so try to find node */
1367 agnode = GetAGNode(cl, obj, agf, FilePart(msg->dtg_NodeName));
1368 if(agnode != NULL)
1370 /* set active AG file */
1371 data->ag_File = agf;
1372 break;
1375 agf = (struct AmigaGuideFile *) agf->agf_Node.ln_Succ;
1378 /* no ag file and node found so load it now */
1379 if(agnode == NULL)
1381 DB(("found amigaguide file\n"));
1382 agf = AllocAGFile(cl, obj);
1383 if(agf != NULL)
1385 if((agf->agf_Handle = OpenFromLock(lock)) != NULL)
1387 agf->agf_Lock = DupLockFromFH(agf->agf_Handle);
1388 agf->agf_Flags.CloseHandle = TRUE;
1389 lock = NULL;
1390 ScanFile(cl, obj, agf);
1391 data->ag_File = agf;
1392 agnode = GetAGNode(cl, obj, data->ag_File, FilePart(msg->dtg_NodeName));
1396 } else
1398 STRPTR filename = AllocAGMem(cl, obj, 1024);
1399 agobj = AllocAGObject(cl, obj);
1400 if(agobj != NULL && filename != NULL)
1402 NameFromLock(lock, filename, 1024);
1403 DB(("try to open file \"%s\"\n", file));
1404 DTL(msg->dtg_AttrList);
1405 if(msg->dtg_AttrList != NULL)
1406 agobj->ago_TopVert = GetTagData(DTA_TopVert, 0, msg->dtg_AttrList);
1407 agobj->ago_Object =
1408 dtobj = NewDTObject(filename,
1409 GA_Immediate, TRUE,
1410 GA_RelVerify, TRUE,
1411 GA_Top, data->ag_SubObjDomain.Top,
1412 GA_Left, data->ag_SubObjDomain.Left,
1413 GA_RelWidth, CAST_GAD(obj)->Width,
1414 GA_RelHeight, CAST_GAD(obj)->Height - data->ag_NavHeight,
1415 GA_ID, CAST_GAD(obj)->GadgetID,
1416 ICA_TARGET, (ULONG) data->ag_ICTarget,
1417 ICA_MAP, (ULONG) data->ag_ICMap,
1418 DTA_TopVert, agobj->ago_TopVert,
1419 (textattr != NULL) ? DTA_TextAttr : TAG_IGNORE, (ULONG) textattr,
1420 TAG_DONE);
1421 data->ag_Flags.InitialLayout = TRUE;
1422 } else
1424 rv = 0;
1427 if(filename != NULL)
1428 FreeAGMem(cl, obj, filename, 1024);
1430 ReleaseDataType(dt);
1432 UnLock(lock);
1434 FreeAGVec(cl ,obj, file);
1438 if(agnode != NULL)
1440 /* GEORGFIX: data->ag_ActualObject could be NULL here so added
1441 "data->ag_ActualObject" to checks (to make sure it is != NULL) */
1443 if(data->ag_ActualObject && data->ag_ActualObject->ago_AGNode != NULL && aginternal &&
1444 !Stricmp(agnode->agn_Node.ln_Name, data->ag_ActualObject->ago_AGNode->agn_Node.ln_Name))
1446 DB(("link within same node \"%s\"\n", agnode->agn_Node.ln_Name));
1447 agobj = AllocAGObject(cl, obj);
1448 if(agobj != NULL)
1450 dtobj = agobj->ago_Object = data->ag_Actual;
1451 agobj->ago_AGNode = data->ag_ActualObject->ago_AGNode;
1452 agobj->ago_NoDispose = TRUE;
1454 } else
1456 agobj = AllocAGObjectNode(cl, obj, data->ag_File, agnode);
1457 if(agobj != NULL)
1459 char buf[64];
1460 LONG i=0;
1463 mysprintf(cb, buf, sizeof(buf), "T:%s_%ld", FilePart(msg->dtg_NodeName), ++i);
1464 agobj->ago_TmpHandle = Open(buf, MODE_NEWFILE);
1465 } while(agobj->ago_TmpHandle == NULL && i<100);
1466 if(agobj->ago_TmpHandle != NULL)
1468 Write(agobj->ago_TmpHandle, agobj->ago_Buffer, agobj->ago_BufferLen);
1469 Close(agobj->ago_TmpHandle);
1470 agobj->ago_TmpHandle = Lock(buf, SHARED_LOCK);
1473 if(agnode->agn_Font != NULL)
1475 ta.ta_Name = fontname;
1476 ParseFontLine(cl, obj, agnode->agn_Font, &ta);
1477 textattr = &ta;
1480 dt = ObtainDataTypeA(DTST_FILE, (APTR) agobj->ago_TmpHandle, NULL);
1481 #if 0
1482 /* TODO: Currently MorphOS datatypes.library doesn't support DTST_MEMORY... */
1483 DTA_SourceType, DTST_MEMORY,
1484 DTA_SourceAddress,agobj->ago_Buffer,
1485 DTA_SourceSize, agobj->ago_BufferLen,
1486 TAG_DONE);
1487 #endif
1488 DA(dt == NULL, ("can't determine datatype\n"));
1490 if(dt != NULL)
1492 agobj->ago_Object =
1493 dtobj = NewObject(cb->cb_NodeClass, NULL,
1494 GA_Top, data->ag_SubObjDomain.Top,
1495 GA_Left, data->ag_SubObjDomain.Left,
1496 GA_RelWidth, CAST_GAD(obj)->Width,
1497 GA_RelHeight, CAST_GAD(obj)->Height - data->ag_NavHeight,
1498 GA_ID, CAST_GAD(obj)->GadgetID,
1499 DTA_DataType, (ULONG) dt,
1500 DTA_Name, (ULONG) buf,
1501 DTA_SourceType, DTST_FILE,
1502 DTA_Handle, (ULONG) agobj->ago_TmpHandle,
1503 ICA_TARGET, (ULONG) data->ag_ICTarget,
1504 ICA_MAP, (ULONG) data->ag_ICMap,
1505 /* special attributes for amigagudienode class */
1506 AGNA_RootObject, (ULONG) obj,
1507 AGNA_AGFile, (ULONG) data->ag_File,
1509 (textattr != NULL) ? DTA_TextAttr : TAG_IGNORE, (ULONG) textattr,
1510 (msg->dtg_AttrList != NULL) ? TAG_MORE : TAG_DONE, (ULONG) msg->dtg_AttrList);
1511 if(dtobj != NULL)
1513 agobj->ago_TmpHandle = NULL;
1514 data->ag_Flags.InitialLayout = TRUE;
1516 ReleaseDataType(dt);
1522 if(dtobj == NULL)
1524 err = IoErr();
1525 DB(("couldn't create dtobj %ld for node=\"%s\"\n", err, msg->dtg_NodeName));
1526 if(agobj != NULL)
1527 FreeAGObject(cl, obj, agobj);
1528 } else
1530 AddHead(&data->ag_Visited, &agobj->ago_Node);
1531 if(msg->dtg_AttrList != NULL)
1532 agobj->ago_TopVert = GetTagData(DTA_TopVert, 0, msg->dtg_AttrList);
1533 DB(("top vert is %ld\n", agobj->ago_TopVert));
1534 ActivateAGObject(cl, obj, msg->dtg_GInfo, agobj);
1535 rv = 1;
1538 if(err != 0)
1540 DB(("error occured %ld for node=\"%s\"\n", err, msg->dtg_NodeName));
1542 NotifyAttrs(obj, msg->dtg_GInfo, 0,
1543 GA_ID, CAST_GAD(obj)->GadgetID,
1544 DTA_Busy, FALSE,
1545 DTA_ErrorString, msg->dtg_NodeName,
1546 DTA_ErrorNumber, err,
1547 DTA_ErrorLevel, 1,
1548 TAG_DONE);
1549 rv = -1;
1552 return rv;
1555 #ifdef __AROS__
1556 IPTR om_update(Class *cl, Object *obj, struct opSet *msg)
1558 ULONG rv;
1560 /* avoid update loops */
1561 if(DoMethod(obj, ICM_CHECKLOOP))
1562 return (IPTR)0;
1564 rv = _om_update(cl, obj, msg);
1565 rv += _om_set(cl, obj, msg);
1567 rv += (ULONG)DoSuperMethodA(cl, obj, (Msg) msg);
1569 DB(("set returned %ld\n", rv));
1570 /* this class is derived from the gadgetclass, check
1571 * if the gadget needs a refresh : */
1572 if(rv != 0 && (OCLASS (obj) == cl))
1574 struct RastPort *rp;
1575 if((rp = ObtainGIRPort(CAST_SET(msg)->ops_GInfo)) != NULL)
1577 struct gpRender render;
1578 render.MethodID = GM_RENDER;
1579 render.gpr_GInfo = CAST_SET(msg)->ops_GInfo;
1580 render.gpr_RPort = rp;
1581 render.gpr_Redraw= GREDRAW_UPDATE;
1582 DoMethodA(obj, (Msg) &render);
1584 ReleaseGIRPort(rp);
1588 return (IPTR)rv;
1591 IPTR om_set(Class *cl, Object *obj, struct opSet *msg)
1593 ULONG rv = _om_set(cl, obj, CAST_SET(msg));
1595 rv += (ULONG)DoSuperMethodA(cl, obj, (Msg) msg);
1597 DB(("set returned %ld\n", rv));
1598 /* this class is derived from the gadgetclass, check
1599 * if the gadget needs a refresh : */
1600 if(rv != 0 && (OCLASS (obj) == cl))
1602 struct RastPort *rp;
1603 if((rp = ObtainGIRPort(CAST_SET(msg)->ops_GInfo)) != NULL)
1605 struct gpRender render;
1606 render.MethodID = GM_RENDER;
1607 render.gpr_GInfo = CAST_SET(msg)->ops_GInfo;
1608 render.gpr_RPort = rp;
1609 render.gpr_Redraw= GREDRAW_UPDATE;
1610 DoMethodA(obj, (Msg) &render);
1612 ReleaseGIRPort(rp);
1616 return (IPTR)rv;
1619 IPTR dtm_proclayout(Class *cl, Object *obj, struct gpLayout *msg)
1621 DoSuperMethodA(cl, obj, (Msg)msg);
1623 return dtm_asynclayout(cl, obj, msg);
1626 #else /* !defined(__AROS__) */
1628 IPTR class_dispatcher(Class *cl, Object *obj, Msg msg)
1630 CLASSBASE;
1631 IPTR rv = 0;
1633 switch(msg->MethodID)
1635 case OM_NEW:
1636 rv = om_new(cl, obj, CAST_SET(msg));
1637 break;
1638 case OM_DISPOSE:
1639 rv = om_dispose(cl, obj, msg);
1640 break;
1642 case OM_GET:
1643 rv = om_get(cl,obj,(struct opGet *) msg);
1644 break;
1646 case OM_UPDATE:
1647 /* avoid update loops */
1648 if(DoMethod(obj, ICM_CHECKLOOP))
1649 break;
1651 rv = _om_update(cl, obj, CAST_SET(msg));
1652 case OM_SET:
1653 rv += _om_set(cl, obj, CAST_SET(msg));
1655 rv += DoSuperMethodA(cl, obj, (Msg) msg);
1657 DB(("set returned %ld\n", rv));
1658 /* this class is derived from the gadgetclass, check
1659 * if the gadget needs a refresh : */
1660 if(rv != 0 && (OCLASS (obj) == cl))
1662 struct RastPort *rp;
1663 if((rp = ObtainGIRPort(CAST_SET(msg)->ops_GInfo)) != NULL)
1665 struct gpRender render;
1666 render.MethodID = GM_RENDER;
1667 render.gpr_GInfo = CAST_SET(msg)->ops_GInfo;
1668 render.gpr_RPort = rp;
1669 render.gpr_Redraw= GREDRAW_UPDATE;
1670 DoMethodA(obj, (Msg) &render);
1672 ReleaseGIRPort(rp);
1675 break;
1676 case GM_LAYOUT:
1677 rv = gm_layout(cl, obj, CAST_GPL(msg));
1678 break;
1679 case GM_RENDER:
1680 rv = gm_render(cl, obj, (struct gpRender *) msg);
1681 break;
1682 case GM_GOACTIVE:
1683 case GM_HANDLEINPUT:
1684 rv = gm_input(cl, obj, (struct gpInput *) msg);
1685 break;
1686 case DTM_REMOVEDTOBJECT:
1687 rv = dtm_removedtobject(cl, obj, msg);
1688 break;
1689 case DTM_PROCLAYOUT:
1690 rv = DoSuperMethodA(cl, obj, msg);
1691 /* fall through */
1692 case DTM_ASYNCLAYOUT:
1693 rv = dtm_asynclayout(cl, obj, CAST_GPL(msg));
1694 break;
1695 case DTM_TRIGGER:
1696 rv = dtm_trigger(cl, obj, (struct dtTrigger *) msg);
1697 break;
1698 case DTM_GOTO:
1699 rv = dtm_goto(cl, obj, (struct dtGoto *) msg);
1700 break;
1701 default:
1702 rv = DoSuperMethodA(cl,obj,msg);
1705 return rv;
1708 #endif /* __AROS__ */