1 /* $Id: vibmouse.c,v 6.4 2001/03/28 01:40:48 juran Exp $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information (NCBI)
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government do not place any restriction on its use or reproduction.
13 * We would, however, appreciate having the NCBI and the author cited in
14 * any work or product based on this material
15 *
16 * Although all reasonable efforts have been taken to ensure the accuracy
17 * and reliability of the software and data, the NLM and the U.S.
18 * Government do not and cannot warrant the performance or results that
19 * may be obtained by using this software or data. The NLM and the U.S.
20 * Government disclaim all warranties, express or implied, including
21 * warranties of performance, merchantability or fitness for any particular
22 * purpose.
23 *
24 * ===========================================================================
25 *
26 * Author: Denis Vakatov
27 *
28 * File Description:
29 * user interface to manage mouse-event callbacks
30 * program interface to describe groups of mouse-event callbacks
31 *
32 * ===========================================================================
33 * $Log: vibmouse.c,v $
34 * Revision 6.4 2001/03/28 01:40:48 juran
35 * "for (...) { continue; }", squelch warning
36 *
37 * Revision 6.3 1999/04/06 14:23:25 lewisg
38 * add opengl replacement for viewer3d
39 *
40 * Revision 6.2 1998/07/02 18:24:34 vakatov
41 * Cleaned the code & made it pass through the C++ compilation
42 *
43 * Revision 6.1 1997/11/26 21:30:31 vakatov
44 * Fixed errors and warnings issued by C and C++ (GNU and Sun) compilers
45 *
46 * Revision 6.0 1997/08/25 18:57:21 madden
47 * Revision changed to 6.0
48 *
49 * Revision 1.3 1997/05/06 16:27:07 vakatov
50 * Ignore the MA_Drag and MA_Release events not preceded by MA_Press
51 *
52 * Revision 1.2 1997/03/21 16:15:12 vakatov
53 * Removed #<ni_list.h> -- as the list stuff has been moved to "ncbimisk.[ch]"
54 *
55 * Revision 1.1 1997/03/20 16:23:26 vakatov
56 * Initial revision
57 *
58 *
59 * ==========================================================================
60 */
61
62 #ifdef VAR_ARGS
63 #include <varargs.h>
64 #else
65 #include <stdarg.h>
66 #endif
67 #include <vibrant.h> /* move out of header. lyg */
68 #include <vibmouse.h>
69
70
71 #define BAD ASSERT(FALSE)
72
73
74 /*****************************************************************************
75 * Internal Data and Type Definitions
76 *****************************************************************************/
77
78 static const Char *MA_name[MK_Default][MA_Init] =
79 {
80 {
81 "Click",
82 "Press",
83 "DoubleClick",
84 "Hold",
85 "Drag",
86 "Release",
87 "Cancel"
88 },
89
90 {
91 "Shift-Click",
92 "Shift-Press",
93 "Shift-DoubleClick",
94 "Shift-Hold",
95 "Shift-Drag",
96 "Shift-Release",
97 "Shift-Cancel"
98 },
99
100 {
101 "Ctrl-Click",
102 "Ctrl-Press",
103 "Ctrl-DoubleClick",
104 "Ctrl-Hold",
105 "Ctrl-Drag",
106 "Ctrl-Release",
107 "Ctrl-Cancel"
108 }
109 };
110
111
112 typedef struct _MAction
113 {
114 enumMKey mod_key;
115 enumMAction type;
116 MA_Func func;
117 VoidPtr data;
118 CharPtr name;
119 IteM item;
120 MAPtr ma;
121 }
122 MAction;
123
124 typedef struct _MA_Group
125 {
126 CharPtr name; /* the group name as it appears in the group menu */
127 MActionPtr init;
128 MActionPtr done;
129 MActionPtr action[MK_Default][MA_Init];
130 Boolean only [MK_Default][MA_Init]; /* TRUE if cannot be replaced by a
131 "foreign" callback while the group is active */
132 IteM item;
133 MAPtr ma;
134 }
135 MA_Group;
136
137
138
139 typedef struct _MA
140 {
141 /* interface */
142 MenU group_menu;
143 MenU action_menu;
144 MenU menu[MK_Default][MA_Init];
145
146 /* all registered actions and groups */
147 NodePtr actions;
148 NodePtr groups;
149
150 /* presently active groups and actions */
151 NodePtr active_groups;
152 MActionPtr action[MK_Default][MA_Init];
153 Boolean only [MK_Default][MA_Init];
154
155 /* presently active(snapshot during the last "Press" action) modifier */
156 enumMKey mod_key;
157
158 /* type and position of the most recent mouse action(but MA_Hold) */
159 enumMAction last_type;
160 PoinT last_pos;
161
162 /* auxiliary temporary store area shared between the action callbacks */
163 MA_Trace trace;
164
165 /* presently linked panel(slate) */
166 PaneL panel;
167
168 /* user-specified pointer to an extra data */
169 VoidPtr extra;
170 }
171 MA;
172
173
174
175 /*****************************************************************************
176 * Internal (Static) Functions
177 *****************************************************************************/
178
179 /* In the "action->ma", find the active group containing
180 * the "only" action of type "action->mod_key/type"
181 */
GroupOfOnlyAction(MActionPtr action)182 static MA_GroupPtr GroupOfOnlyAction(MActionPtr action)
183 {
184 MAPtr ma = action->ma;
185 NodePtr node = ma->active_groups;
186
187 ASSERT ( ma->only[action->mod_key][action->type] );
188
189 while ( node )
190 {
191 MA_GroupPtr mag = (MA_GroupPtr)node->elem;
192 if ( mag->only[action->mod_key][action->type] )
193 return mag;
194
195 node = ListGetNext( node );
196 }
197
198 BAD;
199 return NULL;
200 }
201
202
203 /* Set current action according to the submenu item click
204 */
MA_ActionItemCB(IteM item)205 static void MA_ActionItemCB(IteM item)
206 {
207 MActionPtr action = (MActionPtr)GetObjectExtra( item );
208
209 VERIFY ( MA_SetAction(action, TRUE) );
210 }
211
212
213 /* Add the action item to the relevant submenu
214 */
MA_ShowAction(MActionPtr action)215 static Boolean MA_ShowAction(MActionPtr action)
216 {
217 MAPtr ma;
218 if (action == NULL || action->name == NULL ||
219 (ma = action->ma) == NULL || ma->action_menu == NULL ||
220 !ma->action_menu || !ma->menu[action->mod_key][action->type])
221 return FALSE;
222
223 if (action->item != NULL)
224 return TRUE;
225
226 action->item = CommandItem(ma->menu[action->mod_key][action->type],
227 action->name, MA_ActionItemCB);
228 if ( !action->item )
229 return FALSE;
230
231 SetObjectExtra(action->item, action, NULL);
232 return TRUE;
233 }
234
235
236 /* Activate/deactivate the mouse callback group "group"
237 */
MA_GroupItemCB(IteM item)238 static void MA_GroupItemCB(IteM item)
239 {
240 MA_GroupPtr group = (MA_GroupPtr)GetObjectExtra( item );
241
242 if ( GetStatus( item ) )
243 VERIFY ( MA_SetGroup( group ) );
244 else
245 VERIFY ( MA_UnsetGroup( group ) );
246 }
247
248
249 /* Add the "group"'s name to the list of mouse callback groups
250 */
MA_ShowGroup(MA_GroupPtr group)251 static Boolean MA_ShowGroup(MA_GroupPtr group)
252 {
253 if (group != NULL &&
254 group->name != NULL &&
255 group->ma != NULL &&
256 group->ma->group_menu != NULL &&
257 (group->item = StatusItem(group->ma->group_menu, group->name,
258 MA_GroupItemCB)) != NULL)
259 {
260 SetObjectExtra(group->item, group, NULL);
261 return TRUE;
262 }
263
264 return FALSE;
265 }
266
267
268 /* Measure distance between the two points
269 */
PointDist(PoinT p1,PoinT p2)270 static double PointDist(PoinT p1, PoinT p2)
271 {
272 return sqrt( (double)((p2.x - p1.x) * (p2.x - p1.x) +
273 (p2.y - p1.y) * (p2.y - p1.y)));
274 }
275
276 /* The Panel-to-MA callback dispatcher
277 */
MA_Execute(MAPtr ma,PoinT pt,enumMAction type)278 static void MA_Execute(MAPtr ma, PoinT pt, enumMAction type)
279 {
280 ASSERT ( 0 <= type && type < MA_Init );
281
282 /* set the key status of the action in progress */
283 if (type == MA_Press || type == MA_DClick || ma->mod_key == MK_Default)
284 ma->mod_key = Nlm_shftKey ? MK_Shift :
285 Nlm_ctrlKey ? MK_Ctrl :
286 MK_Normal;
287
288 /* Refuse MA_Drag and MA_Release not preceded by MA_Press */
289 if ((type == MA_Drag || type == MA_Release) &&
290 ma->last_type != MA_Press && ma->last_type != MA_Drag)
291 return;
292
293 /* MA_Click vs. MA_Drag|MA_Release */
294 if (ma->last_type == MA_Press)
295 {
296 double CLICK_RADIUS = (double)8;
297 switch ( type )
298 {
299 case MA_Drag:
300 if (PointDist(pt, ma->last_pos) <= CLICK_RADIUS)
301 return;
302 break;
303
304 case MA_Release:
305 if (PointDist(pt, ma->last_pos) <= CLICK_RADIUS)
306 type = MA_Click;
307 break;
308
309 default:
310 break;
311 }
312 }
313
314 {{ /* call the relevant user-specified action callback, if any */
315 MActionPtr action = ma->action[ma->mod_key][type];
316 if ( action )
317 {
318 ASSERT ( action->ma == ma );
319 ASSERT ( action->type == type );
320 (*action->func)(ma, &ma->trace, pt, action->data);
321 }
322 }}
323
324 if (type == MA_Release || type == MA_Cancel || type == MA_DClick)
325 ma->mod_key = MK_Default; /* no action in progress */
326
327 if (type != MA_Hold)
328 {
329 ma->last_type = type;
330 ma->last_pos = pt;
331 }
332 }
333
MA_ExecuteP(PaneL panel,PoinT pt,enumMAction type)334 static void MA_ExecuteP(PaneL panel, PoinT pt, enumMAction type)
335 {
336 MAPtr ma = NULL;
337 GetPanelExtra(panel, &ma);
338 MA_Execute(ma, pt, type);
339 }
340
341
342 /* MA wrappers of the panel callbacks
343 */
MA_ClickCB(PaneL panel,PoinT pt)344 static void MA_ClickCB(PaneL panel, PoinT pt)
345 {
346 if ( Nlm_dblClick )
347 MA_ExecuteP(panel, pt, MA_DClick);
348 else
349 MA_ExecuteP(panel, pt, MA_Press);
350 }
351
352
MA_HoldCB(PaneL panel,PoinT pt)353 static void MA_HoldCB(PaneL panel, PoinT pt)
354 {
355 MA_ExecuteP(panel, pt, MA_Hold);
356 }
357
358
MA_DragCB(PaneL panel,PoinT pt)359 static void MA_DragCB(PaneL panel, PoinT pt)
360 {
361 MA_ExecuteP(panel, pt, MA_Drag);
362 }
363
364
MA_ReleaseCB(PaneL panel,PoinT pt)365 static void MA_ReleaseCB(PaneL panel, PoinT pt)
366 {
367 MA_ExecuteP(panel, pt, MA_Release);
368 }
369
370
371
372 /*****************************************************************************
373 * External Functions
374 *****************************************************************************/
375
376 /* Creation functions
377 */
MA_Create(MenU group_menu,MenU action_menu)378 extern MAPtr MA_Create(MenU group_menu, MenU action_menu)
379 {
380 MAPtr ma = (MAPtr)MemNew( sizeof(MA) );
381 if ( !ma ) {
382 BAD;
383 return NULL;
384 }
385
386 ma->group_menu = group_menu;
387 ma->action_menu = action_menu;
388
389 MA_Reset( ma );
390 return ma;
391 }
392
393
394 /* DUMMY MA callback function
395 */
DoNothingMA(MAPtr ma,MA_TracePtr trace,PoinT point,VoidPtr extra)396 extern void DoNothingMA(MAPtr ma, MA_TracePtr trace, PoinT point,
397 VoidPtr extra)
398 {
399 /* do nothing */
400 }
401
402
MA_AddAction(MAPtr ma,enumMKey mod_key,enumMAction type,MA_Func func,VoidPtr data,const Char PNTR name)403 extern MActionPtr MA_AddAction(MAPtr ma,
404 enumMKey mod_key,
405 enumMAction type,
406 MA_Func func,
407 VoidPtr data,
408 const Char PNTR name)
409 {
410 MActionPtr new_action;
411 NodePtr new_node;
412
413 if (ma == NULL || mod_key == MK_Default || type == MA_Default ||
414 func == NULL)
415 {
416 BAD;
417 return NULL;
418 }
419 ASSERT ( name == NULL || *name != '\0' );
420
421 new_action = (MActionPtr) MemNew( sizeof(MAction) );
422 new_node = ListInsertPrev(new_action, ma->actions);
423 if (new_node == NULL)
424 {
425 BAD;
426 MemFree( new_action );
427 return NULL;
428 }
429 if (ma->actions == NULL)
430 ma->actions = new_node;
431
432 new_action->mod_key = mod_key;
433 new_action->type = type;
434 new_action->func = func;
435 new_action->data = data;
436 new_action->name = StringSave( name );
437 new_action->ma = ma;
438 MA_ShowAction( new_action );
439
440 return new_action;
441 }
442
443
MA_SetAction(MActionPtr action,Boolean can_unset_group)444 extern Boolean MA_SetAction(MActionPtr action, Boolean can_unset_group)
445 {
446 MAPtr ma = action->ma;
447 MActionPtr *ma_action = &ma->action[action->mod_key][action->type];
448
449 if ( ma->only[action->mod_key][action->type] )
450 {
451 if ( can_unset_group )
452 {
453 VERIFY ( MA_UnsetGroup( GroupOfOnlyAction(action) ) );
454 ASSERT ( !ma->only[action->mod_key][action->type] );
455 }
456 else
457 return FALSE;
458 }
459
460 if (*ma_action && (*ma_action)->item)
461 Enable( (*ma_action)->item );
462 if (action && action->item)
463 Disable( action->item );
464
465 *ma_action = action;
466 return TRUE;
467 }
468
469
MA_UnsetAll(MAPtr ma)470 extern Boolean MA_UnsetAll(MAPtr ma)
471 {
472 while ( ma->active_groups )
473 if ( !MA_UnsetGroup( (MA_GroupPtr)ma->active_groups->elem ) )
474 {
475 BAD;
476 return FALSE;
477 }
478
479 {{
480 int i,j;
481 for (i = 0; i < MK_Default; i++)
482 for (j = 0; j < MA_Init; j++)
483 {
484 ASSERT ( !ma->only[i][j] );
485 if ( ma->action[i][j] )
486 {
487 if ( ma->action[i][j]->item )
488 Enable( ma->action[i][j]->item );
489 ma->action[i][j] = NULL;
490 }
491 }
492 }}
493
494 return TRUE;
495 }
496
497
498 #ifdef VAR_ARGS
499 extern MA_GroupPtr MA_AddGroup(ma, name, action, only, va_alist)
500 MAPtr ma;
501 const Char PNTR name;
502 MActionPtr action;
503 long only;
504 va_dcl
505 #else
506 extern MA_GroupPtr MA_AddGroup(MAPtr ma, const Char PNTR name,
507 MActionPtr action, long only,
508 /* and more pairs: <action>, <only>; */
509 /* then, the last arg. must be NULL! */
510 ...)
511 #endif
512 {
513 MA_GroupPtr new_group;
514
515 if (ma == NULL || name == NULL || action == NULL)
516 {
517 BAD;
518 return NULL;
519 }
520
521 new_group = (MA_GroupPtr)MemNew( sizeof(MA_Group) );
522
523 {{ /* Extract the group actions from the list of arguments */
524 va_list args;
525 #ifdef VAR_ARGS
526 va_start(args);
527 #else
528 va_start(args, only);
529 #endif
530 for ( ; action != NULL;
531 action = va_arg(args, MActionPtr),
532 only = va_arg(args, long))
533 {
534 MActionPtr *dest_action = NULL;
535
536 switch ( action->type )
537 {
538 case MA_Init:
539 dest_action = &new_group->init;
540 break;
541
542 case MA_Done:
543 dest_action = &new_group->done;
544 break;
545
546 default:
547 dest_action = &new_group->action[action->mod_key][action->type];
548 new_group->only[action->mod_key][action->type] =
549 (Boolean)(only == MA_ONLY);
550 break;
551 }
552
553 if (*dest_action != NULL)
554 {
555 BAD;
556 MemFree( new_group );
557 return NULL;
558 }
559
560 *dest_action = action;
561 }
562 va_end(args);
563 }}
564
565 {{ /* Insert the new group to the end of the list of groups */
566 NodePtr new_node = ListInsertPrev(new_group, ma->groups);
567 if (new_node == NULL)
568 {
569 BAD;
570 MemFree( new_group );
571 return NULL;
572 }
573 if (ma->groups == NULL)
574 ma->groups = new_node;
575 }}
576
577 new_group->name = StringSave( name );
578 new_group->ma = ma;
579 MA_ShowGroup( new_group );
580
581 return new_group;
582 }
583
584
MA_UnsetGroup(MA_GroupPtr group)585 extern Boolean MA_UnsetGroup(MA_GroupPtr group)
586 {
587 MAPtr ma = group->ma;
588
589 {{ /* find and exclude the "group" from the list of active groups */
590 NodePtr node;
591 for (node = ma->active_groups;
592 node && node->elem != group;
593 node = ListGetNext( node ))
594 {
595 continue;
596 }
597
598 if ( !node )
599 return FALSE;
600
601 if (node == ma->active_groups)
602 ma->active_groups = ListDelete( node );
603 else
604 ListDelete( node );
605 }}
606
607 {{ /* unset the "group"'s "only" actions */
608 int i, j;
609 for (i = 0; i < MK_Default; i++)
610 for (j = 0; j < MA_Init; j++)
611 if ( group->only[i][j] )
612 {
613 ASSERT ( ma->action[i][j] == group->action[i][j] );
614 ASSERT ( ma->only [i][j] );
615 if ( ma->menu[i][j] )
616 Enable( ma->menu[i][j] );
617 ma->action[i][j] = NULL;
618 ma->only [i][j] = FALSE;
619 }
620 }}
621
622 /* call the group's "done" method(i.e. the user-defined group destructor);
623 always call the "cancel" method before -- if there is a mouse
624 action "in progress" */
625 if (ma->mod_key != MK_Default)
626 MA_Execute(ma, ma->trace.end, MA_Cancel);
627
628 if (group->item != NULL)
629 SetStatus(group->item, FALSE);
630
631 if ( group->done )
632 (*group->done->func)(ma, &ma->trace, ma->trace.end, group->done->data);
633
634 return TRUE;
635 }
636
637
MA_SetGroup(MA_GroupPtr group)638 extern Boolean MA_SetGroup(MA_GroupPtr group)
639 {
640 int i, j;
641 MAPtr ma = group->ma;
642
643 {{ /* check for the "only"-actions double-crossing; in that case
644 * unset all "only" actions of the old group(i.e. unset the group) */
645 for (i = 0; i < MK_Default; i++)
646 for (j = 0; j < MA_Init; j++)
647 if (ma->only[i][j] && group->only[i][j] &&
648 !MA_UnsetGroup( GroupOfOnlyAction(group->action[i][j]) ))
649 {
650 BAD;
651 return FALSE;
652 }
653 }}
654
655 /* replace all old non-"only" actions with these from the "group" */
656 for (i = 0; i < MK_Default; i++)
657 for (j = 0; j < MA_Init; j++)
658 {
659 if (group->action[i][j] != NULL)
660 {
661 ASSERT ( !group->only[i][j] || !ma->only[i][j]);
662 if ( ma->only[i][j] )
663 {
664 ASSERT ( !group->only[i][j] );
665 }
666 else
667 {
668 if (ma->action[i][j] && ma->action[i][j]->item)
669 Enable( ma->action[i][j]->item );
670 ma->action[i][j] = group->action[i][j];
671 ma->only [i][j] = group->only [i][j];
672 }
673 }
674
675 if ( ma->only[i][j] )
676 Disable( ma->menu[i][j] );
677 }
678
679 ListConnectRing( ma->active_groups );
680 ma->active_groups = ListInsertPrev(group, ma->active_groups);
681 ListBreakRing( ma->active_groups );
682
683 if (group->item != NULL)
684 SetStatus(group->item, TRUE);
685
686 /* call the group "init" method (user-defined group constructor) */
687 ma->trace.end.x = ma->trace.end.y = 0;
688 ma->trace.start = ma->trace.end;
689 if ( group->init )
690 (*group->init->func)(ma, &ma->trace, ma->trace.end, group->init->data);
691
692 return TRUE;
693 }
694
695
MA_LinkPanel(MAPtr ma,PaneL panel)696 extern Boolean MA_LinkPanel(MAPtr ma, PaneL panel)
697 {
698 if (ma == NULL || panel == NULL)
699 return FALSE;
700
701 SetPanelClick(panel, MA_ClickCB, MA_DragCB, MA_HoldCB, MA_ReleaseCB);
702 SetPanelExtra(panel, &ma);
703 ma->panel = panel;
704 return TRUE;
705 }
706
707
MA_GetPanel(MAPtr ma)708 extern PaneL MA_GetPanel(MAPtr ma)
709 {
710 return (PaneL) (ma ? ma->panel : NULL);
711 }
712
713
MA_UnlinkPanel(MAPtr ma)714 extern void MA_UnlinkPanel(MAPtr ma)
715 {
716 MAPtr ma_NULL = NULL;
717
718 if (ma == NULL || ma->panel == NULL)
719 return;
720
721 SetPanelClick(ma->panel, NULL, NULL, NULL, NULL);
722 SetPanelExtra(ma->panel, &ma_NULL);
723 ma->panel = NULL;
724 }
725
726
MA_SetVisible(MAPtr ma,Boolean visibility)727 extern Boolean MA_SetVisible(MAPtr ma, Boolean visibility)
728 {
729 if (!ma || (!ma->group_menu && !ma->action_menu))
730 return FALSE;
731
732 if ( visibility )
733 {
734 Show( ma->group_menu );
735 Show( ma->action_menu );
736 }
737 else
738 {
739 Hide( ma->group_menu );
740 Hide( ma->action_menu );
741 }
742
743 return TRUE;
744 }
745
746
MA_GetVisible(MAPtr ma)747 extern Boolean MA_GetVisible(MAPtr ma)
748 {
749 return (Boolean)
750 (ma &&
751 ((ma->group_menu && Visible(ma->group_menu )) ||
752 (ma->action_menu && Visible(ma->action_menu))));
753 }
754
755
MA_SetExtra(MAPtr ma,VoidPtr extra)756 extern void MA_SetExtra(MAPtr ma, VoidPtr extra)
757 {
758 ma->extra = extra;
759 }
760
761
MA_GetExtra(MAPtr ma)762 extern VoidPtr MA_GetExtra(MAPtr ma)
763 {
764 return (ma ? ma->extra : NULL);
765 }
766
767
MA_Reset(MAPtr ma)768 extern void MA_Reset(MAPtr ma)
769 {
770 int i, j;
771
772 /* unset all presently active groups */
773 while ( ma->active_groups )
774 VERIFY ( MA_UnsetGroup( (MA_GroupPtr)ma->active_groups->elem ) );
775
776 /* Unlink panel */
777 MA_UnlinkPanel( ma );
778
779 /* Reset menu-based interface */
780 if ( ma->action_menu )
781 {
782 Reset( ma->action_menu );
783
784 for (i = 0; i < MK_Default; i++)
785 for (j = 0; j < MA_Init; j++)
786 ma->menu[i][j] = SubMenu(ma->action_menu, (CharPtr)MA_name[i][j]);
787 }
788
789 if ( ma->group_menu )
790 {
791 if (ma->group_menu == ma->action_menu)
792 SeparatorItem( ma->action_menu );
793 else
794 Reset( ma->group_menu );
795 }
796
797 /* Reset internal data */
798 MA_SetExtra(ma, NULL);
799
800 while (ma->groups != NULL)
801 {
802 MemFree( ((MA_GroupPtr)ma->groups->elem)->name );
803 MemFree( ma->groups->elem );
804 ma->groups = ListDelete( ma->groups );
805 }
806
807 for (i = 0; i < MK_Default; i++)
808 for (j = 0; j < MA_Init; j++)
809 {
810 ma->action[i][j] = NULL;
811 ma->only [i][j] = FALSE;
812 }
813
814 while ( ma->actions )
815 {
816 MemFree( ((MActionPtr)ma->actions->elem)->name );
817 MemFree( ma->actions->elem );
818 ma->actions = ListDelete( ma->actions );
819 }
820
821 ma->mod_key = MK_Default;
822 ma->last_type = MA_Default;
823 }
824
825
MA_Destroy(MAPtr ma)826 extern void MA_Destroy(MAPtr ma)
827 {
828 MA_Reset( ma );
829 MemFree( ma );
830 }
831
832
833 /* EOF ($RCSfile: vibmouse.c,v $) */
834
835