2 Copyright © 2002-2014, The AROS Development Team. All rights reserved.
9 #include <exec/types.h>
10 #include <clib/alib_protos.h>
11 #include <libraries/commodities.h>
12 #include <proto/commodities.h>
13 #include <proto/exec.h>
14 #include <proto/intuition.h>
15 #include <proto/utility.h>
16 #include <proto/muimaster.h>
18 #include "muimaster_intern.h"
27 extern struct Library
*MUIMasterBase
;
29 AROS_UFH2S(void, cpy_func
,
30 AROS_UFHA(UBYTE
, chr
, D0
),
31 AROS_UFHA(STRPTR
*, strPtrPtr
, A3
))
35 *(*strPtrPtr
)++ = chr
;
40 AROS_UFH2S(void, len_func
,
41 AROS_UFHA(UBYTE
, chr
, D0
),
42 AROS_UFHA(LONG
*, lenPtr
, A3
))
53 * Notify class is superclass of all other MUI classes.
57 MUIA_ApplicationObject [..G] done
58 MUIA_AppMessage [..G] done
59 MUIA_HelpLine [ISG] done
60 MUIA_HelpNode [ISG] done
61 MUIA_NoNotify [.S.] done
62 MUIA_ObjectID [ISG] done
63 MUIA_Parent [..G] done
64 MUIA_Revision [..G] done
65 MUIA_UserData [ISG] done
66 MUIA_Version [..G] done
69 MUIM_Export dummy & redefine in subclasses w/ children
70 MUIM_FindUData redefine in subclasses w/ children
72 MUIM_GetUData redefine in subclasses w/ children
73 MUIM_Import dummy & redefine in subclasses w/ children
75 MUIM_KillNotifyObj done (semantic ?)
81 MUIM_SetUData redefine in subclasses w/ children
82 MUIM_SetUDataOnce redefine in subclasses w/ children
87 static const int __version
= 1;
88 static const int __revision
= 1;
90 struct MUI_NotifyAttributes
94 struct AppMessage
*na_AppMessage
;
98 * Notification handler
100 typedef struct NotifyNode
102 struct MinNode nn_Node
;
103 BOOL nn_Active
; /* TRUE if notification is currently being handled */
104 /* It's used to prevent loops */
109 IPTR
*nn_Params
; /* FIXME: use nn_Params[1] and tweak stuff below */
110 IPTR
*nn_NewParams
; /* For MUIV_EveryTime */
113 typedef struct NotifyNodeIX
115 struct NotifyNode nn
;
119 static struct NotifyNode
*CreateNNode(struct MUI_NotifyData
*data
,
120 struct MUIP_Notify
*msg
)
124 struct NotifyNode
*nnode
;
126 if ((msg
->TrigAttr
== MUIA_Window_InputEvent
)
127 && (msg
->TrigVal
!= MUIV_EveryTime
))
129 IX ix
= { IX_VERSION
};
131 if (ParseIX((CONST_STRPTR
) msg
->TrigVal
, &ix
) != 0)
135 (struct NotifyNode
*)mui_alloc_struct(struct NotifyNodeIX
)))
137 ((struct NotifyNodeIX
*)nnode
)->ix
= ix
;
142 nnode
= mui_alloc_struct(struct NotifyNode
);
148 nnode
->nn_Active
= FALSE
;
149 nnode
->nn_TrigAttr
= msg
->TrigAttr
;
150 nnode
->nn_TrigVal
= msg
->TrigVal
;
151 nnode
->nn_DestObj
= msg
->DestObj
;
152 nnode
->nn_NumParams
= msg
->FollowParams
;
154 /* Allocate one more IPTR (FollowParams + 1) as some ext apps/classes
155 forget trailing NULLs in methods like MUIM_MultiSet and MUI seems
156 like it can live with that (without crashing) */
158 paramsize
= (msg
->FollowParams
+ 1);
159 if (msg
->TrigVal
== MUIV_EveryTime
)
164 if ((nnode
->nn_Params
= (IPTR
*) mui_alloc(paramsize
* sizeof(IPTR
))))
166 IPTR
*par
= (IPTR
*) & msg
->FollowParams
;
168 for (i
= 0; i
< msg
->FollowParams
; i
++)
170 nnode
->nn_Params
[i
] = *(par
+ i
+ 1);
173 if (msg
->TrigVal
== MUIV_EveryTime
)
175 nnode
->nn_NewParams
= nnode
->nn_Params
+ msg
->FollowParams
+ 1;
176 for (i
= 0; i
< msg
->FollowParams
; i
++)
178 nnode
->nn_NewParams
[i
] = *(par
+ i
+ 1);
190 static void DeleteNNode(struct MUI_NotifyData
*data
,
191 struct NotifyNode
*nnode
)
193 mui_free(nnode
->nn_Params
);
198 IPTR
Notify__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
);
203 IPTR
Notify__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
205 struct MUI_NotifyData
*data
;
206 struct TagItem
*tags
= msg
->ops_AttrList
;
209 obj
= (Object
*) DoSuperMethodA(cl
, obj
, (Msg
) msg
);
213 data
= INST_DATA(cl
, obj
);
215 data
->mnd_Attributes
= mui_alloc_struct(struct MUI_NotifyAttributes
);
216 if (data
->mnd_Attributes
== NULL
)
218 CoerceMethod(cl
, obj
, OM_DISPOSE
);
222 while ((tag
= NextTagItem(&tags
)) != NULL
)
227 data
->mnd_Attributes
->na_HelpLine
= (LONG
) tag
->ti_Data
;
231 data
->mnd_Attributes
->na_HelpNode
= (STRPTR
) tag
->ti_Data
;
235 data
->mnd_ObjectID
= (ULONG
) tag
->ti_Data
;
239 data
->mnd_UserData
= (IPTR
) tag
->ti_Data
;
251 IPTR
Notify__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
253 struct MinNode
*node
, *tmp
;
254 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
256 mui_free(data
->mnd_Attributes
);
258 if (data
->mnd_NotifyList
)
260 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
263 tmp
= node
->mln_Succ
;
264 DeleteNNode(data
, (struct NotifyNode
*)node
);
266 mui_free(data
->mnd_NotifyList
);
269 return DoSuperMethodA(cl
, obj
, msg
);
272 static void check_notify(NNode nnode
, Object
*obj
, struct TagItem
*tag
)
277 BOOL donotify
= FALSE
;
279 /* is it the good attribute ? */
280 if (tag
->ti_Tag
!= nnode
->nn_TrigAttr
)
283 /* Is the notification already being performed? */
284 if (nnode
->nn_Active
)
289 D(bug("Notifyloop detected! (#%d)\n", counter
++));
290 D(bug(" Source object: 0x%x", obj
));
292 switch ((IPTR
) nnode
->nn_DestObj
)
294 case MUIV_Notify_Application
:
295 D(bug(" Dest object: 0x%x (MUIV_Notify_Application)\n",
298 case MUIV_Notify_Self
:
299 D(bug(" Dest object: 0x%x (MUIV_Notify_Self)\n", obj
));
302 case MUIV_Notify_Window
:
303 if (muiRenderInfo(obj
)) /* otherwise _win(obj) does NULL access! */
305 D(bug(" Dest object: 0x%x (MUIV_Notify_Window)\n",
310 D(bug(" Dest object: INVALID "
311 "(MUIV_Notify_Window, but no muiRenderInfo)\n"));
315 D(bug(" Dest object: 0x%x\n", nnode
->nn_DestObj
));
318 D(bug(" Attribute: 0x%x Value: 0x%x\n", tag
->ti_Tag
,
325 if (nnode
->nn_TrigVal
== MUIV_EveryTime
)
329 else if (nnode
->nn_TrigAttr
== MUIA_Window_InputEvent
)
331 if (MatchIX((struct InputEvent
*)tag
->ti_Data
,
332 &((struct NotifyNodeIX
*)nnode
)->ix
))
337 else if (nnode
->nn_TrigVal
== tag
->ti_Data
)
344 switch ((IPTR
) nnode
->nn_DestObj
)
346 case MUIV_Notify_Application
:
349 case MUIV_Notify_Self
:
352 case MUIV_Notify_Window
:
353 if (muiRenderInfo(obj
)) /* otherwise _win(obj) does NULL access! */
363 destobj
= nnode
->nn_DestObj
;
366 params
= nnode
->nn_Params
;
367 if (nnode
->nn_TrigVal
== MUIV_EveryTime
)
369 params
= nnode
->nn_NewParams
;
371 for (i
= 1; i
< nnode
->nn_NumParams
; i
++)
373 switch (nnode
->nn_Params
[i
])
375 case MUIV_TriggerValue
:
376 params
[i
] = tag
->ti_Data
;
379 case MUIV_NotTriggerValue
:
380 params
[i
] = !tag
->ti_Data
;
386 nnode
->nn_Active
= TRUE
;
389 DoMethodA(destobj
, (Msg
) params
);
391 nnode
->nn_Active
= FALSE
;
398 IPTR
Notify__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
400 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
401 struct TagItem
*tags
= msg
->ops_AttrList
;
402 BOOL no_notify
= FALSE
;
404 struct MinNode
*node
;
406 /* There are many ways to find out what tag items provided by set()
407 ** we do know. The best way should be using NextTagItem() and simply
408 ** browsing through the list.
410 while ((tag
= NextTagItem(&tags
)) != NULL
)
414 case MUIA_AppMessage
:
415 data
->mnd_Attributes
->na_AppMessage
= (struct AppMessage
*)tag
->ti_Data
;
419 data
->mnd_Attributes
->na_HelpLine
= (LONG
) tag
->ti_Data
;
423 data
->mnd_Attributes
->na_HelpNode
= (STRPTR
) tag
->ti_Data
;
427 if (tag
->ti_Data
== TRUE
)
432 data
->mnd_ObjectID
= (ULONG
) tag
->ti_Data
;
436 data
->mnd_UserData
= tag
->ti_Data
;
442 * check for notifications
444 if (!data
->mnd_NotifyList
|| no_notify
)
447 tags
= msg
->ops_AttrList
;
448 while ((tag
= NextTagItem(&tags
)))
450 for (node
= data
->mnd_NotifyList
->mlh_Head
;
451 node
->mln_Succ
; node
= node
->mln_Succ
)
453 check_notify((NNode
) node
, obj
, tag
);
464 IPTR
Notify__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
466 /* small macro to simplify return value storage */
467 #define STORE *(msg->opg_Storage)
469 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
471 //kprintf("*** Notify->GET\n");
472 switch (msg
->opg_AttrID
)
474 case MUIA_ApplicationObject
:
475 if (data
->mnd_GlobalInfo
)
476 STORE
= (IPTR
) data
->mnd_GlobalInfo
->mgi_ApplicationObject
;
481 case MUIA_AppMessage
:
482 STORE
= (IPTR
) data
->mnd_Attributes
->na_AppMessage
;
486 STORE
= (IPTR
) data
->mnd_Attributes
->na_HelpLine
;
490 STORE
= (IPTR
) data
->mnd_Attributes
->na_HelpNode
;
494 STORE
= (IPTR
) data
->mnd_ObjectID
;
498 STORE
= (IPTR
) data
->mnd_ParentObject
;
506 STORE
= data
->mnd_UserData
;
514 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
519 * MUIM_CallHook : Call a standard amiga callback hook, defined by a Hook
522 IPTR
Notify__MUIM_CallHook(struct IClass
*cl
, Object
*obj
,
523 struct MUIP_CallHook
*msg
)
525 if (msg
->Hook
->h_Entry
)
526 return CallHookPkt(msg
->Hook
, obj
, &msg
->param1
);
533 * MUIM_Export : to export an object's "contents" to a dataspace object.
535 /* nothing to export */
538 * MUIM_FindUData : tests if the MUIA_UserData of the object
539 * contains the given <udata> and returns the object pointer in this case.
541 IPTR
Notify__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
542 struct MUIP_FindUData
*msg
)
544 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
546 if (data
->mnd_UserData
== msg
->udata
)
555 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
556 * contains the given <udata> and gets <attr> to <storage> for itself
559 IPTR
Notify__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
560 struct MUIP_GetUData
*msg
)
562 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
564 if (data
->mnd_UserData
== msg
->udata
)
566 get(obj
, msg
->attr
, msg
->storage
);
574 * MUIM_Import : to import an object's "contents" from a dataspace object.
576 /* nothing to import */
579 * MUIM_KillNotify : kills previously given notifications on specific attributes.
581 IPTR
Notify__MUIM_KillNotify(struct IClass
*cl
, Object
*obj
,
582 struct MUIP_KillNotify
*msg
)
584 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
585 struct MinNode
*node
;
586 struct NotifyNode
*nnode
;
588 if (!data
->mnd_NotifyList
)
591 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
592 node
= node
->mln_Succ
)
594 nnode
= (NNode
) node
;
595 if (msg
->TrigAttr
== nnode
->nn_TrigAttr
)
597 Remove((struct Node
*)node
);
598 DeleteNNode(data
, nnode
);
607 * MUIM_KillNotifyObj : originally undocumented !
608 * Supposed to kill a notification with a given attr and a given dest.
610 IPTR
Notify__MUIM_KillNotifyObj(struct IClass
*cl
, Object
*obj
,
611 struct MUIP_KillNotifyObj
*msg
)
613 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
614 struct MinNode
*node
;
615 struct NotifyNode
*nnode
;
617 if (!data
->mnd_NotifyList
)
620 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
621 node
= node
->mln_Succ
)
623 nnode
= (NNode
) node
;
624 if ((msg
->TrigAttr
== nnode
->nn_TrigAttr
)
625 && (msg
->dest
== nnode
->nn_DestObj
))
627 Remove((struct Node
*)node
);
628 DeleteNNode(data
, nnode
);
637 * MUIM_MultiSet : Set an attribute for multiple objects.
639 IPTR
Notify__MUIM_MultiSet(struct IClass
*cl
, Object
*obj
,
640 struct MUIP_MultiSet
*msg
)
643 for (destobj_p
= (IPTR
*) & msg
->obj
; (*destobj_p
) != 0; destobj_p
++)
645 set((APTR
) *destobj_p
, msg
->attr
, msg
->val
);
652 * MUIM_NoNotifySet : Acts like MUIM_Set but doesn't trigger any notification.
654 IPTR
Notify__MUIM_NoNotifySet(struct IClass
*cl
, Object
*obj
,
655 struct MUIP_NoNotifySet
*msg
)
657 return SetAttrs(obj
, MUIA_NoNotify
, TRUE
, msg
->attr
, msg
->val
,
663 * MUIM_Notify : Add a notification event handler to an object.
665 IPTR
Notify__MUIM_Notify(struct IClass
*cl
, Object
*obj
,
666 struct MUIP_Notify
*msg
)
668 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
669 struct NotifyNode
*nnode
;
671 if (msg
->FollowParams
< 1)
674 if (data
->mnd_NotifyList
== NULL
)
676 if (!(data
->mnd_NotifyList
= mui_alloc_struct(struct MinList
)))
678 NewList((struct List
*)data
->mnd_NotifyList
);
681 nnode
= CreateNNode(data
, msg
);
685 AddTail((struct List
*)data
->mnd_NotifyList
, (struct Node
*)nnode
);
691 * MUIM_Set : Set an attribute to a value, useful within a MUIM_Notify method.
693 IPTR
Notify__MUIM_Set(struct IClass
*cl
, Object
*obj
,
694 struct MUIP_Set
*msg
)
696 return set(obj
, msg
->attr
, msg
->val
);
700 * MUIM_SetAsString : Set a (text kind) attribute to a string.
702 IPTR
Notify__MUIM_SetAsString(struct IClass
*cl
, Object
*obj
,
703 struct MUIP_SetAsString
*msg
)
709 RawDoFmt(msg
->format
, (RAWARG
)&msg
->val
,
710 (VOID_FUNC
) AROS_ASMSYMNAME(len_func
), &txt_len
);
712 /* D(bug("Notify_SetAsString: fmt=%s, txtlen=%d\n", msg->format, txt_len)); */
713 txt
= AllocVec(txt_len
+ 1, 0);
719 RawDoFmt(msg
->format
, (RAWARG
)&msg
->val
,
720 (VOID_FUNC
) AROS_ASMSYMNAME(cpy_func
), &txtptr
);
723 set(obj
, msg
->attr
, (IPTR
) txt
);
731 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
732 * contains the given <udata> and sets <attr> to <val> for itself in this case.
734 IPTR
Notify__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
735 struct MUIP_SetUData
*msg
)
737 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
739 if (data
->mnd_UserData
== msg
->udata
)
741 set(obj
, msg
->attr
, msg
->val
);
749 * MUIM_WriteLong : This method simply writes a longword somewhere to memory.
751 IPTR
Notify__MUIM_WriteLong(struct IClass
*cl
, Object
*obj
,
752 struct MUIP_WriteLong
*msg
)
754 *(msg
->memory
) = msg
->val
;
760 * MUIM_WriteString : This method simply copies a string somewhere to memory.
762 IPTR
Notify__MUIM_WriteString(struct IClass
*cl
, Object
*obj
,
763 struct MUIP_WriteString
*msg
)
765 strcpy(msg
->memory
, msg
->str
);
769 /**************************************************************************
771 **************************************************************************/
772 IPTR
Notify__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
773 struct MUIP_ConnectParent
*msg
)
775 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
777 /* Objects only have parents if they are inside a group or family object;
778 ** no idea why MUIA_Parent belongs to the notify class then
780 /* data->mnd_ParentObject = msg->parent;*/
781 muiGlobalInfo(obj
) = muiGlobalInfo(msg
->parent
);
785 /**************************************************************************
786 MUIM_DisconnectParent
787 **************************************************************************/
788 IPTR
Notify__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
789 struct MUIP_DisconnectParent
*msg
)
791 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
792 /* data->mnd_ParentObject = NULL;*/
794 /* Some apps (YAM) seem to access this even after disconnection */
795 muiGlobalInfo(obj
) = NULL
;
800 /**************************************************************************
802 **************************************************************************/
803 IPTR
Notify__MUIM_GetConfigItem(struct IClass
*cl
, Object
*obj
,
804 struct MUIP_GetConfigItem
*msg
)
807 DoMethod(muiGlobalInfo(obj
)->mgi_Configdata
, MUIM_Dataspace_Find
,
812 *msg
->storage
= found
;
822 BOOPSI_DISPATCHER(IPTR
, Notify_Dispatcher
, cl
, obj
, msg
)
824 switch (msg
->MethodID
)
827 return Notify__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
829 return Notify__OM_DISPOSE(cl
, obj
, msg
);
831 return Notify__OM_SET(cl
, obj
, (struct opSet
*)msg
);
833 return Notify__OM_GET(cl
, obj
, (struct opGet
*)msg
);
835 return Notify__MUIM_CallHook(cl
, obj
, (APTR
) msg
);
839 return Notify__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
841 return Notify__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
844 case MUIM_KillNotify
:
845 return Notify__MUIM_KillNotify(cl
, obj
, (APTR
) msg
);
846 case MUIM_KillNotifyObj
:
847 return Notify__MUIM_KillNotifyObj(cl
, obj
, (APTR
) msg
);
849 return Notify__MUIM_MultiSet(cl
, obj
, (APTR
) msg
);
850 case MUIM_NoNotifySet
:
851 return Notify__MUIM_NoNotifySet(cl
, obj
, (APTR
) msg
);
853 return Notify__MUIM_Notify(cl
, obj
, (APTR
) msg
);
855 return Notify__MUIM_Set(cl
, obj
, (APTR
) msg
);
856 case MUIM_SetAsString
:
857 return Notify__MUIM_SetAsString(cl
, obj
, (APTR
) msg
);
859 return Notify__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
860 case MUIM_SetUDataOnce
:
861 return Notify__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
862 /* use Notify_SetUData */
864 return Notify__MUIM_WriteLong(cl
, obj
, (APTR
) msg
);
865 case MUIM_WriteString
:
866 return Notify__MUIM_WriteString(cl
, obj
, (APTR
) msg
);
867 case MUIM_ConnectParent
:
868 return Notify__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
869 case MUIM_DisconnectParent
:
870 return Notify__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
871 case MUIM_GetConfigItem
:
872 return Notify__MUIM_GetConfigItem(cl
, obj
, (APTR
) msg
);
875 return DoSuperMethodA(cl
, obj
, msg
);
877 BOOPSI_DISPATCHER_END
882 const struct __MUIBuiltinClass _MUI_Notify_desc
=
884 MUIC_Notify
, /* Class name */
885 ROOTCLASS
, /* super class name */
886 sizeof(struct MUI_NotifyData
), /* size of class's own data */
887 (void *) Notify_Dispatcher
/* class dispatcher */