Initial commit
[amiga/OpenBoopsi.git] / gadgets / SmartGroup / SmartGroupGClass.c
1 /*
2 **      $Id: SmartGroupGClass.c,v 1.1 1999/02/07 14:24:44 bernie Exp $
3 **
4 **      Copyright (C) 1999 Bernardo Innocenti
5 **      All rights reserved.
6 **
7 **      Use 4 chars wide TABs to read this file
8 **
9 **      "smartgroupgclass", a subclass of the gadgetclass which replaces
10 **      and enhances the builtin groupgclass.
11 **      See the header file "SmartGroupGClass.h" for class documentation.
12 */
13
14 /* Definitions for system headers */
15 #define USE_BUILTIN_MATH
16 #define INTUI_V36_NAMES_ONLY
17 #define INTUITION_IOBSOLETE_H
18 #define __USE_SYSBASE
19 #define  CLIB_ALIB_PROTOS_H             /* Avoid dupe defines of boopsi funcs */
20
21 #include <exec/types.h>
22 #include <exec/memory.h>
23 #include <utility/tagitem.h>
24 #include <intuition/intuition.h>
25 #include <intuition/classes.h>
26 #include <intuition/classusr.h>
27 #include <intuition/gadgetclass.h>
28
29 #include <proto/exec.h>
30 #include <proto/intuition.h>
31 #include <proto/utility.h>
32
33 #ifdef __STORM__
34         #pragma header
35 #endif
36
37 #include <gadgets/SmartGroupGClass.h>
38
39 #include <CompilerSpecific.h>
40 #include <DebugMacros.h>
41 #include <ListMacros.h>
42 #include <BoopsiStubs.h>
43 #include <BoopsiLib.h>
44
45
46 /* Local function prototypes */
47
48 static ULONG HOOKCALL SmartGroupDispatcher (REG(a0, Class *cl), REG(a2, Object *o), REG(a1, Msg msg));
49
50 static ULONG    ASMCALL SG_GMHitTest    (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpHitTest *msg));
51 static void             ASMCALL SG_GMRender             (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpRender *msg));
52 static ULONG    ASMCALL SG_GMGoActive   (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpInput *msg));
53 static ULONG    ASMCALL SG_GMHandleInput(REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpInput *msg));
54 static void             ASMCALL SG_GMGoInactive (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpGoInactive *msg));
55 static ULONG    ASMCALL SG_GMHelpTest   (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpHitTest *msg));
56 static void             ASMCALL SG_GMLayout             (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpLayout *msg));
57 static ULONG    ASMCALL SG_GMDomain             (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpDomain *msg));
58 static ULONG    ASMCALL SG_OMNew                (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opSet *msg));
59 static void             ASMCALL SG_OMDispose    (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, Msg msg));
60 //static ULONG  ASMCALL SG_OMSet                (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opUpdate *msg));
61 static void             ASMCALL SG_OMAddMember  (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opMember *msg));
62 static void             ASMCALL SG_OMRemMember  (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opMember *msg));
63
64 /* Per-object instance data */
65
66 struct GroupData
67 {
68         struct MinList          ChildList;
69
70         struct ExtGadget *      ActiveChild;
71         struct IBox                     GBox;
72
73         /* Group orientation: can be LORIENT_VERT or LORIENT_HORIZ */
74         ULONG                           Orientation;
75 };
76
77
78
79 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
80
81         /* Class library support functions */
82         struct ClassLibrary     *       HOOKCALL _UserLibInit           (REG(a6, struct ClassLibrary *mybase));
83         struct ClassLibrary     *       HOOKCALL _UserLibCleanup        (REG(a6, struct ClassLibrary *mybase));
84         Class *                                 HOOKCALL _GetEngine                     (REG(a6, struct ClassLibrary *mybase));
85
86         /* Library data */
87         const UBYTE LibName[] = "sliderbar.gadget";
88         const UBYTE LibVer[] = { '$', 'V', 'E', 'R', ':', ' ' };
89         const UBYTE LibId[] = "smartgroup.gadget 1.0 (6.1.99) © 1999 Bernardo Innocenti\n";
90
91         /* Workaround a bug in StormC header file <proto/utility.h> */
92         #ifdef __STORM__
93                 #define UTILITYBASETYPE struct Library
94         #else
95                 #define UTILITYBASETYPE struct UtilityBase
96         #endif
97
98         /* Library bases */
99         static struct ExecBase          *SysBase                = NULL;
100         static struct IntuitionBase     *IntuitionBase  = NULL;
101         static UTILITYBASETYPE          *UtilityBase    = NULL;
102
103 #endif
104
105
106
107 static ULONG ASMCALL SG_GMHitTest (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpHitTest *msg))
108 {
109         struct GroupData *gd = INST_DATA (cl, g);
110         struct ExtGadget *child;
111         APTR object_state;
112         WORD x, y;
113
114         DB2 (DBPRINTF ("SmartGroupGClass: GM_HITTEST\n");)
115         ASSERT_VALID_PTR(gd)
116
117         object_state = (APTR)gd->ChildList.mlh_Head;
118         ASSERT_VALID_PTR(object_state)
119
120         x = msg->gpht_Mouse.X + gd->GBox.Left;
121         y = msg->gpht_Mouse.Y + gd->GBox.Top;
122
123         /* Search over all our children */
124         while (child = (struct ExtGadget *)NextObject(&object_state))
125         {
126                 ASSERT_VALID_PTR(child)
127
128                 /* Check whether the mouse coordinates are inside
129                  * the gadget rectangle of our child
130                  */
131                 if ((x >= child->LeftEdge) &&
132                         (x < child->LeftEdge + child->Width) &&
133                         (y >= child->TopEdge) &&
134                         (y < child->TopEdge + child->Height))
135                 {
136                         struct gpHitTest childmsg;
137
138                         childmsg.MethodID               = GM_HITTEST;
139                         childmsg.gpht_GInfo             = msg->gpht_GInfo;
140                         childmsg.gpht_Mouse.X   = x - child->LeftEdge;
141                         childmsg.gpht_Mouse.Y   = y - child->TopEdge;
142
143                         if (DoMethodA ((Object *)child, (Msg)&childmsg) == GMR_GADGETHIT)
144                         {
145                                 gd->ActiveChild = child;
146                                 return GMR_GADGETHIT;
147                         }
148                 }
149         }
150
151         return 0;
152 }
153
154
155
156 static void ASMCALL SG_GMRender(REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpRender *msg))
157 {
158         struct GroupData *gd = INST_DATA (cl, g);
159         Object *o;
160         APTR object_state;
161
162         DB2 (DBPRINTF ("SmartGroupGClass: GM_RENDER\n");)
163
164         ASSERT_VALID_PTR(gd)
165         object_state = (APTR)gd->ChildList.mlh_Head;
166         ASSERT_VALID_PTR(object_state)
167
168         /* The groupgclass disposes all its children automatically */
169         while (o = NextObject(&object_state))
170         {
171                 ASSERT_VALID_PTR(o)
172                 DoMethodA (o, (Msg)msg);
173         }
174 }
175
176
177
178 static ULONG ASMCALL SG_GMGoActive (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpInput *msg))
179 {
180         struct GroupData *gd = INST_DATA (cl, g);
181
182         DB2 (DBPRINTF ("SmartGroupGClass: GM_GOACTIVE\n");)
183         ASSERT_VALID_PTR(gd)
184         ASSERT_VALID_PTR(gd->ActiveChild)
185
186         if (gd->ActiveChild)
187         {
188                 struct gpInput childmsg;
189
190                 childmsg.MethodID               = GM_GOACTIVE;
191                 childmsg.gpi_GInfo              = msg->gpi_GInfo;
192                 childmsg.gpi_IEvent             = msg->gpi_IEvent;
193                 childmsg.gpi_Termination= msg->gpi_Termination;
194                 childmsg.gpi_Mouse.X    = msg->gpi_Mouse.X + gd->GBox.Left
195                         - gd->ActiveChild->LeftEdge;
196                 childmsg.gpi_Mouse.Y    = msg->gpi_Mouse.Y + gd->GBox.Top
197                         - gd->ActiveChild->TopEdge;
198                 childmsg.gpi_TabletData = msg->gpi_TabletData;
199
200                 return (DoMethodA ((Object *)gd->ActiveChild, (Msg)&childmsg));
201         }
202
203         gd->ActiveChild = NULL;
204         return GMR_NOREUSE;
205 }
206
207
208
209 static ULONG ASMCALL SG_GMHandleInput (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpInput *msg))
210 {
211         struct GroupData *gd = INST_DATA (cl, g);
212
213         DB2 (DBPRINTF ("SmartGroupGClass: GM_HANDLEINPUT\n");)
214         ASSERT_VALID_PTR(gd)
215         ASSERT_VALID_PTR(gd->ActiveChild)
216
217         if (gd->ActiveChild)
218         {
219                 struct gpInput childmsg;
220
221                 childmsg.MethodID               = GM_HANDLEINPUT;
222                 childmsg.gpi_GInfo              = msg->gpi_GInfo;
223                 childmsg.gpi_IEvent             = msg->gpi_IEvent;
224                 childmsg.gpi_Termination= msg->gpi_Termination;
225                 childmsg.gpi_Mouse.X    = msg->gpi_Mouse.X + gd->GBox.Left
226                         - gd->ActiveChild->LeftEdge;
227                 childmsg.gpi_Mouse.Y    = msg->gpi_Mouse.Y + gd->GBox.Top
228                         - gd->ActiveChild->TopEdge;
229                 childmsg.gpi_TabletData = msg->gpi_TabletData;
230
231                 DB2 (DBPRINTF ("SmartGroupGClass:   Translating coords: X=%ld, Y=%ld\n",
232                         childmsg.gpi_Mouse.X, childmsg.gpi_Mouse.Y);)
233
234                 return DoMethodA ((Object *)gd->ActiveChild, (Msg)&childmsg);
235         }
236
237         return GMR_NOREUSE;
238 }
239
240
241
242 static void ASMCALL SG_GMGoInactive (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpGoInactive *msg))
243 {
244         struct GroupData *gd = INST_DATA (cl, g);
245
246         DB2 (DBPRINTF ("SmartGroupGClass: GM_GOINACTIVE\n");)
247         ASSERT_VALID_PTR(gd)
248         ASSERT_VALID_PTR(gd->ActiveChild)
249
250         if (gd->ActiveChild)
251         {
252                 DoMethodA ((Object *)gd->ActiveChild, (Msg)msg);
253                 gd->ActiveChild = NULL;
254         }
255 }
256
257
258
259 static ULONG ASMCALL SG_GMHelpTest (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpHitTest *msg))
260 {
261         struct GroupData *gd = INST_DATA (cl, g);
262         struct ExtGadget *child;
263         APTR object_state;
264         WORD x, y;
265
266         DB1 (DBPRINTF ("SmartGroupGClass: GM_HELPTEST\n");)
267
268         ASSERT_VALID_PTR(gd)
269         object_state = (APTR)gd->ChildList.mlh_Head;
270         ASSERT_VALID_PTR(object_state)
271
272
273         if ((g->Flags & GFLG_EXTENDED) && (g->MoreFlags & GMORE_GADGETHELP))
274         {
275                 x = msg->gpht_Mouse.X + gd->GBox.Left;
276                 y = msg->gpht_Mouse.Y + gd->GBox.Top;
277
278                 /* Search over all our children */
279                 while (child = (struct ExtGadget *)NextObject(&object_state))
280                 {
281                         ASSERT_VALID_PTR(child)
282
283                         /* Limit to gadgets that understand GM_HELPTEST */
284                         if ((child->Flags & GFLG_EXTENDED) && (child->MoreFlags & GMORE_GADGETHELP))
285                         {
286                                 if (child->MoreFlags & GMORE_BOUNDS)
287                                 {
288                                         /* Check whether the mouse coordinates are inside
289                                          * the gadget rectangle of our child
290                                          */
291                                         if ((x >= child->BoundsLeftEdge) &&
292                                                 (x < child->BoundsLeftEdge + child->BoundsWidth) &&
293                                                 (y >= child->BoundsTopEdge) &&
294                                                 (y < child->BoundsTopEdge + child->BoundsHeight))
295                                         {
296                                                 struct gpHitTest childmsg;
297
298                                                 childmsg.MethodID               = GM_HELPTEST;
299                                                 childmsg.gpht_GInfo             = msg->gpht_GInfo;
300                                                 childmsg.gpht_Mouse.X   = x - child->BoundsLeftEdge;
301                                                 childmsg.gpht_Mouse.Y   = y - child->BoundsTopEdge;
302
303                                                 if (DoMethodA ((Object *)child, (Msg)&childmsg) == GMR_HELPHIT)
304                                                 {
305                                                         gd->ActiveChild = child;
306                                                         return GMR_HELPHIT;
307                                                 }
308                                         }
309                                 }
310                                 else /* No valid bounds, use gadget select box */
311                                 {
312                                         /* Check whether the mouse coordinates are inside
313                                          * the gadget rectangle of our child
314                                          */
315                                         if ((x >= child->LeftEdge) &&
316                                                 (x < child->LeftEdge + child->Width) &&
317                                                 (y >= child->TopEdge) &&
318                                                 (y < child->TopEdge + child->Height))
319                                         {
320                                                 struct gpHitTest childmsg;
321
322                                                 childmsg.MethodID               = GM_HELPTEST;
323                                                 childmsg.gpht_GInfo             = msg->gpht_GInfo;
324                                                 childmsg.gpht_Mouse.X   = x - child->LeftEdge;
325                                                 childmsg.gpht_Mouse.Y   = y - child->TopEdge;
326
327                                                 if (DoMethodA ((Object *)child, (Msg)&childmsg) == GMR_HELPHIT)
328                                                 {
329                                                         gd->ActiveChild = child;
330                                                         return GMR_HELPHIT;
331                                                 }
332                                         }
333                                 }
334                         }
335                 }
336         }
337
338         return GMR_NOHELPHIT;
339 }
340
341
342
343 static void ASMCALL SG_GMLayout(REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpLayout *msg))
344 {
345         struct GroupData *gd = (struct GroupData *) INST_DATA (cl, (Object *)g);
346         struct ExtGadget *child;
347         APTR object_state;
348
349         DB2 (DBPRINTF ("SmartGroupGClass: GM_LAYOUT\n");)
350         ASSERT_VALID_PTR(gd)
351
352         /* Collect new group size */
353         GetGadgetBounds(msg->gpl_GInfo, g, &gd->GBox);
354
355         /* Forward GM_LAYOUT to our children that need it */
356
357         object_state = (APTR)gd->ChildList.mlh_Head;
358         ASSERT_VALID_PTR(object_state)
359
360         while (child = (struct ExtGadget *)NextObject(&object_state))
361         {
362                 ASSERT_VALID_PTR(child)
363
364                 if (child->Flags & (
365                         GFLG_RELBOTTOM |
366                         GFLG_RELRIGHT |
367                         GFLG_RELWIDTH |
368                         GFLG_RELHEIGHT |
369                         GFLG_RELSPECIAL))
370                 {
371                         DB2 (DBPRINTF ("SmartGroupGClass:   Forwarding GM_LAYOUT to child\n");)
372                         DoMethodA ((Object *)child, (Msg)msg);
373                 }
374         }
375 }
376
377
378
379 static ULONG ASMCALL SG_GMDomain (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct gpDomain *msg))
380 {
381         DB1 (DBPRINTF ("SmartGroupGClass: GM_DOMAIN\n");)
382
383         /* TODO */
384         return 0;
385 }
386
387
388
389 static ULONG ASMCALL SG_OMNew (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opSet *msg))
390 {
391         struct GroupData *gd;
392         struct TagItem *ti, *tstate = msg->ops_AttrList;
393
394         DB1 (DBPRINTF ("SmartGroupGClass: OM_NEW\n");)
395
396         if (g = (struct ExtGadget *)DoSuperMethodA (cl, (Object *)g, (Msg)msg))
397         {
398                 gd = (struct GroupData *) INST_DATA (cl, (Object *)g);
399                 ASSERT_VALID_PTR(gd)
400
401                 DB (if (g->Flags & GFLG_EXTENDED)
402                         DBPRINTF ("SmartGroupGClass:   Wow, we are an ExtGadget!\n");)
403
404                 /* Initialize object instance data */
405                 NEWLIST((struct List *)&gd->ChildList);
406                 gd->ActiveChild = NULL;
407                 gd->ActiveChild = NULL;
408
409                 gd->Orientation = LORIENT_NONE;
410
411                 while (ti = NextTagItem (&tstate))
412                         switch (ti->ti_Tag)
413                         {
414                                 case SGA_Child:
415                                 {
416                                         struct opMember opam;
417
418                                         if (!ti->ti_Data)
419                                         {
420                                                 /* Commit suicide without disturbing the
421                                                  * dispatchers of our subclasses
422                                                  */
423                                                 SG_OMDispose (cl, g, NULL);
424                                                 return NULL;
425                                         }
426
427                                         ASSERT_VALID_PTR(ti->ti_Data)
428                                         opam.opam_Object = (Object *)ti->ti_Data;
429                                         SG_OMAddMember (cl, g, &opam);
430                                         break;
431                                 }
432
433                                 case LAYOUTA_Orientation:
434                                         gd->Orientation = ti->ti_Data;
435                                         break;
436
437                                 default:
438                                         break;
439                         }
440
441                 /* Intuition sends GM_LAYOUT messages only to gadgets with
442                  * relative postion. Since we need to recalculate the
443                  * positions of our children when the window resizes, we
444                  * set the GFLG_RELSPECIAL property if to be notified in all cases.
445                  */
446                 g->Flags |= GFLG_RELSPECIAL;
447         }
448
449         return (ULONG)g;
450 }
451
452
453
454 static void ASMCALL SG_OMDispose (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, Msg msg))
455 {
456         struct GroupData *gd = (struct GroupData *) INST_DATA (cl, (Object *)g);
457         Object *o;
458         APTR object_state;
459
460         DB1 (DBPRINTF ("SmartGroupGClass: OM_DISPOSE\n");)
461
462         ASSERT_VALID_PTR(gd)
463         object_state = (APTR)gd->ChildList.mlh_Head;
464         ASSERT_VALID_PTR(object_state)
465
466         /* The groupgclass disposes all its children automatically */
467         while (o = NextObject(&object_state))
468         {
469                 ASSERT_VALID_PTR(o)
470                 DoMethod (o, OM_REMOVE);
471                 DisposeObject(o);
472         }
473
474         /* Our superclass will cleanup everything else now */
475         DoSuperMethodA (cl, (Object *)g, msg);
476
477         /* From now on, our instance data is no longer available */
478 }
479
480
481 #if 0
482 static ULONG ASMCALL SG_OMSet (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opUpdate *msg))
483 {
484         struct GroupData *gd = INST_DATA (cl, g);
485         struct TagItem *ti, *tstate = msg->opu_AttrList;
486
487         DB1 (DBPRINTF ("SmartGroupGClass: OM_SET\n");)
488
489         ASSERT_VALID_PTR(gd)
490         ASSERT_VALID_PTR_OR_NULL(tstate)
491
492         DB2 (DBPRINTF ((msg->MethodID == OM_SET) ?
493                 "SliderBarGClass: OM_SET\n" :
494                 "SliderBarGClass: OM_UPDATE\n");)
495
496
497         while (ti = NextTagItem (&tstate))
498                 switch (ti->ti_Tag)
499                 {
500                         default:
501                                 break;
502                 }
503
504                 result = TRUE;
505
506
507         return result;
508 }
509 #endif
510
511
512
513 static void ASMCALL SG_OMAddMember (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opMember *msg))
514 {
515         struct GroupData *gd = INST_DATA (cl, g);
516         ASSERT_VALID_PTR(gd)
517         DB1 (DBPRINTF ("SmartGroupGClass: OM_ADDMEMBER\n");)
518
519         if(msg->opam_Object)
520         {
521                 ASSERT_VALID_PTR(msg->opam_Object)
522
523                 /* TODO: check for GMORE_SCROLLRASTER ? */
524
525                 DoMethod (msg->opam_Object, OM_ADDTAIL, &gd->ChildList);
526         }
527 }
528
529
530
531 static void ASMCALL SG_OMRemMember (REG(a0, Class *cl), REG(a2, struct ExtGadget *g), REG(a1, struct opMember *msg))
532 {
533         struct GroupData *gd = INST_DATA (cl, g);
534
535         DB1 (DBPRINTF ("SmartGroupGClass: OM_REMMEBRER\n");)
536         ASSERT_VALID_PTR(gd)
537
538         DoMethod (msg->opam_Object, OM_REMOVE);
539
540         if (msg->opam_Object == (Object *)gd->ActiveChild)
541                 gd->ActiveChild = NULL;
542
543         /* TODO: resize & redraw group */
544 }
545
546
547
548 static ULONG HOOKCALL SmartGroupDispatcher (
549         REG(a0, Class *cl),
550         REG(a2, Object *o),
551         REG(a1, Msg msg))
552
553 /* SmartGroup class dispatcher - Handles all boopsi messages. */
554 {
555         static const HookPtr GMHooks[] =
556         {
557                 /* GM_HITTEST           */ (HookPtr)SG_GMHitTest,
558                 /* GM_RENDER            */ (HookPtr)SG_GMRender,
559                 /* GM_GOACTIVE          */ (HookPtr)SG_GMGoActive,
560                 /* GM_HANDLEINPUT       */ (HookPtr)SG_GMHandleInput,
561                 /* GM_GOINACTIVE        */ (HookPtr)SG_GMGoInactive,
562                 /* GM_HELPTEST          */ (HookPtr)SG_GMHelpTest,
563                 /* GM_LAYOUT            */ (HookPtr)SG_GMLayout,
564                 /* GM_DOMAIN            */ (HookPtr)SG_GMDomain
565         };
566
567         static const HookPtr OMHooks[] =
568         {
569                 /* OM_NEW               */ (HookPtr)SG_OMNew,
570                 /* OM_DISPOSE   */ (HookPtr)SG_OMDispose,
571                 /* OM_SET               */ (HookPtr)NULL,
572                 /* OM_GET               */ (HookPtr)NULL,
573                 /* OM_ADDTAIL   */ (HookPtr)NULL,
574                 /* OM_REMOVE    */ (HookPtr)NULL,
575                 /* OM_NOTIFY    */ (HookPtr)NULL,
576                 /* OM_UPDATE    */ (HookPtr)NULL,
577                 /* OM_ADDMEMBER */ (HookPtr)SG_OMAddMember,
578                 /* OM_REMMEMBER */ (HookPtr)SG_OMRemMember
579         };
580
581         ULONG id;
582
583         ASSERT_VALID_PTR(cl)
584         ASSERT_VALID_PTR(o)
585         ASSERT_VALID_PTR(msg)
586
587         /* Optimized boopsi class dispatcher.
588          *
589          * This class overrides almost all gadgetclass and rootclass messages.
590          * The usual switch() statement on msg->MessageID would be quite inefficient.
591          * Most compilers aren't smart enough to implement it with two jump tables
592          * as we did here. This code relies on the values assigned to the method IDs
593          * in the headers to remain constant. It will break otherwise.
594          */
595
596         id = msg->MethodID;
597
598         if (id <= GM_DOMAIN)
599                 return GMHooks[id](cl, o, msg);
600
601         id -= OM_NEW;
602
603         if (id <= (OM_REMMEMBER - OM_NEW))
604                 if (OMHooks[id])
605                         return OMHooks[id](cl, o, msg);
606
607         return DoSuperMethodA (cl, o, msg);
608 }
609
610
611
612 Class *MakeSmartGroupGClass (void)
613 {
614         Class *class;
615
616         if (class = MakeClass (
617 #if (CLASS_FLAVOUR & FLAVOUR_PUBCLASS)
618                 SMARTGROUPGCLASS,
619 #else
620                 NULL,
621 #endif
622                 GADGETCLASS, NULL, sizeof (struct GroupData), 0))
623         {
624                 class->cl_Dispatcher.h_Entry = (ULONG (*)()) SmartGroupDispatcher;
625         }
626
627         return class;
628 }
629
630
631 BOOL FreeSmartGroupGClass (Class *class)
632 {
633         if (class)
634         {
635                 ASSERT_VALID_PTR(class)
636
637                 /* Try to remove the class */
638                 if (FreeClass (class))
639                         return TRUE;
640
641                 return FALSE;
642         }
643         return TRUE;
644 }
645
646
647
648 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
649 /*
650  * Class library support functions
651  */
652
653 struct ClassLibrary * HOOKCALL _UserLibInit (REG(a6, struct ClassLibrary *mybase))
654 {
655         SysBase = *((struct ExecBase **)4);     /* Initialize SysBase */
656
657         IntuitionBase   = (struct IntuitionBase *) OpenLibrary ("intuition.library", 39);
658         UtilityBase             = (UTILITYBASETYPE *) OpenLibrary ("utility.library", 39);
659
660         if (!(IntuitionBase && UtilityBase))
661         {
662                 _UserLibCleanup (mybase);
663                 return NULL;
664         }
665
666         if (mybase->cl_Class = MakeSmartGroupGClass ())
667         {
668                 return mybase;
669         }
670         else
671         {
672                 _UserLibCleanup (mybase);
673                 return NULL;
674         }
675 }
676
677 struct ClassLibrary * HOOKCALL _UserLibCleanup (REG(a6, struct ClassLibrary *mybase))
678 {
679         if (mybase->cl_Class)
680                 if (!FreeSliderBarGClass (mybase->cl_Class))
681                         return NULL;
682
683         CloseLibrary ((struct Library *)UtilityBase);
684         CloseLibrary ((struct Library *)IntuitionBase);
685
686         return mybase;
687 }
688
689 Class * HOOKCALL _GetEngine (REG(a6, struct ClassLibrary *mybase))
690 {
691         return (mybase->cl_Class);
692 }
693
694 #endif /* (CLASS_FLAVOUR & FLAVOUR_CLASSLIB) */