home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
-
- This code serves as a basis for writing a library-based MUI custom class
- (xyz.mcc) and its preferences editor (xyz.mcp).
-
- You need to define a few things in your main source file, then include
- this file and then continue with your classes methods. The order is
- important, mccheader.c must be the first code-generating module.
-
- Things to be defined before mccheader.c is included:
-
- (1) UserLibID - version string for your class. must follow normal $VER: string conventions.
- (2) VERSION - version number of the class. must match the one given in the $VER: string.
- (3) REVISION - revision number of the class. must match the one given in the $VER: string.
- (4) CLASS - Name of your class, ".mcc" or ".mcp" must always be appended.
-
- (5) SUPERCLASS - superclass of your class.
- (6) struct Data - instance data structure.
- (7) _Dispatcher - your dispatcher function.
-
- (8) SUPERCLASSP - Superclass of the preferences class, must be MUIC_Mccprefs or a subclass.
- (9) struct DataP - instance data structure of preferences class.
- (10) _DispatcherP - dispatcher for the preferences class.
-
- Items (1) to (4) must always be defined. If you create a stand-alone
- custom class (*.mcc) without preferences editor, also define (5), (6)
- and (7). Name your class and the resulting ouptut file "Myclass.mcc".
-
- If you create a preferences class (*.mcp) for a custom class, define
- (8), (9) and (10) instead of (5), (6) and (7). Name your class and the
- resulting output file "Myclass.mcp".
-
- If you create a custom class with included preferences editor, define
- all the above. Note that in this case, the name of your class and the
- resulting output file is always "Myclass.mcc". MUI will automatically
- recognize that there's also a "Myclass.mcp" included. Having a builtin
- preferences class reduces the need for a second file but increases the
- size and memory consuption of the class.
-
- If your class needs custom initialization (e.g. opening other
- libraries), you can define
- ClassInit
- ClassExit
- to point to custom functions. These functions need to have the prototypes
- BOOL ClassInitFunc(struct Library *base);
- VOID ClassExitFunc(struct Library *base);
- and will be called right after the class has been created and right
- before the class is being deleted. If your init func returns FALSE,
- the custom class will be unloaded immediately.
-
- Define the minimum version of muimaster.libray in MASTERVERSION. If you
- don't define MASTERVERSION, it will default to MUIMASTER_VMIN from the
- mui.h include file.
-
- This code automatically defines and initializes the following variables:
- struct Library *MUIMasterBase;
- struct Library *SysBase;
- struct Library *UtilityBase;
- struct Library *DOSBase;
- struct Library *GfxBase;
- struct Library *IntuitionBase;
- struct Library *MUIClassBase; /* your classes library base */
- struct MUI_CustomClass *ThisClass; /* your custom class */
- struct MUI_CustomClass *ThisClassP; /* your preferences class */
-
- Example: Myclass.c
- #define CLASS MUIC_Myclass // name of class, e.g. "Myclass.mcc"
- #define SUPERCLASS MUIC_Area // name of superclass
- struct Data
- {
- LONG MyData;
- struct Foobar MyData2;
- // ...
- };
- #define UserLibID "$VER: Myclass.mcc 17.53 (11.11.96)"
- #define VERSION 17
- #define REVISION 53
- #include "mccheader.c"
- ULONG ASM SAVEDS _Dispatcher(REG(a0) struct IClass *cl,
- REG(a2) Object *obj,
- REG(a1) Msg msg)
- {
- // ...
- }
-
- Compiling and linking with SAS-C can look like this:
- Myclass.mcc: Myclass.c
- sc $(CFLAGS) $*.c OBJNAME $*.o
- slink to $@ from $*.o lib $(LINKERLIBS) $(LINKERFLAGS)
-
- Note well that we don't use SAS library creation feature here, it simply
- sucks too much. It's not much more complicated to do the library
- initialziation ourselves and we have better control over everything.
-
- Make sure to read the whole source to get some interesting comments
- and some understanding on how libraries are created!
-
- *****************************************************************************/
-
-
- /* a few includes... */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <exec/semaphores.h>
- #include <exec/resident.h>
- #include <dos/dos.h>
- #include <clib/exec_protos.h>
- #include <pragmas/exec_sysbase_pragmas.h>
-
-
- /* The name of the class will also become the name of the library. */
- /* We need a pointer to this string in our ROMTag (see below). */
-
- static const char UserLibName[] = CLASS;
-
-
- /* Here's our global data, described above. */
-
- struct Library *MUIClassBase;
- struct Library *MUIMasterBase;
- struct Library *SysBase;
- struct Library *UtilityBase;
- struct Library *DOSBase;
- struct Library *GfxBase;
- struct Library *IntuitionBase;
-
- #ifdef SUPERCLASS
- struct MUI_CustomClass *ThisClass;
- #endif
-
- #ifdef SUPERCLASSP
- struct MUI_CustomClass *ThisClassP;
- #endif
-
- #ifdef _DCC
- #define REG(x) __ ## x
- #define ASM
- #define SAVEDS __geta4
- #else
- #define REG(x) register __ ## x
- #define ASM __asm
- #define SAVEDS __saveds
- #endif
-
-
- /* Our library structure, consisting of a struct Library, a segment pointer */
- /* and a semaphore. We need the semaphore to protect init/exit stuff in our */
- /* open/close functions */
-
- struct LibraryHeader
- {
- struct Library lh_Library;
- BPTR lh_Segment;
- struct SignalSemaphore lh_Semaphore;
- };
-
-
- /* Prototypes for all library functions */
-
- struct LibraryHeader * ASM LibInit (REG(a0) BPTR Segment);
- BPTR ASM LibExpunge(REG(a6) struct LibraryHeader *base);
- struct LibraryHeader * ASM LibOpen (REG(a6) struct LibraryHeader *base);
- BPTR ASM LibClose (REG(a6) struct LibraryHeader *base);
- LONG ASM LibNull (VOID);
- ULONG SAVEDS ASM MCC_Query (REG(d0) LONG which);
-
-
- /* Prototypes for a few sub-functions */
-
- BOOL ASM UserLibInit (REG(a6) struct Library *base);
- BOOL ASM UserLibExpunge(REG(a6) struct Library *base);
- BOOL ASM UserLibOpen (REG(a6) struct Library *base);
- BOOL ASM UserLibClose (REG(a6) struct Library *base);
-
-
- /* This is the librarie's jump table */
-
- static const APTR LibVectors[] =
- {
- LibOpen,
- LibClose,
- LibExpunge,
- LibNull,
- MCC_Query,
- (APTR)-1
- };
-
-
- /* Dummy entry point and LibNull() function all in one */
-
- LONG ASM LibNull(VOID)
- {
- return(NULL);
- }
-
-
- /* Here's what makes us a library. */
-
- static const struct Resident ROMTag =
- {
- RTC_MATCHWORD,
- &ROMTag,
- &ROMTag + 1,
- 0,
- VERSION,
- NT_LIBRARY,
- 0,
- UserLibName,
- UserLibID,
- LibInit
- };
-
-
- #undef D
- #undef bug
- #undef bugg
-
- #ifdef DEBUG
-
- extern void kprintf(const char *, ...);
- #define D(flags,x) { ##x; }
- #define bug kprintf("%-12.12s %-17.17s: ",__FILE__,__FUNC__); kprintf
- #define bugg kprintf
-
- #else
-
- #define D(flags,x)
- #define bug
- #define bugg
-
- #endif /* DEBUG */
-
-
-
- /******************************************************************************/
- /* Standard Library Functions, all of them are called in Forbid() state. */
- /******************************************************************************/
-
- struct LibraryHeader * ASM SAVEDS LibInit(REG(a0) BPTR Segment)
- {
- struct LibraryHeader *base;
-
- SysBase = *((struct Library **)4);
-
- D(DBF_LIB,bug("start...\n"));
-
- #ifdef __SASC
- #ifdef _M68040
- if (!(((struct ExecBase *)SysBase)->AttnFlags & AFF_68040)) return(NULL);
- #endif
- #ifdef _M68030
- if (!(((struct ExecBase *)SysBase)->AttnFlags & AFF_68030)) return(NULL);
- #endif
- #ifdef _M68020
- if (!(((struct ExecBase *)SysBase)->AttnFlags & AFF_68020)) return(NULL);
- #endif
- #endif
-
- if (base = (struct LibraryHeader *)MakeLibrary((APTR)LibVectors,NULL,NULL,sizeof(struct LibraryHeader),NULL))
- {
- base->lh_Library.lib_Node.ln_Type = NT_LIBRARY;
- base->lh_Library.lib_Node.ln_Name = (char *)UserLibName;
- base->lh_Library.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
- base->lh_Library.lib_Version = VERSION;
- base->lh_Library.lib_Revision = REVISION;
- base->lh_Library.lib_IdString = (char *)UserLibID;
-
- base->lh_Segment = Segment;
-
- InitSemaphore(&base->lh_Semaphore);
-
- AddLibrary((struct Library *)base);
- }
- else
- {
- D(DBF_LIB,bug("\7MakeLibrary() failed\n"));
- }
-
- return(base);
- }
-
-
- BPTR ASM SAVEDS LibExpunge(REG(a6) struct LibraryHeader *base)
- {
- struct Library *SysBase = *((struct Library **)4);
- BPTR rc;
-
- D(DBF_LIB,bug("OpenCount=%ld\n",base->lh_Library.lib_OpenCnt));
-
- if (base->lh_Library.lib_OpenCnt)
- {
- base->lh_Library.lib_Flags |= LIBF_DELEXP;
- D(DBF_LIB,bug("Setting LIBF_DELEXP\n"));
- return(NULL);
- }
-
- Remove((struct Node *)base);
- rc = base->lh_Segment;
- FreeMem((BYTE *)base - base->lh_Library.lib_NegSize,base->lh_Library.lib_NegSize + base->lh_Library.lib_PosSize);
-
- return(rc);
- }
-
-
- struct LibraryHeader * ASM SAVEDS LibOpen(REG(a6) struct LibraryHeader *base)
- {
- struct Library *SysBase = *((struct Library **)4);
- struct LibraryHeader *rc;
-
- base->lh_Library.lib_OpenCnt++;
- base->lh_Library.lib_Flags &= ~LIBF_DELEXP;
-
- D(DBF_LIB,bug("OpenCount=%ld\n",base->lh_Library.lib_OpenCnt));
-
- ObtainSemaphore(&base->lh_Semaphore);
-
- if (UserLibOpen((struct Library *)base))
- {
- rc = base;
- }
- else
- {
- rc = NULL;
- base->lh_Library.lib_OpenCnt--;
- D(DBF_LIB,bug("\7UserLibOpen() failed\n"));
- }
-
- ReleaseSemaphore(&base->lh_Semaphore);
-
- return(rc);
- }
-
-
- BPTR ASM SAVEDS LibClose(REG(a6) struct LibraryHeader *base)
- {
- struct Library *SysBase = *((struct Library **)4);
- BPTR rc = NULL;
-
- D(DBF_LIB,bug("OpenCount=%ld %s\n",base->lh_Library.lib_OpenCnt,base->lh_Library.lib_OpenCnt==0 ? "\7ERROR" : ""));
-
- ObtainSemaphore(&base->lh_Semaphore);
- UserLibClose((struct Library *)base);
- ReleaseSemaphore(&base->lh_Semaphore);
-
- if (--base->lh_Library.lib_OpenCnt == 0)
- {
- if (base->lh_Library.lib_Flags & LIBF_DELEXP)
- {
- rc = LibExpunge(base);
- }
- }
-
- return(rc);
- }
-
-
- BOOL ASM SAVEDS UserLibOpen(REG(a6) struct Library *base)
- {
- ULONG ASM _Dispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
- ULONG ASM _DispatcherP(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
- BOOL ClassInitFunc(struct Library *base);
-
- D(DBF_CLASS,bug("%ld\n",base->lib_OpenCnt));
-
- if (base->lib_OpenCnt!=1)
- return(TRUE);
-
- #ifndef MASTERVERSION
- #define MASTERVERSION MUIMASTER_VMIN
- #endif
-
- if (MUIMasterBase = OpenLibrary("muimaster.library",MASTERVERSION))
- {
- #ifdef SUPERCLASS
- if (ThisClass = MUI_CreateCustomClass(base,SUPERCLASS,NULL,sizeof(struct Data),_Dispatcher))
- #endif
- {
- #ifdef SUPERCLASSP
- if (ThisClassP = MUI_CreateCustomClass(base,SUPERCLASSP,NULL,sizeof(struct DataP),_DispatcherP))
- #endif
- {
- #ifdef SUPERCLASS
- #define THISCLASS ThisClass
- #else
- #define THISCLASS ThisClassP
- #endif
-
- UtilityBase = THISCLASS->mcc_UtilityBase;
- DOSBase = THISCLASS->mcc_DOSBase;
- GfxBase = THISCLASS->mcc_GfxBase;
- IntuitionBase = THISCLASS->mcc_IntuitionBase;
-
- #ifndef ClassInit
- return(TRUE);
- #else
- if (ClassInitFunc(base))
- {
- return(TRUE);
- }
-
- #ifdef SUPERCLASSP
- MUI_DeleteCustomClass(ThisClassP);
- ThisClassP = NULL;
- #endif
-
- #endif
- }
- #ifdef SUPERCLASSP
- #ifdef SUPERCLASS
- MUI_DeleteCustomClass(ThisClass);
- ThisClass = NULL;
- #endif
- #endif
- }
- CloseLibrary(MUIMasterBase);
- MUIMasterBase = NULL;
- }
-
- D(DBF_CLASS,bug("fail.: %08lx %s\n",base,base->lib_Node.ln_Name));
-
- return(FALSE);
- }
-
-
- BOOL ASM SAVEDS UserLibClose(REG(a6) struct Library *base)
- {
- VOID ClassExitFunc(struct Library *base);
-
- D(DBF_CLASS,bug("%ld\n",base->lib_OpenCnt));
-
- if (base->lib_OpenCnt==1)
- {
- #ifdef ClassExit
- ClassExitFunc(base);
- #endif
-
- #ifdef SUPERCLASSP
- if (ThisClassP)
- {
- MUI_DeleteCustomClass(ThisClassP);
- ThisClassP = NULL;
- }
- #endif
-
- #ifdef SUPERCLASS
- if (ThisClass)
- {
- MUI_DeleteCustomClass(ThisClass);
- ThisClass = NULL;
- }
- #endif
-
- if (MUIMasterBase)
- {
- CloseLibrary(MUIMasterBase);
- MUIMasterBase = NULL;
- }
- }
-
- return(TRUE);
- }
-
-
- ULONG SAVEDS ASM MCC_Query(REG(d0) LONG which)
- {
- switch (which)
- {
- #ifdef SUPERCLASS
- case 0: return((ULONG)ThisClass);
- #endif
-
- #ifdef SUPERCLASSP
- case 1: return((ULONG)ThisClassP);
- #endif
-
- #ifdef PREFSIMAGEOBJECT
- case 2:
- {
- Object *obj = PREFSIMAGEOBJECT;
- return((ULONG)obj);
- }
- #endif
-
- #ifdef ONLYGLOBAL
- case 3:
- {
- return(TRUE);
- }
- #endif
- }
- return(NULL);
- }
-