/* nodehost.c * Written by David N. Junod * * Example of a Dynamic Node Host. This example is useful for determining * what nodes an AmigaGuide database is calling when it brings up the * "Can't locate node" requester. * * I use it when I'm writing help files for AppShell applications... * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct Library *SysBase, *DOSBase; struct Library *IntuitionBase, *GfxBase, *AmigaGuideBase; void kprintf (void *, ...); #define DB(x) ; #define ASM __asm #define REG(x) register __ ## x ULONG __saveds dispatchAmigaGuideHost (struct Hook *h, STRPTR db, Msg msg); ULONG ASM hookEntry (register __a0 struct Hook *,register __a2 VOID *,register __a1 VOID *); main (int argc, char **argv) { struct Hook hook; AMIGAGUIDEHOST hh; IntuitionBase = OpenLibrary ("intuition.library", 0); GfxBase = OpenLibrary ("graphics.library", 0); /* amigaguide.library works with 1.3 and newer versions of the OS */ if (AmigaGuideBase = OpenLibrary ("amigaguide.library", 33)) { /* Initialize the hook */ hook.h_Entry = hookEntry; hook.h_SubEntry = dispatchAmigaGuideHost; /* Add the AmigaGuideHost to the system */ if (hh = AddAmigaGuideHost (&hook, "ExampleHost", NULL)) { printf ("Added AmigaGuideHost 0x%lx\n", hh); /* Wait until we're told to quit */ Wait (SIGBREAKF_CTRL_C); printf ("Remove AmigaGuideHost 0x%lx", hh); /* Try removing the host */ while (RemoveAmigaGuideHost (hh, NULL) > 0) { /* Wait a while */ printf ("."); Delay (250); } printf ("\n"); } else { printf ("Couldn't add AmigaGuideHost\n"); } /* close the library */ CloseLibrary (AmigaGuideBase); } CloseLibrary (GfxBase); CloseLibrary (IntuitionBase); } /*** Common tag manipulation routines ************************************/ struct TagItem *nextTagItem(struct TagItem **tp) { struct TagItem *nextti; /* 'tp' already holds "next" item in list */ nextti = *tp; /* walk all TAG_MORE and TAG_IGNORE chaining */ while ( nextti ) { switch ( nextti->ti_Tag ) { case TAG_MORE: nextti = (struct TagItem *) nextti->ti_Data; break; case TAG_SKIP: nextti+= 1 + (int) nextti->ti_Data; break; case TAG_IGNORE: nextti++; break; case TAG_DONE: return ( *tp = NULL ); break; default: /* a normal tag item */ *tp = nextti + 1; return ( nextti ); } } return ( *tp = NULL ); } struct TagItem *findTagItem(Tag tag, struct TagItem * ti) { struct TagItem *tistate; tistate = ti; while ( ti = nextTagItem( &tistate ) ) { if ( ti->ti_Tag == tag ) break; } return ( ti ); } ULONG getTagData(Tag tag, ULONG deflt, struct TagItem *ti) { if ( ti = findTagItem( tag, ti ) ) { return ( ti->ti_Data ); } return ( deflt ); } #define TEMP_NODE "This AmigaGuideHost is example, that can also\nbe used as a debuggin tool.\n" #define LINK "Link: " struct TextAttr TOPAZ8 = {"topaz.font", 8, NULL, NULL}; struct TextAttr TOPAZ8B = {"topaz.font", 8, FSF_BOLD, NULL}; /* We really need the screen, rectangle, and pen spec. */ VOID Display (struct opNodeIO *onm) { struct TagItem *attrs = onm->onm_Attrs; struct IntuiText it1 = {NULL}; struct IntuiText it2 = {NULL}; struct Rectangle *rect = NULL; struct NewWindow nw = {NULL}; struct Screen *scr = NULL; struct IntuiMessage *msg; struct Window *win; UWORD *pens = NULL; BOOL going = TRUE; LONG width = 0L; WORD w = 640; WORD h = 200; WORD dif; /* Get attributes, could be NULL */ if (attrs) { scr = (struct Screen *) getTagData (HTNA_Screen, NULL, attrs); pens = (UWORD *) getTagData (HTNA_Pens, NULL, attrs); rect = (struct Rectangle *) getTagData (HTNA_Rectangle, NULL, attrs); } /* Prepare the IntuiText */ it1.FrontPen = it2.FrontPen = ((pens) ? pens[SHADOWPEN] : 1); it1.DrawMode = it2.DrawMode = JAM1; it1.ITextFont = &TOPAZ8; it2.ITextFont = &TOPAZ8B; it1.IText = LINK; it2.IText = onm->onm_Node; /* Get the width of the first string */ width = IntuiTextLength (&it1); it2.LeftEdge = (SHORT) width; /* Add in the length of the node name */ width += IntuiTextLength (&it2); /* Link the text */ it1.NextText = &it2; /* Prepare the window */ nw.IDCMPFlags = IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS; nw.Flags = WFLG_BORDERLESS | WFLG_SMART_REFRESH | WFLG_NOCAREREFRESH \ | WFLG_ACTIVATE; nw.Width = 8 + width + 8; nw.Height = 16; nw.Screen = scr; nw.Type = (scr) ? CUSTOMSCREEN : WBENCHSCREEN; /* Cache the screen size */ if (scr) { w = scr->Width; h = scr->Height; } /* See if we have a open help window */ if (rect) { /* Center the window within the help window */ nw.LeftEdge = rect->MinX + ((rect->MaxX - nw.Width) / 2); nw.TopEdge = rect->MinY + ((rect->MaxY - nw.Height) / 2); } /* No help window, so go off the screen */ else if (scr) { /* Center the window horizontally under the mouse and place it * vertically over the mouse position. */ nw.LeftEdge = scr->MouseX - (nw.Width / 2); nw.TopEdge = scr->MouseY - (nw.Height - 2); /* Make sure the window can open */ nw.LeftEdge = (nw.LeftEdge < 0) ? 0 : nw.LeftEdge; nw.TopEdge = (nw.TopEdge < 0) ? 0 : nw.TopEdge; } /* Make sure window is on-screen */ dif = (nw.LeftEdge + nw.Width) - w; nw.LeftEdge = (dif > 0) ? nw.LeftEdge - dif : nw.LeftEdge; dif = (nw.TopEdge + nw.Height) - h; nw.TopEdge = (dif > 0) ? nw.TopEdge - dif : nw.TopEdge; /* Open the temporary window */ if (win = OpenWindow (&nw)) { /* Clear the window background */ SetAPen (win->RPort, ((pens) ? pens[SHADOWPEN] : 1)); RectFill (win->RPort, 0, 0, (win->Width - 1), (win->Height - 1)); SetAPen (win->RPort, ((pens) ? pens[SHINEPEN] : 2)); RectFill (win->RPort, 1, 1, (win->Width - 2), (win->Height - 2)); /* Print the text */ PrintIText (win->RPort, &it1, 8, 4); /* Keep on going til the going gets tough */ while (going) { /* Wait around for something eventful */ Wait (1L << win->UserPort->mp_SigBit); /* Pull each message and handle it */ while (msg = (struct IntuiMessage *) GetMsg (win->UserPort)) { switch (msg->Class) { case IDCMP_MOUSEBUTTONS: /* Stop if we were touched */ if (msg->Code == SELECTDOWN) { going = FALSE; } break; case IDCMP_VANILLAKEY: /* Stop on significant keypress */ if ((msg->Code == 27) || (msg->Code == 13)) { going = FALSE; } break; } ReplyMsg ((struct Message *) msg); } } /* Close the window */ CloseWindow (win); } } /* This is your AmigaGuideHost dispatch hook. It will never run on your * own process. */ ULONG __saveds dispatchAmigaGuideHost (struct Hook *h, STRPTR db, Msg msg) { struct opNodeIO *onm = (struct opNodeIO *) msg; ULONG retval = 0; switch (msg->MethodID) { /* Does this node belong to you? */ case HM_FindNode: { struct opFindHost *ofh = (struct opFindHost *) msg; DB (kprintf ("Find [%s] in %s\n", ofh->ofh_Node, db)); /* See if they want to find our table of contents */ if ((stricmp (ofh->ofh_Node, "main")) == 0) { /* Return TRUE to indicate that it's your node, * otherwise return FALSE. */ retval = TRUE; } else { /* Display the name of the node */ Display (onm); /* Return TRUE to indicate that it's your node, * otherwise return FALSE. */ retval = FALSE; } } break; /* Open a node. */ case HM_OpenNode: DB (kprintf ("Open [%s] in %s\n", onm->onm_Node, db)); /* See if they want to display our table of contents */ if ((stricmp (onm->onm_Node, "main")) == 0) { /* Provide the contents of the node */ onm->onm_DocBuffer = TEMP_NODE; onm->onm_BuffLen = strlen (TEMP_NODE); } else { /* Display the name of the node */ Display (onm); /* Indicate that we want the node removed from our database, * and that we handled the display of the node */ onm->onm_Flags |= (HTNF_CLEAN | HTNF_DONE); } /* Indicate that we were able to open the node */ retval = TRUE; break; /* Close a node, that has no users. */ case HM_CloseNode: DB (kprintf ("Close [%s] in %s\n", onm->onm_Node, db)); /* Indicate that we were able to close the node */ retval = TRUE; break; /* Free any extra memory */ case HM_Expunge: DB (kprintf ("Expunge [%s]\n", db)); break; default: DB (kprintf ("Unknown method %ld\n", msg->MethodID)); break; } return (retval); } /* Main entry point for your AmigaGuideHost dispatch hook */ ULONG __asm hookEntry ( register __a0 struct Hook *h, register __a2 VOID *obj, register __a1 VOID *msg) { /* Pass the parameters on the stack */ return ((h->h_SubEntry)(h, obj, msg)); }