Fix for a crash which happened when a document couldn't be opened.
[AROS-Contrib.git] / bgui / classes.c
blob8933b1d2e9a36dde56f7ad2c3f1d7c3b6a22ee23
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * classes.c
7 * (C) Copyright 1998 Manuel Lemos.
8 * (C) Copyright 1996-1997 Ian J. Einman.
9 * (C) Copyright 1993-1996 Jaba Development.
10 * (C) Copyright 1993-1996 Jan van den Baard.
11 * All Rights Reserved.
13 * $Log$
14 * Revision 42.9 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.8 2003/01/18 19:09:55 chodorowski
18 * Instead of using the _AROS or __AROS preprocessor symbols, use __AROS__.
20 * Revision 42.7 2000/08/09 11:45:57 chodorowski
21 * Removed a lot of #ifdefs that disabled the AROS_LIB* macros when not building on AROS. This is now handled in contrib/bgui/include/bgui_compilerspecific.h.
23 * Revision 42.6 2000/07/06 16:42:03 stegerg
24 * the function ForwardMsg relied on gpInput->gpht_Mouse.X/Y and
25 * gpHitTest.gpht_Mouse.X/Y being of type WORD. For example
26 * it used LONG reads to backup this values and a WORD * pointer
27 * to change them. Does not work with AROS where these are of
28 * type STACKWORD and not WORD.
30 * This caused the problems with the gadgets which could not be
31 * activated, or only activated by clicking somewhere outside.
33 * Revision 42.5 2000/06/01 01:41:37 bergers
34 * Only 2 linker problems left: stch_l & stcu_d. Somebody might want to replace them (embraced by #ifdef __AROS__), please.
36 * Revision 42.4 2000/05/31 01:23:10 bergers
37 * Changes to make BGUI compilable and linkable.
39 * Revision 42.3 2000/05/29 00:40:23 bergers
40 * Update to compile with AROS now. Should also still compile with SASC etc since I only made changes that test the define __AROS__. The compilation is still very noisy but it does the trick for the main directory. Maybe members of the BGUI team should also have a look at the compiler warnings because some could also cause problems on other systems... (Comparison always TRUE due to datatype (or something like that)). And please compile it on an Amiga to see whether it still works... Thanks.
42 * Revision 42.2 2000/05/15 19:27:00 stegerg
43 * another hundreds of REG() macro replacements in func headers/protos.
45 * Revision 42.1 2000/05/14 23:32:46 stegerg
46 * changed over 200 function headers which all use register
47 * parameters (oh boy ...), because the simple REG() macro
48 * doesn't work with AROS. And there are still hundreds
49 * of headers left to be fixed :(
51 * Many of these functions would also work with stack
52 * params, but since i have fixed every single one
53 * I encountered up to now, I guess will have to do
54 * the same for the rest.
56 * Revision 42.0 2000/05/09 22:08:37 mlemos
57 * Bumped to revision 42.0 before handing BGUI to AROS team
59 * Revision 41.11 2000/05/09 19:54:03 mlemos
60 * Merged with the branch Manuel_Lemos_fixes.
62 * Revision 41.10.2.12 1999/08/09 23:01:25 mlemos
63 * Optimized method lookup by using a 256 positions hash table and a simple
64 * UBYTE conversion as hash function.
66 * Revision 41.10.2.11 1999/07/29 00:42:12 mlemos
67 * Added a call MarkFreedClass at the end of a successful call to
68 * BGUI_FreeClass.
70 * Revision 41.10.2.10 1999/01/06 19:18:18 mlemos
71 * Prevented division by 0 in the class statistics when no methods were
72 * called.
74 * Revision 41.10.2.9 1998/12/14 19:56:13 mlemos
75 * Replaced the binary search method lookup by hash table method lookup.
76 * Added debug code to produce statistics about method lookup on dispatching.
78 * Revision 41.10.2.8 1998/12/14 18:36:25 mlemos
79 * Added support for method inheritance to speed up method dispatching.
81 * Revision 41.10.2.7 1998/12/14 04:59:47 mlemos
82 * Replaced the assembly method dispatcher by a C dispatcher that uses binary
83 * search as method lookup.
85 * Revision 41.10.2.6 1998/11/13 18:08:10 mlemos
86 * Fixed mistaken default value for BaseInfo screen pointer in AllocBaseInfo.
88 * Revision 41.10.2.5 1998/10/18 18:22:59 mlemos
89 * Ensured that the allocated Baseinfo structure is cleared when it is not
90 * being copied from another BaseInfo structure.
92 * Revision 41.10.2.4 1998/10/12 01:21:54 mlemos
93 * Added the support for class constructor and destructor methods.
95 * Revision 41.10.2.3 1998/10/01 04:24:40 mlemos
96 * Made the class data store also BGUI global data pointer.
98 * Revision 41.10.2.2 1998/03/02 23:48:09 mlemos
99 * Switched vector allocation functions calls to BGUI allocation functions.
101 * Revision 41.10.2.1 1998/03/01 15:32:02 mlemos
102 * Added support to track BaseInfo memory leaks.
104 * Revision 41.10 1998/02/25 21:11:47 mlemos
105 * Bumping to 41.10
107 * Revision 1.1 1998/02/25 17:07:51 mlemos
108 * Ian sources
113 #include "include/classdefs.h"
115 #ifdef __AROS__
116 #else
117 #include <dos.h>
118 #endif
120 typedef FUNCPTR ClassMethodDispatcher;
122 typedef struct SortedMethod
124 ULONG MethodID;
125 ClassMethodDispatcher DispatcherFunction;
126 Class *Class;
127 APTR GlobalData;
128 struct SortedMethod *NextHashedMethod;
129 APTR Padding[3];
131 SortedMethod;
133 typedef struct
135 DPFUNC *ClassMethodFunctions;
136 ClassMethodDispatcher ClassDispatcher;
137 APTR BGUIGlobalData;
138 APTR ClassGlobalData;
139 SortedMethod *MethodFunctions;
140 ULONG MethodCount;
141 SortedMethod **MethodHashTable;
142 #ifdef DEBUG_BGUI
143 ULONG MethodLookups;
144 ULONG MethodComparisions;
145 ULONG MethodColisions;
146 APTR Padding[6];
147 #else
148 APTR Padding;
149 #endif
151 BGUIClassData;
153 #define METHOD_HASH_TABLE_SIZE 256
154 #define MethodHashValue(method) ((UBYTE)(method))
156 makeproto UBYTE *RootClass = "rootclass";
157 makeproto UBYTE *ImageClass = "imageclass";
158 makeproto UBYTE *GadgetClass = "gadgetclass";
159 makeproto UBYTE *PropGClass = "propgclass";
160 makeproto UBYTE *StrGClass = "strgclass";
162 makeproto Class *BGUI_MakeClass(Tag tag, ...)
164 AROS_SLOWSTACKTAGS_PRE_AS(tag, Class *)
165 retval = BGUI_MakeClassA(AROS_SLOWSTACKTAGS_ARG(tag));
166 AROS_SLOWSTACKTAGS_POST
169 STATIC METHOD(ClassCallDispatcher, Msg, msg)
171 BGUIClassData *class_data;
172 DPFUNC *class_methods;
174 if(cl
175 && (class_data=(BGUIClassData *)cl->cl_UserData)
176 && (class_methods=class_data[-1].ClassMethodFunctions))
178 for(;class_methods->df_MethodID!=DF_END;class_methods++)
179 if(class_methods->df_MethodID==msg->MethodID)
180 return METHOD_CALL(class_methods->df_Func, cl, obj, msg, _global);
182 switch(msg->MethodID)
184 case OM_NEW:
185 case OM_DISPOSE:
186 return(1);
188 return(0);
190 METHOD_END
192 struct CallData
194 ClassMethodDispatcher dispatcher;
195 Class *cl;
196 Object *obj;
197 Msg msg;
198 APTR global_data;
201 static IPTR ASM CallMethod(REG(a3) struct CallData *call_data)
203 register APTR stack;
204 register IPTR result;
206 stack=EnsureStack();
207 result=METHOD_CALL(call_data->dispatcher,call_data->cl,call_data->obj,call_data->msg,call_data->global_data);
208 RevertStack(stack);
209 return(result);
212 static int CompareMethods(const void *method_1, const void *method_2)
214 return(((SortedMethod *)method_1)->MethodID==((SortedMethod *)method_2)->MethodID ? 0 : (((SortedMethod *)method_1)->MethodID>((SortedMethod *)method_2)->MethodID ? 1 : -1));
217 static SortedMethod *LookupMethod(BGUIClassData *class_data,ULONG method)
219 SortedMethod *method_found;
220 size_t lower,upper,index;
222 #ifdef DEBUG_BGUI
223 class_data->MethodLookups++;
224 #endif
225 for(lower=0,upper=class_data->MethodCount;lower<upper;)
227 #ifdef DEBUG_BGUI
228 class_data->MethodComparisions++;
229 #endif
230 index=(lower+upper)/2;
231 method_found=class_data->MethodFunctions+index;
232 if(method==method_found->MethodID)
233 return(method_found);
234 if(method>method_found->MethodID)
235 lower=index+1;
236 else
237 upper=index;
239 #ifdef DEBUG_BGUI
240 class_data->MethodComparisions++;
241 #endif
242 return(NULL);
245 //makeproto SAVEDS ASM ULONG __GCD( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) Msg msg)
246 makeproto SAVEDS ASM REGFUNC3(IPTR, __GCD,
247 REGPARAM(A0, Class *, cl),
248 REGPARAM(A2, Object *, obj),
249 REGPARAM(A1, Msg, msg))
251 struct CallData call_data;
252 BGUIClassData *class_data;
253 SortedMethod *method_found;
255 if(cl==NULL
256 || (class_data=((BGUIClassData *)cl->cl_UserData))==NULL
257 || ((--class_data)->MethodFunctions)==NULL)
259 D(bug("BGUI method dispatcher was called to handle an invalid class!!\n"));
260 return(0);
262 #ifdef DEBUG_BGUI
263 class_data->MethodLookups++;
264 #endif
265 for(method_found=class_data->MethodHashTable[MethodHashValue(msg->MethodID)];method_found && method_found->MethodID!=msg->MethodID;method_found=method_found->NextHashedMethod)
267 #ifdef DEBUG_BGUI
268 class_data->MethodComparisions++;
269 #endif
271 #ifdef DEBUG_BGUI
272 class_data->MethodComparisions++;
273 #endif
274 if(method_found)
276 call_data.cl=method_found->Class;
277 call_data.dispatcher=(ClassMethodDispatcher)method_found->DispatcherFunction;
278 call_data.global_data=method_found->GlobalData;
280 else
282 call_data.dispatcher=(ClassMethodDispatcher)(call_data.cl=cl->cl_Super)->cl_Dispatcher.h_Entry;
283 call_data.global_data=class_data->BGUIGlobalData;
285 call_data.obj=obj;
286 call_data.msg=msg;
287 return(CallMethod(&call_data));
289 REGFUNC_END
292 * Setup a class.
294 #ifdef __AROS__
295 makearosproto
296 AROS_LH1(Class *, BGUI_MakeClassA,
297 AROS_LHA(struct TagItem *, tags, A0),
298 struct Library *, BGUIBase, 24, BGUI)
299 #else
300 makeproto ASM Class *BGUI_MakeClassA(REG(a0) struct TagItem *tags)
301 #endif
303 AROS_LIBFUNC_INIT
305 IPTR old_a4 = (IPTR)getreg(REG_A4);
306 IPTR SuperClass, SuperClass_ID, Class_ID;
307 ULONG Flags, ClassSize, ObjectSize;
308 BGUIClassData *ClassData;
309 Class *cl=NULL;
311 geta4();
313 if ((SuperClass = GetTagData(CLASS_SuperClassBGUI, (IPTR)~0, tags)) == (IPTR)~0)
314 SuperClass = GetTagData(CLASS_SuperClass, (IPTR)NULL, tags);
315 else
316 SuperClass = (IPTR)BGUI_GetClassPtr(SuperClass);
318 if (SuperClass)
319 SuperClass_ID = 0;
320 else
321 SuperClass_ID = GetTagData(CLASS_SuperClassID, (IPTR)"rootclass", tags);
323 Class_ID = GetTagData(CLASS_ClassID, (IPTR)NULL, tags);
324 Flags = (ULONG)GetTagData(CLASS_Flags, 0, tags);
325 ClassSize = (ULONG)GetTagData(CLASS_ClassSize, 0, tags);
326 ObjectSize = (ULONG)GetTagData(CLASS_ObjectSize, 0, tags);
328 if ((ClassData = BGUI_AllocPoolMem(ClassSize + sizeof(BGUIClassData))))
330 if ((cl = MakeClass((UBYTE *)Class_ID, (UBYTE *)SuperClass_ID, (Class *)SuperClass, ObjectSize, Flags)))
332 DPFUNC *method_functions;
334 cl->cl_UserData = (IPTR)(&ClassData[1]);
335 cl->cl_Dispatcher.h_Entry = (HOOKFUNC)GetTagData(CLASS_Dispatcher, (IPTR)__GCD, tags);
336 ClassData->ClassMethodFunctions = (DPFUNC *)GetTagData(CLASS_ClassDFTable, (IPTR)NULL, tags);
337 ClassData->ClassDispatcher = (ClassMethodDispatcher)GetTagData(CLASS_ClassDispatcher, (IPTR)ClassCallDispatcher, tags);
339 ClassData->BGUIGlobalData = (APTR)getreg(REG_A4);
340 ClassData->ClassGlobalData = (APTR)old_a4;
342 if((method_functions=(DPFUNC *)GetTagData(CLASS_DFTable, 0, tags)))
345 DPFUNC *methods;
347 for(ClassData->MethodCount=0,methods=method_functions;methods->df_MethodID!=DF_END;ClassData->MethodCount++,methods++);
349 if((ClassData->MethodFunctions=BGUI_AllocPoolMem(sizeof(*ClassData->MethodFunctions)*ClassData->MethodCount)))
351 ULONG method;
353 for(method=0;method<ClassData->MethodCount;method++)
355 ClassData->MethodFunctions[method].MethodID=method_functions[method].df_MethodID;
356 ClassData->MethodFunctions[method].DispatcherFunction=(ClassMethodDispatcher)method_functions[method].df_Func;
357 ClassData->MethodFunctions[method].Class=cl;
358 ClassData->MethodFunctions[method].GlobalData=ClassData->ClassGlobalData;
360 qsort(ClassData->MethodFunctions,ClassData->MethodCount,sizeof(*ClassData->MethodFunctions),CompareMethods);
361 if(cl->cl_Super->cl_Dispatcher.h_Entry==(APTR)__GCD)
363 BGUIClassData *super_class_data;
364 ULONG new_methods;
366 super_class_data=(((BGUIClassData *)cl->cl_Super->cl_UserData)-1);
367 for(new_methods=ClassData->MethodCount,method=0;method<super_class_data->MethodCount;method++)
369 if(LookupMethod(ClassData,super_class_data->MethodFunctions[method].MethodID)==NULL)
371 SortedMethod *new_sorted_methods;
373 if((new_sorted_methods=BGUI_AllocPoolMem(sizeof(*new_sorted_methods)*(new_methods+1)))==NULL)
375 cl->cl_UserData=0;
376 FreeClass(cl);
377 cl=NULL;
378 break;
380 memcpy(new_sorted_methods,ClassData->MethodFunctions,sizeof(*new_sorted_methods)*new_methods);
381 BGUI_FreePoolMem(ClassData->MethodFunctions);
382 ClassData->MethodFunctions=new_sorted_methods;
383 ClassData->MethodFunctions[new_methods]=super_class_data->MethodFunctions[method];
384 new_methods++;
387 ClassData->MethodCount=new_methods;
388 qsort(ClassData->MethodFunctions,ClassData->MethodCount,sizeof(*ClassData->MethodFunctions),CompareMethods);
390 if(cl)
392 if((ClassData->MethodHashTable=BGUI_AllocPoolMem(sizeof(*ClassData->MethodHashTable)*METHOD_HASH_TABLE_SIZE)))
394 ULONG method;
396 memset(ClassData->MethodHashTable,'\0',sizeof(*ClassData->MethodHashTable)*METHOD_HASH_TABLE_SIZE);
397 #ifdef DEBUG_BGUI
398 ClassData->MethodColisions=0;
399 #endif
400 for(method=0;method<ClassData->MethodCount;method++)
402 SortedMethod **method_hash;
404 method_hash= ClassData->MethodHashTable+MethodHashValue(ClassData->MethodFunctions[method].MethodID);
405 #ifdef DEBUG_BGUI
406 if(*method_hash)
407 ClassData->MethodColisions++;
408 #endif
409 ClassData->MethodFunctions[method].NextHashedMethod= *method_hash;
410 *method_hash= &ClassData->MethodFunctions[method];
412 #ifdef DEBUG_BGUI
413 ClassData->MethodLookups=ClassData->MethodComparisions=0;
414 #endif
416 else
418 cl->cl_UserData=0;
419 FreeClass(cl);
420 cl=NULL;
424 else
426 cl->cl_UserData=0;
427 FreeClass(cl);
428 cl=NULL;
431 else
433 ClassData->MethodFunctions=NULL;
434 ClassData->MethodHashTable=NULL;
436 if(cl
437 && ClassData->ClassDispatcher)
439 struct opSet msg;
441 msg.MethodID=OM_NEW;
442 msg.ops_AttrList=NULL;
443 msg.ops_GInfo=NULL;
444 if(!METHOD_CALL(ClassData->ClassDispatcher,cl,NULL,(Msg)&msg,ClassData->ClassGlobalData))
446 cl->cl_UserData=0;
447 FreeClass(cl);
448 cl=NULL;
452 if(cl==NULL)
454 if(ClassData->MethodFunctions)
455 BGUI_FreePoolMem(ClassData->MethodFunctions);
456 BGUI_FreePoolMem(ClassData);
459 putreg(REG_A4, (IPTR)old_a4);
460 return cl;
462 AROS_LIBFUNC_EXIT
465 #ifdef __AROS__
466 makearosproto
467 AROS_LH1(BOOL, BGUI_FreeClass,
468 AROS_LHA(Class *, cl, A0),
469 struct Library *, BGUIBase, 25, BGUI)
470 #else
471 makeproto SAVEDS ASM BOOL BGUI_FreeClass(REG(a0) Class *cl)
472 #endif
474 AROS_LIBFUNC_INIT
476 if (cl)
478 if(cl->cl_UserData)
480 BGUIClassData *ClassData;
482 ClassData=((BGUIClassData *)cl->cl_UserData) - 1;
483 if(ClassData->ClassDispatcher)
485 ULONG msg=OM_DISPOSE;
487 if(!METHOD_CALL(ClassData->ClassDispatcher,cl,NULL,(Msg)&msg,ClassData->ClassGlobalData))
488 return FALSE;
490 if(ClassData->MethodFunctions)
492 D(bug("Methods %lu, Lookups %lu, Comparisions %lu, Misses %lu (%lu%%), Colisions %lu (%lu%%)\n",ClassData->MethodCount,ClassData->MethodLookups,ClassData->MethodComparisions,ClassData->MethodComparisions-ClassData->MethodLookups,ClassData->MethodComparisions ? (ClassData->MethodComparisions-ClassData->MethodLookups)*100/ClassData->MethodComparisions : 0,ClassData->MethodColisions,ClassData->MethodCount ? ClassData->MethodColisions*100/ClassData->MethodCount : 0));
493 BGUI_FreePoolMem(ClassData->MethodFunctions);
494 BGUI_FreePoolMem(ClassData->MethodHashTable);
496 BGUI_FreePoolMem(ClassData);
497 cl->cl_UserData=0;
499 if(FreeClass(cl))
501 MarkFreedClass(cl);
502 return(TRUE);
505 return FALSE;
507 AROS_LIBFUNC_EXIT
510 makeproto ULONG ASM BGUI_GetAttrChart(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct rmAttr *ra)
512 ULONG flags = ra->ra_Flags;
513 struct TagItem *attr = ra->ra_Attr;
514 IPTR data = 0;
515 UBYTE *dataspace;
516 ULONG rc;
518 if ((rc = (ULONG)AsmCoerceMethod(cl, obj, RM_GETATTRFLAGS, attr, flags)))
520 if (!(rc & RAF_NOGET))
522 dataspace = (UBYTE *)INST_DATA(cl, obj) + ((rc >> 16) & 0x07FF);
524 if (rc & RAF_BOOL)
526 data = (*dataspace >> ((rc >> 27) & 0x07)) & 1;
527 if (rc & RAF_SIGNED) data = !data;
529 else
531 switch (rc & (RAF_SIGNED|RAF_BYTE|RAF_WORD|RAF_LONG|RAF_IPTR|RAF_ADDR))
533 case RAF_BYTE:
534 data = (IPTR)(*(UBYTE *)dataspace);
535 break;
536 case RAF_BYTE|RAF_SIGNED:
537 data = (IPTR)(*(BYTE *)dataspace);
538 break;
539 case RAF_WORD:
540 data = (IPTR)(*(UWORD *)dataspace);
541 break;
542 case RAF_WORD|RAF_SIGNED:
543 data = (IPTR)(*(WORD *)dataspace);
544 break;
545 case RAF_LONG:
546 data = (IPTR)(*(ULONG *)dataspace);
547 break;
548 case RAF_LONG|RAF_SIGNED:
549 data = (IPTR)(*(LONG *)dataspace);
550 break;
551 case RAF_IPTR:
552 data = *(IPTR *)dataspace;
553 break;
554 case RAF_ADDR:
555 case RAF_ADDR|RAF_IPTR:
556 data = (IPTR)dataspace;
557 break;
558 case RAF_NOP:
559 goto no_get;
562 *((IPTR *)(attr->ti_Data)) = data;
564 no_get:
565 if (rc & RAF_CUSTOM)
567 AsmCoerceMethod(cl, obj, RM_GETCUSTOM, attr, flags);
569 if (rc & RAF_SUPER)
571 rc |= (ULONG)AsmDoSuperMethod(cl, obj, RM_GET, attr, flags);
573 rc = (rc & 0xFFFF) | RAF_UNDERSTOOD;
575 else
578 * Let the superclass have a go at it.
580 rc = (ULONG)AsmDoSuperMethodA(cl, obj, (Msg)ra);
582 return rc;
585 makeproto ULONG ASM BGUI_SetAttrChart(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct rmAttr *ra)
587 ULONG flags = ra->ra_Flags;
588 struct TagItem *attr = ra->ra_Attr;
589 ULONG data;
590 UBYTE *dataspace, flag;
591 ULONG rc;
593 if ((rc = (ULONG)AsmCoerceMethod(cl, obj, RM_GETATTRFLAGS, attr, flags)))
595 if ((rc & RAF_NOSET) || ((rc & RAF_NOUPDATE) && (flags & RAF_UPDATE))
596 || ((rc & RAF_NOINTERIM) && (flags & RAF_INTERIM))
597 || ((rc & RAF_INITIAL) && !(flags & RAF_INITIAL)))
599 rc &= ~RAF_SUPER;
601 else
603 if (flags & RAF_INITIAL) rc &= ~RAF_SUPER;
605 dataspace = (UBYTE *)INST_DATA(cl, obj) + ((rc >> 16) & 0x07FF);
606 data = attr->ti_Data;
608 if (rc & RAF_BOOL)
610 flag = 1 << ((rc >> 27) & 0x07);
611 if (rc & RAF_SIGNED) data = !data;
613 if (data) *dataspace |= flag;
614 else *dataspace &= ~flag;
616 else
618 switch (rc & (RAF_SIGNED|RAF_BYTE|RAF_WORD|RAF_LONG|RAF_IPTR|RAF_ADDR))
620 case RAF_BYTE:
621 case RAF_BYTE|RAF_SIGNED:
622 *((UBYTE *)dataspace) = (UBYTE)data;
623 break;
624 case RAF_WORD:
625 case RAF_WORD|RAF_SIGNED:
626 *((UWORD *)dataspace) = (UWORD)data;
627 break;
628 case RAF_LONG:
629 case RAF_LONG|RAF_SIGNED:
630 *((ULONG *)dataspace) = (ULONG)data;
631 break;
632 case RAF_IPTR:
633 *(IPTR *)dataspace = data;
634 case RAF_NOP:
635 break;
639 if (rc & RAF_CUSTOM)
641 AsmCoerceMethod(cl, obj, RM_SETCUSTOM, attr, flags);
643 if (rc & RAF_SUPER)
645 rc |= (ULONG)AsmDoSuperMethod(cl, obj, RM_SET, attr, flags);
647 rc = (rc & 0xFFFF) | RAF_UNDERSTOOD;
649 else
652 * Let the superclass have a go at it.
654 rc = (ULONG)AsmDoSuperMethod(cl, obj, RM_SET, attr, flags);
656 return rc;
659 makeproto ULONG BGUI_PackStructureTag(UBYTE *dataspace, ULONG *pt, Tag tag, IPTR data)
661 #ifdef ENHANCED
663 struct TagItem tags[2];
665 tags[0].ti_Tag = tag;
666 tags[0].ti_Data = (ULONG)data; // FIXME
667 tags[1].ti_Tag = TAG_DONE;
669 return PackStructureTags(dataspace, pt, tags);
671 #else
673 ULONG type;
674 UBYTE flag;
675 ULONG base = *pt++;
677 while (type = *pt++)
679 if (type == 0xFFFFFFFF)
681 base = *pt++;
682 continue;
684 if (tag == (base + ((type >> 16) & 0x03FF) ))
686 if (type & PKCTRL_UNPACKONLY) return 0;
688 dataspace += (type & 0x1FFF);
690 switch (type & 0x18000000)
692 case PKCTRL_BIT:
693 flag = 1 << ((type >> 13) & 0x0007);
694 if (type & PSTF_SIGNED) data = !data;
695 if (data) *dataspace |= flag;
696 else *dataspace &= ~flag;
697 break;
698 case PKCTRL_UBYTE:
699 *((UBYTE *)dataspace) = (UBYTE)data;
700 break;
701 case PKCTRL_UWORD:
702 *((UWORD *)dataspace) = (UWORD)data;
703 break;
704 case PKCTRL_ULONG:
705 *((ULONG *)dataspace) = (ULONG)data;
706 break;
708 return 1;
711 return 0;
713 #endif
716 makeproto ULONG BGUI_UnpackStructureTag(UBYTE *dataspace, ULONG *pt, Tag tag, IPTR *storage)
718 #ifdef ENHANCED
720 struct TagItem tags[2];
722 tags[0].ti_Tag = tag;
723 tags[0].ti_Data = (ULONG)(IPTR)storage;/* FIXME */
724 tags[1].ti_Tag = TAG_DONE;
726 return UnpackStructureTags(dataspace, pt, tags);
728 #else
730 ULONG type, data;
731 ULONG base = *pt++;
733 while (type = *pt++)
735 if (type == 0xFFFFFFFF)
737 base = *pt++;
738 continue;
740 if (tag == (base + ((type >> 16) & 0x03FF) ))
742 if (type & PKCTRL_PACKONLY) return 0;
744 dataspace += (type & 0x1FFF);
746 switch (type & 0x98000000)
748 case PKCTRL_UBYTE:
749 data = (ULONG)(*((UBYTE *)dataspace));
750 break;
751 case PKCTRL_UWORD:
752 data = (ULONG)(*((UWORD *)dataspace));
753 break;
754 case PKCTRL_ULONG:
755 data = (ULONG)(*((ULONG *)dataspace));
756 break;
757 case PKCTRL_BYTE:
758 data = (LONG)(*((BYTE *)dataspace));
759 break;
760 case PKCTRL_WORD:
761 data = (LONG)(*((WORD *)dataspace));
762 break;
763 case PKCTRL_LONG:
764 data = (LONG)(*((LONG *)dataspace));
765 break;
766 case PKCTRL_BIT:
767 case PKCTRL_FLIPBIT:
768 data = (*dataspace & (1 << ((type >> 13) & 0x0007))) ? ~0 : 0;
769 if (type & PSTF_SIGNED) data = ~data;
770 break;
772 *storage = data;
773 return 1;
776 return 0;
778 #endif
781 #ifdef __AROS__
782 makearosproto
783 AROS_LH3(ULONG, BGUI_PackStructureTags,
784 AROS_LHA(APTR, pack, A0),
785 AROS_LHA(ULONG *, packTable, A1),
786 AROS_LHA(struct TagItem *, tagList, A2),
787 struct Library *, BGUIBase, 26, BGUI)
788 #else
789 makeproto SAVEDS ULONG ASM BGUI_PackStructureTags(REG(a0) APTR pack, REG(a1) ULONG *packTable, REG(a2) struct TagItem *tagList)
790 #endif
792 AROS_LIBFUNC_INIT
794 #ifdef ENHANCED
796 return PackStructureTags(pack, packTable, tagList);
798 #else
800 struct TagItem *tstate = tagList, *tag;
801 ULONG rc = 0;
803 while (tag = NextTagItem(&tstate))
805 rc += BGUI_PackStructureTag((UBYTE *)pack, packTable, tag->ti_Tag, tag->ti_Data);
807 return rc;
809 #endif
811 AROS_LIBFUNC_EXIT
814 #ifdef __AROS__
815 makearosproto
816 AROS_LH3(ULONG, BGUI_UnpackStructureTags,
817 AROS_LHA(APTR, pack, A0),
818 AROS_LHA(ULONG *, packTable, A1),
819 AROS_LHA(struct TagItem *, tagList, A2),
820 struct Library *, BGUIBase, 27, BGUI)
821 #else
822 makeproto SAVEDS ULONG ASM BGUI_UnpackStructureTags(REG(a0) APTR pack, REG(a1) ULONG *packTable, REG(a2) struct TagItem *tagList)
823 #endif
825 AROS_LIBFUNC_INIT
827 #ifdef ENHANCED
829 return UnpackStructureTags(pack, packTable, tagList);
831 #else
833 struct TagItem *tstate = tagList, *tag;
834 ULONG rc = 0;
836 while ((tag = NextTagItem(&tstate)))
838 rc += BGUI_UnpackStructureTag((UBYTE *)pack, packTable, tag->ti_Tag, (ULONG *)tag->ti_Data);
840 return rc;
842 #endif
844 AROS_LIBFUNC_EXIT
848 * Quick GetAttr();
850 makeproto ASM ULONG Get_Attr(REG(a0) Object *obj, REG(d0) ULONG attr, REG(a1) IPTR *storage)
852 return (ULONG)AsmDoMethod(obj, OM_GET, attr, storage);
855 makeproto ASM ULONG Get_SuperAttr(REG(a2) Class *cl, REG(a0) Object *obj, REG(d0) ULONG attr, REG(a1) IPTR *storage)
857 return (ULONG)AsmDoSuperMethod(cl, obj, OM_GET, attr, storage);
860 makeproto IPTR NewSuperObject(Class *cl, Object *obj, struct TagItem *tags)
862 return AsmDoSuperMethod(cl, obj, OM_NEW, (IPTR)tags, NULL);
866 * Like SetAttrs();
868 makeproto ULONG DoSetMethodNG(Object *obj, Tag tag1, ...)
870 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
871 if (obj) retval = (ULONG)AsmDoMethod(obj, OM_SET, AROS_SLOWSTACKTAGS_ARG(tag1), NULL);
872 else retval = 0;
873 AROS_SLOWSTACKTAGS_POST
877 * Like SetAttrs();
879 makeproto ULONG DoSuperSetMethodNG(Class *cl, Object *obj, Tag tag1, ...)
881 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
882 if (obj) retval = (ULONG)AsmDoSuperMethod(cl, obj, OM_SET, AROS_SLOWSTACKTAGS_ARG(tag1), NULL);
883 else retval = 0;
884 AROS_SLOWSTACKTAGS_POST
888 * Call the OM_SET method.
890 makeproto ULONG DoSetMethod(Object *obj, struct GadgetInfo *ginfo, Tag tag1, ...)
892 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
893 if (obj) retval = (ULONG)AsmDoMethod(obj, OM_SET, AROS_SLOWSTACKTAGS_ARG(tag1), ginfo);
894 else retval = 0;
895 AROS_SLOWSTACKTAGS_POST
899 * Call the OM_SET method of the superclass.
901 makeproto ULONG DoSuperSetMethod(Class *cl, Object *obj, struct GadgetInfo *ginfo, Tag tag1, ...)
903 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
904 if (obj) retval = (ULONG)AsmDoSuperMethod(cl, obj, OM_SET, AROS_SLOWSTACKTAGS_ARG(tag1), ginfo);
905 else retval = 0;
906 AROS_SLOWSTACKTAGS_POST
910 * Call the OM_UPDATE method.
912 makeproto ULONG DoUpdateMethod(Object *obj, struct GadgetInfo *ginfo, ULONG flags, Tag tag1, ...)
914 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
915 if (obj) retval = (ULONG)AsmDoMethod(obj, OM_UPDATE, AROS_SLOWSTACKTAGS_ARG(tag1), ginfo, flags);
916 else retval = 0;
917 AROS_SLOWSTACKTAGS_POST
921 * Call the OM_NOTIFY method.
923 makeproto ULONG DoNotifyMethod(Object *obj, struct GadgetInfo *ginfo, ULONG flags, Tag tag1, ...)
925 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
926 if (obj) retval = (ULONG)AsmDoMethod(obj, OM_NOTIFY, AROS_SLOWSTACKTAGS_ARG(tag1), ginfo, flags);
927 else retval = 0;
928 AROS_SLOWSTACKTAGS_POST
932 * Call the GM_RENDER method.
935 makeproto ASM IPTR DoRenderMethod(REG(a0) Object *obj, REG(a1) struct GadgetInfo *ginfo, REG(d0) ULONG redraw)
937 struct RastPort *rp;
938 IPTR rc = 0;
940 if (obj && (rp = BGUI_ObtainGIRPort(ginfo)))
942 rc = AsmDoMethod(obj, GM_RENDER, ginfo, rp, redraw);
943 ReleaseGIRPort(rp);
945 return rc;
949 * Forward certain types of messages with modifications.
951 makeproto ASM IPTR ForwardMsg(REG(a0) Object *s, REG(a1) Object *d, REG(a2) Msg msg)
953 #ifdef __AROS__
954 #define MOUSEWORD STACKED WORD
955 #else
956 #define MOUSEWORD WORD
957 #endif
958 MOUSEWORD *mousex = NULL, *mousey = NULL, old_mousex, old_mousey;
959 IPTR rc;
960 struct IBox *b1 = GADGETBOX(s);
961 struct IBox *b2 = GADGETBOX(d);
964 * Get address of mouse coordinates in message.
966 switch (msg->MethodID)
968 case GM_HITTEST:
969 case GM_HELPTEST:
970 mousex = &((struct gpHitTest *)msg)->gpht_Mouse.X;
971 mousey = &((struct gpHitTest *)msg)->gpht_Mouse.Y;
972 break;
973 case GM_GOACTIVE:
974 case GM_HANDLEINPUT:
975 mousex = &((struct gpInput *)msg)->gpi_Mouse.X;
976 mousey = &((struct gpInput *)msg)->gpi_Mouse.Y;
977 break;
979 if (!mousex) return 0;
982 * Store the coordinates.
984 old_mousex = *mousex;
985 old_mousey = *mousey;
987 Get_Attr(s, BT_OuterBox, (IPTR *)&b1);
988 Get_Attr(d, BT_OuterBox, (IPTR *)&b2);
991 * Adjust the coordinates to be relative to the destination object.
993 *mousex += b1->Left - b2->Left;
994 *mousey += b1->Top - b2->Top;
997 * Send the message to the destination object.
999 rc = AsmDoMethodA(d, msg);
1002 * Put the coordinates back to what they were originally.
1004 *mousex = old_mousex;
1005 *mousey = old_mousey;
1007 return rc;
1010 #define BI_FREE_RP 1
1011 #define BI_FREE_DRI 2
1013 #ifdef DEBUG_BGUI
1014 makeproto struct BaseInfo *AllocBaseInfoDebug(STRPTR file, ULONG line,Tag tag1, ...)
1016 AROS_SLOWSTACKTAGS_PRE_AS(tag1, struct BaseInfo *)
1017 retval = BGUI_AllocBaseInfoDebugA(AROS_SLOWSTACKTAGS_ARG(tag1),file,line);
1018 AROS_SLOWSTACKTAGS_POST
1020 #else
1021 makeproto struct BaseInfo *AllocBaseInfo(Tag tag1, ...)
1023 AROS_SLOWSTACKTAGS_PRE_AS(tag1, struct BaseInfo *)
1024 retval = BGUI_AllocBaseInfoA(AROS_SLOWSTACKTAGS_ARG(tag1));
1025 AROS_SLOWSTACKTAGS_POST
1027 #endif
1029 #ifdef DEBUG_BGUI
1030 makeproto SAVEDS ASM struct BaseInfo *BGUI_AllocBaseInfoDebugA(REG(a0) struct TagItem *tags,REG(a1) STRPTR file, REG(d0) ULONG line)
1031 #else
1032 makeproto SAVEDS ASM struct BaseInfo *BGUI_AllocBaseInfoA(REG(a0) struct TagItem *tags)
1033 #endif
1035 struct BaseInfo *bi, *bi2;
1036 struct GadgetInfo *gi = NULL;
1037 ULONG *flags;
1039 #ifdef DEBUG_BGUI
1040 if ((bi = BGUI_AllocPoolMemDebug(sizeof(struct BaseInfo) + sizeof(ULONG),file,line)))
1041 #else
1042 if ((bi = BGUI_AllocPoolMem(sizeof(struct BaseInfo) + sizeof(ULONG))))
1043 #endif
1045 flags = (ULONG *)(bi + 1);
1047 if ((bi2 = (struct BaseInfo *)GetTagData(BI_BaseInfo, 0, tags)))
1049 *bi = *bi2;
1051 else
1052 memset(bi,'\0',sizeof(*bi));
1054 if ((gi = (struct GadgetInfo *)GetTagData(BI_GadgetInfo, (IPTR)gi, tags)))
1056 *((struct GadgetInfo *)bi) = *gi;
1059 bi->bi_DrInfo = (struct DrawInfo *)GetTagData(BI_DrawInfo, (IPTR)bi->bi_DrInfo, tags);
1060 bi->bi_RPort = (struct RastPort *)GetTagData(BI_RastPort, (IPTR)bi->bi_RPort, tags);
1061 bi->bi_IScreen = (struct Screen *) GetTagData(BI_Screen, (IPTR)bi->bi_IScreen, tags);
1062 bi->bi_Pens = (UWORD *) GetTagData(BI_Pens, (IPTR)bi->bi_Pens, tags);
1064 if (gi && !bi->bi_RPort)
1066 if ((bi->bi_RPort = ObtainGIRPort(gi)))
1068 *flags |= BI_FREE_RP;
1072 if (bi->bi_IScreen && !bi->bi_DrInfo)
1074 if ((bi->bi_DrInfo = GetScreenDrawInfo(bi->bi_IScreen)))
1076 *flags |= BI_FREE_DRI;
1080 if (!bi->bi_Pens)
1082 if (bi->bi_DrInfo) bi->bi_Pens = bi->bi_DrInfo->dri_Pens;
1083 else bi->bi_Pens = DefDriPens;
1086 return bi;
1089 #ifdef DEBUG_BGUI
1090 makeproto void FreeBaseInfoDebug(struct BaseInfo *bi, STRPTR file, ULONG line)
1092 #else
1093 makeproto void FreeBaseInfo(struct BaseInfo *bi)
1095 #endif
1096 ULONG *flags = (ULONG *)(bi + 1);
1098 if (*flags & BI_FREE_RP) ReleaseGIRPort(bi->bi_RPort);
1099 if (*flags & BI_FREE_DRI) FreeScreenDrawInfo(bi->bi_IScreen, bi->bi_DrInfo);
1101 #ifdef DEBUG_BGUI
1102 BGUI_FreePoolMemDebug(bi,file,line);
1103 #else
1104 BGUI_FreePoolMem(bi);
1105 #endif