home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / dev / mui / OOPExample.lha / OOPExample / OOPExample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-07  |  20.9 KB  |  661 lines

  1.  
  2. /*
  3.  
  4.      OOPExample 1.0 - Copyright © 07-Feb-1997 by Maik "BLiZZeR" Schreiber
  5.      ====================================================================
  6.  
  7. Hello, this is OOPExample. As stated in OOPExample.readme, it should show you
  8. how to write an object-oriented program with MUI. However, OOP with MUI does
  9. not mean C++ here. We are programming in normal C, but using MUI's OOP
  10. features, ok? ;)
  11.  
  12. First of all you should have little knowledge of OOP, because it's quite
  13. complicated to explain it all here. I think it's the best if you get a good
  14. C++ book from your library or something. Second, you should know how to write
  15. MUI programs. You should know about MUI's classes, their attributes, methods
  16. and stuff.
  17.  
  18. Ok, now let's go on. Before I got to know how MUI's OOP features work,
  19. I didn't have a clue about it. I didn't know about dispatchers, method
  20. handlers and all that stuff. I looked at psi.c, but that was so complex
  21. that I really didn't get the point!
  22.  
  23. All I wanted was a small example. It should open a window with a button
  24. inside it. Clicking on this button should open a second window, clicking
  25. it again should close the second window. Nothing more, nothing less.
  26. (Maybe a few guys on the MUI mailing remember ;)
  27.  
  28. Fine, I knew how to do it with return IDs: Clicking the button returns an
  29. ID to the main input loop, and the loop decides to open or close the second
  30. window. But damn, that was no OOP!
  31.  
  32. Then, two guys (Kai Hofmann and Jan Hendrik Schulz, hello there :)) told me
  33. to implement my example using an attribute. But how?! How to add a new
  34. attribute to what?
  35.  
  36. Anyway, I finally had a look at Klaus Melchior's Tron.mcc example and - click!
  37. Of course! That's how it works!
  38.  
  39.  
  40. You're still reading? Fine :-))) Let's go on then:
  41.  
  42. Of course there are may ways to implement a new custom class which satisfies
  43. my wish for that example above. I want to show you two of them:
  44.  
  45. 1. Implement a new custom class which is derived from Window.mui. Inside it,
  46.    it shall create a button itself. Clicking on this button should read an
  47.    attribute specifying the other window to open/close and open or close
  48.    that window.
  49.  
  50. 2. Implement a new custom class which is derived from Text.mui (adding an
  51.    input mode, of course, so that we have a button). Clicking on this button
  52.    again reads out the attribute and opens or closes the other window.
  53.  
  54. In this example we implement the first way, because it shows general data
  55. hiding techniques of OOP: The first window object we create from our custom
  56. class does not know about the button inside the other window and vice versa.
  57. Furthermore, we have less global identifiers and stuff.
  58.  
  59. Now let me explain how we're going to implement the new custom class:
  60.  
  61. First, when creating an object from that class, we create the window itself
  62. (of course). Next, we create the button inside it. Third, we setup a
  63. notification on that button to send the object (our window) a method.
  64.  
  65. "But how does that method know about the other window, which should be
  66. opened or closed depending on its state?" you may ask.
  67. This is done via a new attribute called MUIA_OOPWindow_WindowToOpenOrClose.
  68.  
  69. Look, after the complete application object tree is created within the
  70. main program, we know about our two window objects, which are objects of
  71. our new OOPWindow class.
  72.  
  73. All we have to do now, is to "say" window 1, that its button has to open or
  74. close window 2. And window 2 has to know that its button should open or close
  75. window 1. This is done via a more than simple set() call.
  76.  
  77. THAT'S IT!
  78.  
  79. Now, when you click the button in window 1, its notification sends the
  80. specified method (called MUIM_OOPWindow_OpenOrCloseWindow) to the object,
  81. which is again window 1. Using the attribute window 1 now knows about
  82. window 2 and is able to open/close it! (Of course, this works the other
  83. way round in this example.)
  84.  
  85.  
  86. Ok, girls and guys, now you have the knowledge of how to write object-oriented
  87. progams with MUI! Isn't that simple? :-)))
  88. The following source code has loads of comments inside, so just have a look.
  89.  
  90. Happy programming,
  91.  
  92. Maik "BLiZZeR" Schreiber
  93. (why don't you call me "MUI genius", huh? ;)
  94.  
  95.  
  96.  
  97. ******  IMPORTANT NOTE  ******  IMPORTANT NOTE  ******  IMPORTANT NOTE  ******
  98.  
  99.  
  100. This source code uses the tag base TAGBASE_BLIZZY, which is defined as
  101. (TAG_USER | (1465UL << 16)).
  102.  
  103. PLEASE *DO* *NOT* *USE* THIS TAG BASE IN YOUR OWN APPLICATIONS!!!!!!!!!!!!
  104. It is a personalized tag base!!!!!!!!!!
  105.  
  106. If you need such a tag base for creating attributes and methods identifiers,
  107. you *MUST* write to mccreg@sasg.com and ask for a new tag base for you!!!!!
  108.  
  109. This is really important!!!
  110.  
  111.  
  112. ******  IMPORTANT NOTE  ******  IMPORTANT NOTE  ******  IMPORTANT NOTE  *****/
  113.  
  114.  
  115.  
  116. /*** include files ***/
  117. #include <exec/types.h>
  118. #if defined __MAXON__ || defined __STORM__
  119. #include <pragma/exec_lib.h>
  120. #else
  121. #include <proto/exec.h>
  122. #endif
  123. #include <exec/libraries.h>
  124. #if defined __MAXON__ || defined __STORM__
  125. #include <pragma/muimaster_lib.h>
  126. #else
  127. #include <proto/muimaster.h>
  128. #endif
  129. #include <libraries/mui.h>
  130. #include <intuition/classusr.h>
  131. #if defined __MAXON__ || defined __STORM__
  132. #include <pragma/utility_lib.h>
  133. #else
  134. #include <proto/utility.h>
  135. #endif
  136. #include <utility/utility.h>
  137. #include <clib/alib_protos.h>
  138. #include <stdio.h>
  139. #include <string.h>
  140. #include <stdlib.h>
  141. #if defined __MAXON__ || defined __STORM__
  142. #include <wbstartup.h>
  143. #endif
  144.  
  145. #include "OOPExample.h"
  146.  
  147.  
  148. /*** constants ***/
  149. /* attributes */
  150. #define MUIA_OOPWindow_ButtonTitle         (TAGBASE_BLIZZY + 1) /* [I.G]  STRPTR   */
  151. #define MUIA_OOPWindow_ButtonShortHelp     (TAGBASE_BLIZZY + 2) /* [I.G]  STRPTR   */
  152. #define MUIA_OOPWindow_WindowToOpenOrClose (TAGBASE_BLIZZY + 3) /* [ISG]  Object * */
  153.  
  154.  
  155. /* methods */
  156. #define MUIM_OOPWindow_OpenOrCloseWindow   (TAGBASE_BLIZZY + 1)
  157.  
  158. /* miscellaneous */
  159. #define STR_VERSI_OOPEXAMPLE "1.0"
  160. #define STR_DATE_OOPEXAMPLE  "07-Feb-1997"
  161. #define STR_VDATE_OOPEXAMPLE "7.2.97"
  162.  
  163.  
  164. /*** structures ***/
  165. /* class instance data structure */
  166. struct OOPWindowData
  167. {
  168.   Object *wiWindowToOpenOrClose;
  169.   char   *button_title;
  170.   char   *button_shorthelp;
  171. };
  172.  
  173.  
  174. /*** macros ***/
  175. /* this macro simplifies creation of OOPWindow objects */
  176. #define OOPWindowObject NewObject(clOOPWindow->mcc_Class, NULL
  177.  
  178. /* copied from <blizzy/macros.h> */
  179. #ifndef MAKE_ID
  180. #define MAKE_ID(a,b,c,d) ((((ULONG) (a)) << 24) | (((ULONG) (b)) << 16) | (((ULONG) (c)) << 8) | ((ULONG) (d)))
  181. #endif
  182.  
  183.  
  184. /*** prototypes ***/
  185. BOOL  gui_init(void);
  186. void  gui_exit(void);
  187. BOOL  classes_init(void);
  188. void  classes_exit(void);
  189.  
  190. ULONG ASM SAVEDS OOPWindow_Dispatcher(REG(a0) struct IClass *, REG(a2) Object *, REG(a1) Msg);
  191.  
  192. ULONG DoSuperNew(struct IClass *, Object *, ULONG, ...);
  193. ULONG xget(Object *, ULONG);
  194.  
  195.  
  196. /*** global identifiers ***/
  197. Object                 *apMain        = NULL;
  198. Object                 *  owWindow1;
  199. Object                 *  owWindow2;
  200.  
  201. struct MUI_CustomClass *clOOPWindow   = NULL;
  202.  
  203. struct Library         *MUIMasterBase = NULL;
  204. struct Library         *UtilityBase   = NULL;
  205.  
  206.  
  207. /*** program ***/
  208. int main(void)
  209. {
  210.   int ret = RETURN_FAIL;
  211.  
  212.   /* open all necessary libraries */
  213.   if (!(UtilityBase = OpenLibrary(UTILITYNAME, 37UL)))
  214.   {
  215.     printf("Couldn't open %s 37!\n", UTILITYNAME);
  216.     goto bye;
  217.   }
  218.   if (!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
  219.   {
  220.     printf("Couldn't open %s %lu!\n", MUIMASTER_NAME, (ULONG) MUIMASTER_VMIN);
  221.     goto bye;
  222.   }
  223.  
  224.   /* create custom classes */
  225.   if (!classes_init())
  226.   {
  227.     puts("Couldn't create custom classes!");
  228.     goto bye;
  229.   }
  230.  
  231.   /* create application */
  232.   if (!gui_init())
  233.   {
  234.     puts("Couldn't create application!");
  235.     goto bye;
  236.   }
  237.  
  238.   /* This is the ideal input loop for an object oriented MUI
  239.   ** application. Everything is encapsulated in classes, no
  240.   ** return IDs need to be used, we just check if the program
  241.   ** shall terminate.
  242.   **
  243.   ** (Quote and source part copied from the original MUI distribution.)
  244.   */
  245.   {
  246.     ULONG sigs = 0UL;
  247.  
  248.     while (DoMethod(apMain, MUIM_Application_NewInput, &sigs) != MUIV_Application_ReturnID_Quit)
  249.     {
  250.       if (sigs)
  251.       {
  252.         sigs = Wait(sigs | SIGBREAKF_CTRL_C);
  253.         if (sigs & SIGBREAKF_CTRL_C)
  254.           break;
  255.       }
  256.     }
  257.   }
  258.  
  259.   ret = RETURN_OK;
  260.  
  261.   bye:
  262.   /* free all resources */
  263.   gui_exit();
  264.   classes_exit();
  265.   if (MUIMasterBase) CloseLibrary(MUIMasterBase);
  266.   if (UtilityBase)   CloseLibrary(UtilityBase);
  267.   exit(ret);
  268. }
  269.  
  270. /* setup application and do all necessary initializations */
  271. BOOL gui_init(void)
  272. {
  273.   if (apMain = ApplicationObject,
  274.     MUIA_Application_Title,       "OOPExample",
  275.     MUIA_Application_Version,     "$VER: OOPExample " STR_VERSI_OOPEXAMPLE " (" STR_VDATE_OOPEXAMPLE ") © by Maik \"BLiZZeR\" Schreiber, "
  276. #ifdef __SASC
  277.                                   "SAS/C"
  278. #else
  279.   #ifdef __MAXON__
  280.                                   "MaxonC++"
  281.   #else
  282.     #ifdef __STORM__
  283.                                   "StormC"
  284.     #else
  285.       #ifdef _DCC
  286.                                   "Dice C"
  287.       #else
  288.         #ifdef _GCC
  289.                                   "GNU C"
  290.         #else
  291.                                   "unknown compiler"
  292.         #endif
  293.       #endif
  294.     #endif
  295.   #endif
  296. #endif
  297.                                   " version",
  298.     MUIA_Application_Copyright,   "Copyright © " STR_DATE_OOPEXAMPLE " by Maik Schreiber <BLiZZeR@dame.de>",
  299.     MUIA_Application_Author,      "Maik Schreiber <BLiZZeR@dame.de>",
  300.     MUIA_Application_Description, "Learn OOP with MUI!",
  301.     MUIA_Application_Base,        "OOPEXAMPLE",
  302.  
  303.     SubWindow, owWindow1 = OOPWindowObject,
  304.       MUIA_Window_Title,              "OOPExample · Window 1",
  305.       MUIA_Window_ID,                 MAKE_ID('W', 'I', 'N', '1'),
  306.       MUIA_OOPWindow_ButtonTitle,     "Open/close window _2",
  307.       MUIA_OOPWindow_ButtonShortHelp, "This button opens or closes window 2.",
  308.     End,
  309.  
  310.     SubWindow, owWindow2 = OOPWindowObject,
  311.       MUIA_Window_Title,              "OOPExample · Window 2",
  312.       MUIA_Window_ID,                 MAKE_ID('W', 'I', 'N', '2'),
  313.       MUIA_OOPWindow_ButtonTitle,     "Open/close window _1",
  314.       MUIA_OOPWindow_ButtonShortHelp, "This button opens or closes window 1.",
  315.     End,
  316.  
  317.   End)
  318.   {
  319.     /* specify which window's button should open/close which window */
  320.     set(owWindow1, MUIA_OOPWindow_WindowToOpenOrClose, owWindow2);
  321.     set(owWindow2, MUIA_OOPWindow_WindowToOpenOrClose, owWindow1);
  322.  
  323.     /* this lets us quit the program by closing one of the windows directly */
  324.     DoMethod(owWindow1, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, apMain, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
  325.     DoMethod(owWindow2, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, apMain, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
  326.  
  327.     /* open window 1 and let MUI do the work :-) */
  328.     set(owWindow1, MUIA_Window_Open, TRUE);
  329.  
  330.     return(TRUE);
  331.   }
  332.   return(FALSE);
  333. }
  334. /* dispose application */
  335. void gui_exit(void)
  336. {
  337.   if (apMain) MUI_DisposeObject(apMain);
  338. }
  339. /* create custom classes */
  340. BOOL classes_init(void)
  341. {
  342.   /* This is one of the essential parts when fiddling with custom classes.
  343.   ** Here we create our own custom classes, which can be derived from
  344.   ** any MUI class. Our new classes can also be derived from themselves,
  345.   ** e.g. a new window class derived from Window.mui and a second new
  346.   ** window class which is derived from that first window class.
  347.   **
  348.   ** In this OOPExample program, we create a new window class which is
  349.   ** derived from Window.mui.
  350.   **
  351.   ** A note about the datasize parameter of MUI_CreateCustomClass():
  352.   ** This parameter is used to tell MUI, how much memory a class instance
  353.   ** of this class needs for its data. MUI allocates a memory block of
  354.   ** that given size, which you may use for anything you want.
  355.   **
  356.   ** You can always get a pointer to an object's instance data using
  357.   **
  358.   **   INST_DATA(class, obj);   // see <intuition/classes.h>
  359.   */
  360.   clOOPWindow = MUI_CreateCustomClass(NULL, MUIC_Window, NULL, sizeof(struct OOPWindowData), OOPWindow_Dispatcher);
  361.   if (clOOPWindow)
  362.     return(TRUE);
  363.   return(FALSE);
  364. }
  365. /* dispose custom classes */
  366. void classes_exit(void)
  367. {
  368.   if (clOOPWindow) MUI_DeleteCustomClass(clOOPWindow);
  369. }
  370.  
  371. /* This is the constructor of our newly created OOPWindow custom class. */
  372. ULONG OOPWindow_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
  373. {
  374.   Object         *button;
  375.   struct TagItem *tag;
  376.   char           *button_title;
  377.   char           *button_shorthelp;
  378.  
  379.   /* The MUIA_OOPWindow_ButtonTitle attribute needs a bit more overhead... */
  380.   if (tag = FindTagItem(MUIA_OOPWindow_ButtonTitle, msg->ops_AttrList))
  381.     button_title = (char *) tag->ti_Data;
  382.   else
  383.     button_title = "";
  384.  
  385.   /* ... as does the MUIA_OOPWindow_ButtonShortHelp attribute... */
  386.   if (tag = FindTagItem(MUIA_OOPWindow_ButtonShortHelp, msg->ops_AttrList))
  387.     button_shorthelp = (char *) tag->ti_Data;
  388.   else
  389.     button_shorthelp = "";
  390.  
  391.  
  392.   /* This is the point where we create the new object from our class.
  393.   ** There exist two ways for doing this:
  394.   **
  395.   ** 1. Just creating the new object.
  396.   **    This is done via DoSuperMethodA():
  397.   **
  398.   **    if (obj = (Object *) DoSuperMethodA(cl, obj, (Msg)))
  399.   **    {
  400.   **      ...
  401.   **    }
  402.   **
  403.   ** 2. Creating the object plus adding some new tags to its initial
  404.   **    taglist.
  405.   **    This is done via DoSuperNew(), which is an extra function calling
  406.   **    DoSuperMethodA() again:
  407.   **
  408.   **
  409.   **    if (obj = (Object *) DoSuperNew(cl, obj,
  410.   **      ... add new ("hardcoded") tags here ...
  411.   **      TAG_MORE, msg->ops_AttrList))
  412.   **    {
  413.   **      ...
  414.   **    }
  415.   **
  416.   **
  417.   ** In OOPExample, we want to create a button inside the window object.
  418.   ** Since the main program should not create the button but we want to
  419.   ** create it ourselves, we have to do a call to DoSuperNew().
  420.   */
  421.   if (obj = (Object *) DoSuperNew(cl, obj,
  422.     WindowContents, VGroup,
  423.       Child, TextObject,
  424.         MUIA_Text_Contents, "\033c\033b\033uOOPExample " STR_VERSI_OOPEXAMPLE,
  425.         MUIA_Font, MUIV_Font_Big,
  426.       End,
  427.       Child, TextObject,
  428.         MUIA_Text_Contents, "\033cCopyright © " STR_DATE_OOPEXAMPLE " by Maik \"BLiZZeR\" Schreiber/IQ Computing",
  429.       End,
  430.       Child, TextObject,
  431.         MUIA_Text_Contents, "\033c(This version was compiled using "
  432. #ifdef __SASC
  433.                             "SAS/C."
  434. #else
  435.   #ifdef __MAXON__
  436.                             "MaxonC++."
  437.   #else
  438.     #ifdef __STORM__
  439.                             "StormC."
  440.     #else
  441.       #ifdef _DCC
  442.                             "Dice C."
  443.       #else
  444.         #ifdef _GCC
  445.                             "GNU C."
  446.         #else
  447.                             "an unknown C compiler?!"
  448.         #endif
  449.       #endif
  450.     #endif
  451.   #endif
  452. #endif
  453.                             ")",
  454.         MUIA_Font, MUIV_Font_Tiny,
  455.       End,
  456.       Child, button = SimpleButton(button_title),
  457.     End,
  458.     TAG_MORE, msg->ops_AttrList))
  459.   {
  460.     /* get instance data of the newly created object */
  461.     struct OOPWindowData *data = INST_DATA(cl, obj);
  462.  
  463.     /* set default values */
  464.     memset(data, 0, sizeof(struct OOPWindowData));
  465.     data->button_title     = button_title;
  466.     data->button_shorthelp = button_shorthelp;
  467.  
  468.     /* use a trick to set the initial values */
  469.     msg->MethodID = OM_SET;
  470.     DoMethodA(obj, (Msg) msg);
  471.     msg->MethodID = OM_NEW;
  472.  
  473.     /* set cycle chain */
  474.     set(button, MUIA_CycleChain, TRUE);
  475.  
  476.     /* bubble help */
  477.     set(button, MUIA_ShortHelp, button_shorthelp);
  478.  
  479.     /* Setup notification for the button to open/close a window.
  480.     ** We simply send ourselves the MUIM_OOPWindow_OpenOrCloseWindow
  481.     ** method.
  482.     */
  483.     DoMethod(button, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, MUIM_OOPWindow_OpenOrCloseWindow);
  484.  
  485.     /* return address of the new object */
  486.     return((ULONG) obj);
  487.   }
  488.   /* return failure indicator */
  489.   return(0);
  490. }
  491. /* This is the OM_SET method handler of our class. */
  492. ULONG OOPWindow_SET(struct IClass *cl, Object *obj, struct opSet *msg)
  493. {
  494.   /* get instance data of our object */
  495.   struct OOPWindowData *data      = INST_DATA(cl, obj);
  496.   struct TagItem       *tags      = msg->ops_AttrList;
  497.   struct TagItem       *tag;
  498.  
  499.   /* The identifier no_notify gives us the possibility to handle
  500.   ** the MUIA_NoNotify attribute in our class. If you need this feature
  501.   ** in your class, simple remove the comment markers here and a few
  502.   ** lines below. Then, you have to write
  503.   **
  504.   **   SetAttrs(obj, MUIA_NoNotify, no_notify, ...);
  505.   **
  506.   ** to take care of MUIA_NoNotify.
  507.   */
  508. /*
  509.   BOOL                  no_notify = FALSE;
  510. */
  511.  
  512.   /* There are many ways to find out what tag items provided by set()
  513.   ** we do know. The best way should be using NextTagItem() and simply
  514.   ** browsing through the list.
  515.   */
  516.   while (tag = NextTagItem(&tags))
  517.   {
  518.     switch (tag->ti_Tag)
  519.     {
  520.       /* handle MUIA_NoNotify in our class */
  521. /*
  522.       case MUIA_NoNotify:
  523.         no_notify = (BOOL) tag->ti_Data;
  524.         break;
  525. */
  526.  
  527.       /* specify the window, which should be opened/closed on pressing
  528.       ** the button
  529.       */
  530.       case MUIA_OOPWindow_WindowToOpenOrClose:
  531.         data->wiWindowToOpenOrClose = (Object *) tag->ti_Data;
  532.         break;
  533.     }
  534.   }
  535.   return(DoSuperMethodA(cl, obj, (Msg) msg));
  536. }
  537. /* Here comes the OM_GET method handler. */
  538. ULONG OOPWindow_GET(struct IClass *cl, Object *obj, struct opGet *msg)
  539. {
  540.   /* The OM_GET handler also has a very special behaviour:
  541.   ** Since you can only get() one attribute value at a time,
  542.   ** it has to return() TRUE if it does "understand" your
  543.   ** attribute identifier.
  544.   ** If not, the handler must pass the attribute identifier
  545.   ** to the superclass via DoSuperMethodA().
  546.   */
  547.  
  548. /* small macro to simplify return value storage */
  549. #define STORE *(msg->opg_Storage)
  550.  
  551.   /* get instance data of our object */
  552.   struct OOPWindowData *data = INST_DATA(cl, obj);
  553.  
  554.   switch(msg->opg_AttrID)
  555.   {
  556.     /* Return button title of our button.
  557.     ** This attribute isn't used in this example program,
  558.     ** but it shows another time how the technique is done.
  559.     **
  560.     ** NOTE: In this example, the returned string must not be
  561.     ** modified!
  562.     */
  563.     case MUIA_OOPWindow_ButtonTitle:
  564.       STORE = (ULONG) data->button_title;
  565.       return(TRUE);
  566.  
  567.     /* return bubble help string of our button */
  568.     case MUIA_OOPWindow_ButtonShortHelp:
  569.       STORE = (ULONG) data->button_shorthelp;
  570.       return(TRUE);
  571.  
  572.     /* return the specified window, which should be opened/closed
  573.     ** on pressing the button
  574.     */
  575.     case MUIA_OOPWindow_WindowToOpenOrClose:
  576.       STORE = (ULONG) data->wiWindowToOpenOrClose;
  577.       return(TRUE);
  578.   }
  579.  
  580.   /* our handler didn't understand the attribute, we simply pass
  581.   ** it to our superclass now
  582.   */
  583.   return(DoSuperMethodA(cl, obj, (Msg) msg));
  584. #undef STORE
  585. }
  586. /* MUIM_OOPWindow_OpenOrCloseWindow method handler */
  587. ULONG OOPWindow_OpenOrCloseWindow(Object *obj)
  588. {
  589.   /* This is the "main" method of our OOPWindow class.
  590.   ** Here's what it does:
  591.   **
  592.   ** 1. Get the window, which should be opened or closed.
  593.   ** 2. Open/close the window depending on its current state
  594.   **    (ie. if it's open, close it, otherwise open).
  595.   **
  596.   ** Since this is a new method, we don't have anything to pass to
  597.   ** our superclass here. Instead, we return() TRUE to indicate that
  598.   ** all went ok.
  599.   **
  600.   ** NOTE: In this example, the return value of this method isn't used,
  601.   ** so we could also return() FALSE here. When writing custom classes,
  602.   ** it can sometimes be very handy to have return values. You can get
  603.   ** them from your DoMethod() call to this method.
  604.   */
  605.  
  606.   Object *window;
  607.  
  608.   if (window = (Object *) xget(obj, MUIA_OOPWindow_WindowToOpenOrClose))
  609.     set(window, MUIA_Window_Open, xget(window, MUIA_Window_Open) ? FALSE : TRUE);
  610.   return(TRUE);
  611. }
  612. /* Here you see the dispatcher of our class. */
  613. ULONG ASM SAVEDS OOPWindow_Dispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg)
  614. {
  615.   /* The class dispatcher is the function, that will be called when a
  616.   ** method is sent to your class. The dispatcher has to determine
  617.   ** if it understands the method. If yes, it calls the according
  618.   ** method handler (you can also write the handler here instead of
  619.   ** return()ing a function return value - that's a style question).
  620.   ** If not, it has to pass the method to the superclass.
  621.   */
  622.  
  623.   /* watch out for methods we do understand */
  624.   switch (msg->MethodID)
  625.   {
  626.     /* Whenever an object shall be created using NewObject(), it will be
  627.     ** sent a OM_NEW method.
  628.     */
  629.     case OM_NEW:                           return(OOPWindow_NEW(cl, obj, (struct opSet *) msg));
  630.  
  631.     /* SetAttrs() sends a OM_SET method */
  632.     case OM_SET:                           return(OOPWindow_SET(cl, obj, (struct opSet *) msg));
  633.  
  634.     /* GetAttr() sends a OM_GET method */
  635.     case OM_GET:                           return(OOPWindow_GET(cl, obj, (struct opGet *) msg));
  636.  
  637.     /* one of our own methods */
  638.     case MUIM_OOPWindow_OpenOrCloseWindow: return(OOPWindow_OpenOrCloseWindow(obj));
  639.   }
  640.  
  641.   /* we didn't understand the last method, so call our superclass */
  642.   return(DoSuperMethodA(cl, obj, msg));
  643. }
  644.  
  645. /* This is a small function to add some new capabilities to
  646. ** DoSuperMethodA().
  647. */
  648. ULONG DoSuperNew(struct IClass *cl, Object *obj, ULONG tag1, ...)
  649. {
  650.   return(DoSuperMethod(cl, obj, OM_NEW, &tag1, NULL));
  651. }
  652. /* This simplifies get()ting values of attributes. */
  653. ULONG xget(Object *obj, ULONG attr)
  654. {
  655.   ULONG ret;
  656.  
  657.   get(obj, attr, &ret);
  658.   return(ret);
  659. }
  660.  
  661.