2 Copyright © 2002-2018, 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
)
288 bug("%s: MUI Notification loop detected! (#%d)\n", FindTask(NULL
)->tc_Node
.ln_Name
, 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 ForeachNode (data
->mnd_NotifyList
, node
)
452 check_notify((NNode
) node
, obj
, tag
);
463 IPTR
Notify__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
465 /* small macro to simplify return value storage */
466 #define STORE *(msg->opg_Storage)
468 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
470 //kprintf("*** Notify->GET\n");
471 switch (msg
->opg_AttrID
)
473 case MUIA_ApplicationObject
:
474 if (data
->mnd_GlobalInfo
)
475 STORE
= (IPTR
) data
->mnd_GlobalInfo
->mgi_ApplicationObject
;
480 case MUIA_AppMessage
:
481 STORE
= (IPTR
) data
->mnd_Attributes
->na_AppMessage
;
485 STORE
= (IPTR
) data
->mnd_Attributes
->na_HelpLine
;
489 STORE
= (IPTR
) data
->mnd_Attributes
->na_HelpNode
;
493 STORE
= (IPTR
) data
->mnd_ObjectID
;
497 STORE
= (IPTR
) data
->mnd_ParentObject
;
505 STORE
= data
->mnd_UserData
;
513 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
518 * MUIM_CallHook : Call a standard amiga callback hook, defined by a Hook
521 IPTR
Notify__MUIM_CallHook(struct IClass
*cl
, Object
*obj
,
522 struct MUIP_CallHook
*msg
)
524 if (msg
->Hook
->h_Entry
)
525 return CallHookPkt(msg
->Hook
, obj
, &msg
->param1
);
532 * MUIM_Export : to export an object's "contents" to a dataspace object.
534 /* nothing to export */
537 * MUIM_FindUData : tests if the MUIA_UserData of the object
538 * contains the given <udata> and returns the object pointer in this case.
540 IPTR
Notify__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
541 struct MUIP_FindUData
*msg
)
543 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
545 if (data
->mnd_UserData
== msg
->udata
)
554 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
555 * contains the given <udata> and gets <attr> to <storage> for itself
558 IPTR
Notify__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
559 struct MUIP_GetUData
*msg
)
561 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
563 if (data
->mnd_UserData
== msg
->udata
)
565 get(obj
, msg
->attr
, msg
->storage
);
573 * MUIM_Import : to import an object's "contents" from a dataspace object.
575 /* nothing to import */
578 * MUIM_KillNotify : kills previously given notifications on specific attributes.
580 IPTR
Notify__MUIM_KillNotify(struct IClass
*cl
, Object
*obj
,
581 struct MUIP_KillNotify
*msg
)
583 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
584 struct MinNode
*node
;
585 struct NotifyNode
*nnode
;
587 if (!data
->mnd_NotifyList
)
590 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
591 node
= node
->mln_Succ
)
593 nnode
= (NNode
) node
;
594 if (msg
->TrigAttr
== nnode
->nn_TrigAttr
)
596 Remove((struct Node
*)node
);
597 DeleteNNode(data
, nnode
);
606 * MUIM_KillNotifyObj : originally undocumented !
607 * Supposed to kill a notification with a given attr and a given dest.
609 IPTR
Notify__MUIM_KillNotifyObj(struct IClass
*cl
, Object
*obj
,
610 struct MUIP_KillNotifyObj
*msg
)
612 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
613 struct MinNode
*node
;
614 struct NotifyNode
*nnode
;
616 if (!data
->mnd_NotifyList
)
619 for (node
= data
->mnd_NotifyList
->mlh_Head
; node
->mln_Succ
;
620 node
= node
->mln_Succ
)
622 nnode
= (NNode
) node
;
623 if ((msg
->TrigAttr
== nnode
->nn_TrigAttr
)
624 && (msg
->dest
== nnode
->nn_DestObj
))
626 Remove((struct Node
*)node
);
627 DeleteNNode(data
, nnode
);
636 * MUIM_MultiSet : Set an attribute for multiple objects.
638 IPTR
Notify__MUIM_MultiSet(struct IClass
*cl
, Object
*obj
,
639 struct MUIP_MultiSet
*msg
)
642 for (destobj_p
= (IPTR
*) & msg
->obj
; (*destobj_p
) != 0; destobj_p
++)
644 set((APTR
) *destobj_p
, msg
->attr
, msg
->val
);
651 * MUIM_NoNotifySet : Acts like MUIM_Set but doesn't trigger any notification.
653 IPTR
Notify__MUIM_NoNotifySet(struct IClass
*cl
, Object
*obj
,
654 struct MUIP_NoNotifySet
*msg
)
656 return SetAttrs(obj
, MUIA_NoNotify
, TRUE
, msg
->attr
, msg
->val
,
662 * MUIM_Notify : Add a notification event handler to an object.
664 IPTR
Notify__MUIM_Notify(struct IClass
*cl
, Object
*obj
,
665 struct MUIP_Notify
*msg
)
667 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
668 struct NotifyNode
*nnode
;
670 if (msg
->FollowParams
< 1)
673 if (data
->mnd_NotifyList
== NULL
)
675 if (!(data
->mnd_NotifyList
= mui_alloc_struct(struct MinList
)))
677 NewList((struct List
*)data
->mnd_NotifyList
);
680 nnode
= CreateNNode(data
, msg
);
684 AddTail((struct List
*)data
->mnd_NotifyList
, (struct Node
*)nnode
);
690 * MUIM_Set : Set an attribute to a value, useful within a MUIM_Notify method.
692 IPTR
Notify__MUIM_Set(struct IClass
*cl
, Object
*obj
,
693 struct MUIP_Set
*msg
)
695 return set(obj
, msg
->attr
, msg
->val
);
699 * MUIM_SetAsString : Set a (text kind) attribute to a string.
701 IPTR
Notify__MUIM_SetAsString(struct IClass
*cl
, Object
*obj
,
702 struct MUIP_SetAsString
*msg
)
708 RawDoFmt(msg
->format
, (RAWARG
)&msg
->val
,
709 (VOID_FUNC
) AROS_ASMSYMNAME(len_func
), &txt_len
);
711 /* D(bug("Notify_SetAsString: fmt=%s, txtlen=%d\n", msg->format, txt_len)); */
712 txt
= AllocVec(txt_len
+ 1, 0);
718 RawDoFmt(msg
->format
, (RAWARG
)&msg
->val
,
719 (VOID_FUNC
) AROS_ASMSYMNAME(cpy_func
), &txtptr
);
722 set(obj
, msg
->attr
, (IPTR
) txt
);
730 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
731 * contains the given <udata> and sets <attr> to <val> for itself in this case.
733 IPTR
Notify__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
734 struct MUIP_SetUData
*msg
)
736 struct MUI_NotifyData
*data
= INST_DATA(cl
, obj
);
738 if (data
->mnd_UserData
== msg
->udata
)
740 set(obj
, msg
->attr
, msg
->val
);
748 * MUIM_WriteLong : This method simply writes a longword somewhere to memory.
750 IPTR
Notify__MUIM_WriteLong(struct IClass
*cl
, Object
*obj
,
751 struct MUIP_WriteLong
*msg
)
753 *(msg
->memory
) = msg
->val
;
759 * MUIM_WriteString : This method simply copies a string somewhere to memory.
761 IPTR
Notify__MUIM_WriteString(struct IClass
*cl
, Object
*obj
,
762 struct MUIP_WriteString
*msg
)
764 strcpy(msg
->memory
, msg
->str
);
768 /**************************************************************************
770 **************************************************************************/
771 IPTR
Notify__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
772 struct MUIP_ConnectParent
*msg
)
774 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
776 /* Objects only have parents if they are inside a group or family object;
777 ** no idea why MUIA_Parent belongs to the notify class then
779 /* data->mnd_ParentObject = msg->parent;*/
780 muiGlobalInfo(obj
) = muiGlobalInfo(msg
->parent
);
784 /**************************************************************************
785 MUIM_DisconnectParent
786 **************************************************************************/
787 IPTR
Notify__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
788 struct MUIP_DisconnectParent
*msg
)
790 //struct MUI_NotifyData *data = INST_DATA(cl, obj);
791 /* data->mnd_ParentObject = NULL;*/
793 /* Some apps (YAM) seem to access this even after disconnection */
794 muiGlobalInfo(obj
) = NULL
;
799 /**************************************************************************
801 **************************************************************************/
802 IPTR
Notify__MUIM_GetConfigItem(struct IClass
*cl
, Object
*obj
,
803 struct MUIP_GetConfigItem
*msg
)
806 DoMethod(muiGlobalInfo(obj
)->mgi_Configdata
, MUIM_Dataspace_Find
,
811 *msg
->storage
= found
;
821 BOOPSI_DISPATCHER(IPTR
, Notify_Dispatcher
, cl
, obj
, msg
)
823 switch (msg
->MethodID
)
826 return Notify__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
828 return Notify__OM_DISPOSE(cl
, obj
, msg
);
830 return Notify__OM_SET(cl
, obj
, (struct opSet
*)msg
);
832 return Notify__OM_GET(cl
, obj
, (struct opGet
*)msg
);
834 return Notify__MUIM_CallHook(cl
, obj
, (APTR
) msg
);
838 return Notify__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
840 return Notify__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
843 case MUIM_KillNotify
:
844 return Notify__MUIM_KillNotify(cl
, obj
, (APTR
) msg
);
845 case MUIM_KillNotifyObj
:
846 return Notify__MUIM_KillNotifyObj(cl
, obj
, (APTR
) msg
);
848 return Notify__MUIM_MultiSet(cl
, obj
, (APTR
) msg
);
849 case MUIM_NoNotifySet
:
850 return Notify__MUIM_NoNotifySet(cl
, obj
, (APTR
) msg
);
852 return Notify__MUIM_Notify(cl
, obj
, (APTR
) msg
);
854 return Notify__MUIM_Set(cl
, obj
, (APTR
) msg
);
855 case MUIM_SetAsString
:
856 return Notify__MUIM_SetAsString(cl
, obj
, (APTR
) msg
);
858 return Notify__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
859 case MUIM_SetUDataOnce
:
860 return Notify__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
861 /* use Notify_SetUData */
863 return Notify__MUIM_WriteLong(cl
, obj
, (APTR
) msg
);
864 case MUIM_WriteString
:
865 return Notify__MUIM_WriteString(cl
, obj
, (APTR
) msg
);
866 case MUIM_ConnectParent
:
867 return Notify__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
868 case MUIM_DisconnectParent
:
869 return Notify__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
870 case MUIM_GetConfigItem
:
871 return Notify__MUIM_GetConfigItem(cl
, obj
, (APTR
) msg
);
874 return DoSuperMethodA(cl
, obj
, msg
);
876 BOOPSI_DISPATCHER_END
881 const struct __MUIBuiltinClass _MUI_Notify_desc
=
883 MUIC_Notify
, /* Class name */
884 ROOTCLASS
, /* super class name */
885 sizeof(struct MUI_NotifyData
), /* size of class's own data */
886 (void *) Notify_Dispatcher
/* class dispatcher */