Initial revision
[ssr] / StraySrc / Libraries / Steel / c / menu
1 /*
2 * menu
3 *
4 * A working menu system
5 *
6 * © 1993-1998 Straylight
7 */
8
9 /*----- Licensing note ----------------------------------------------------*
10 *
11 * This file is part of Straylight's Steel library.
12 *
13 * Steel is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * Steel is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with Steel. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */
27
28 #include "menu.h"
29 #include "mem.h"
30 #include "wimp.h"
31 #include "werr.h"
32 #include "msgs.h"
33 #include "resspr.h"
34 #include "event.h"
35 #include "wimpt.h"
36 #include "os.h"
37 #include "swis.h"
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41
42 #include "dll.h"
43
44 #ifndef _dll_NODLL
45 extern void _dllEntry(menu__menuproc)(void *handle,char hits[]);
46 extern menu _dllEntry(menu__menumaker)(void *handle);
47 #endif
48
49 typedef struct menu__menustr
50 {
51 int items;
52 int maxlen;
53 BOOL submenu;
54 char *indirect;
55 int indbytes;
56 wimp_menustr *syshandle; /* This points to the actual structure, */
57 /* and 1 word ahead of a back-pointer to */
58 /* this structure */
59 }
60 menu__menustr;
61
62 typedef struct
63 {
64 event_menu_maker m;
65 menu_selectProc sel;
66 menu_helpProc help;
67 void *handle;
68 }
69 menu__handlerstr;
70
71 static menu__handlerstr menu__instant;
72
73 /*---------------------------------------------------------------------------
74
75 The syntax of menu strings is an extension of the system used by the
76 RISC_OSlib menu segment:
77
78 menu_description ::= <flags> <item> <sep> { <flags> <item> <sep> }
79 flags ::= '!' | '~' | '>' | ' ' | '+'
80 sep ::= ',' | '|'
81 item ::= <a bunch of other characters>
82
83 flags have meanings as follows:
84
85 ' ' has no effect
86 '~' shades the item
87 '>' item has a menu dbox attached
88 '!' item is ticked
89 '+' open submenu even if item is shaded
90
91 ---------------------------------------------------------------------------*/
92
93 /*
94 * static BOOL menu__ROparse(menu m,char **p,wimp_menuitem *item)
95 *
96 * Use
97 * Reads the next menu entry for a RISC_OSlib-style menu definition.
98 *
99 * Parameters
100 * menu m == the menu structure that this is being added to.
101 * char **p == pass-by-reference pointer to next item to parse. This is
102 * updated to point to the next item after successful termination, to the
103 * point where an error was discovered, or to zero to indicate successful
104 * completion of the entire menu.
105 * wimp_menuitem *item == pointer to structure for the routine to deposit
106 * its output.
107 *
108 * Returns
109 * TRUE for successful termination, or FALSE to indicate an error.
110 */
111
112 static BOOL menu__ROparse(menu m,char **p,wimp_menuitem *item)
113 {
114 char *ind;
115 int len=0;
116 int diff;
117 wimp_menuflags f=0;
118 wimp_iconflags i=
119 (
120 (7*wimp_IFORECOL) |
121 wimp_ITEXT |
122 wimp_IVCENTRE |
123 wimp_IFILLED
124 );
125 BOOL done=FALSE;
126 wimp_menuitem *itm;
127 char *eptr;
128 item->submenu=(wimp_menustr *)-1;
129 while (!done)
130 {
131 switch (**p)
132 {
133 case '!':
134 f|=wimp_MTICK;
135 (*p)++;
136 break;
137 case ' ':
138 (*p)++;
139 break;
140 case '>':
141 f|=wimp_MSUBLINKMSG;
142 item->submenu=(wimp_menustr *)1;
143 (*p)++;
144 break;
145 case '~':
146 i|=wimp_INOSELECT;
147 (*p)++;
148 break;
149 case '+':
150 f|=wimp_MOPENSUB;
151 (*p)++;
152 break;
153 default:
154 done=TRUE;
155 break;
156 }
157 }
158 done=FALSE;
159 for (eptr=*p;*eptr!=0 && *eptr!='|' && *eptr!=',';eptr++,len++)
160 /* blank */;
161 if (len>12)
162 {
163 i|=wimp_INDIRECT;
164 if (ind=mem_reAlloc(m->indirect,m->indbytes+len+1),!ind)
165 /* This will allocate memory if there isn't */
166 /* any indirected workspace yet */
167 {
168 werr
169 (
170 FALSE,
171 msgs_lookup("menuNEM:Not enough memory to construct menu.")
172 );
173 return (FALSE);
174 }
175 itm=(wimp_menuitem *)(m->syshandle+1);
176 while (itm!=item)
177 {
178 if (itm->iconflags & wimp_INDIRECT)
179 {
180 diff=itm->data.indirecttext.buffer-m->indirect;
181 if (diff<m->indbytes && diff>=0)
182 itm->data.indirecttext.buffer=ind+diff;
183 }
184 itm++;
185 }
186 m->indirect=ind;
187 ind+=m->indbytes;
188 m->indbytes+=len+1;
189 item->data.indirecttext.buffer=ind;
190 item->data.indirecttext.validstring=(char *)-1;
191 item->data.indirecttext.bufflen=len+1;
192 }
193 else
194 ind=item->data.text;
195 while (**p!=0 && **p!='|' && **p!=',')
196 *(ind++)=*((*p)++);
197 *(ind++)=0;
198 if (**p=='|')
199 f|=wimp_MSEPARATE;
200 if (!**p)
201 *p=0;
202 else
203 (*p)++;
204 item->flags=f;
205 item->iconflags=i;
206 if (len>m->maxlen)
207 m->maxlen=len;
208 m->items+=1;
209 return (TRUE);
210 }
211
212 /*
213 * int menu__ROitemCount(char *string)
214 *
215 * Use
216 * Counts the number of menu items specified in a RISC_OSlib style menu
217 * string.
218 *
219 * Parameters
220 * char *s == pointer to the menu string
221 *
222 * Returns
223 * The number of items specified
224 */
225
226 static int menu__ROitemCount(char *s)
227 {
228 int count=1;
229 if (*s=='|')
230 s++;
231 while (*s)
232 {
233 switch (*s)
234 {
235 case '|':
236 case ',':
237 count++;
238 break;
239 }
240 s++;
241 }
242 return (count);
243 }
244
245 /*
246 * menu menu_new(char *title,char *items)
247 *
248 * Use
249 * Creates a menu as per the old RISC_OSlib system.
250 *
251 * Parameters
252 * char *title == the menu title (truncated to 12 chars if necessary)
253 * char *items == the menu item text. Data is indirected where required.
254 *
255 * Returns
256 * A pointer to the menu if successful, or a NULL pointer if not.
257 */
258
259 menu menu_new(char *title,char *items)
260 {
261 menu m;
262 int i;
263 menu *t;
264 wimp_menuitem *itm;
265 int ino=menu__ROitemCount(items);
266 if (m=mem_alloc(sizeof(menu__menustr)),!m)
267 {
268 werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
269 return (0);
270 }
271 if (t=mem_alloc
272 (
273 sizeof(menu)+sizeof(wimp_menuhdr)+ino*sizeof(wimp_menuitem)+4
274 ),
275 !t)
276 {
277 mem_free(m);
278 werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
279 return (0);
280 }
281 m->syshandle=(wimp_menustr *)(t+1);
282 m->indirect=0;
283 m->indbytes=0;
284 m->submenu=FALSE;
285 m->items=0;
286 m->maxlen=strlen(title);
287 strcpy(m->syshandle->hdr.title,title);
288 m->syshandle->hdr.tit_fcol=7;
289 m->syshandle->hdr.tit_bcol=2;
290 m->syshandle->hdr.work_fcol=7;
291 m->syshandle->hdr.work_bcol=0;
292 m->syshandle->hdr.height=44;
293 m->syshandle->hdr.gap=0;
294 *t=m;
295 itm=((wimp_menuitem *)(m->syshandle+1))-1;
296 for (i=0;i<ino;i++)
297 {
298 itm++;
299 if (!items)
300 werr(TRUE,msgs_lookup("menuICOU:(menu_new): Menu item undercount."));
301 if (!menu__ROparse(m,&items,itm))
302 {
303 if (m->indirect)
304 mem_free(m->indirect);
305 mem_free(m);
306 mem_free(t);
307 return (0);
308 }
309 }
310 if (items)
311 werr(TRUE,msgs_lookup("menuICOO:(menu_new): Menu item overcount."));
312 if (ino!=m->items)
313 werr(TRUE,msgs_lookup("menuIMSC:(menu_new): Menu item count mismatch."));
314 itm->flags|=wimp_MLAST;
315 m->syshandle->hdr.width=16*m->maxlen+16;
316 return (m);
317 }
318
319 /*
320 * wimp_menuitem *menu__itmPointer(menu m,int i)
321 *
322 * Use
323 * Returns a pointer to the specified menu item. Items are numbered
324 * starting from 1.
325 *
326 * Parameters
327 * menu m == the menu to look up
328 * int i == the item number to find
329 *
330 * Returns
331 * A pointer to the specified menu item
332 */
333
334 static wimp_menuitem *menu__itmPointer(menu m,int i)
335 {
336 return ((wimp_menuitem *)(m->syshandle+1)+(i-1));
337 }
338
339 /*
340 * void menu_submenu(menu main,int item,menu submenu)
341 *
342 * Use
343 * Attaches a menu as a submenu, but it will put in a submenu warning flag,
344 * so the user-friendly too-many-windows messages come up right!
345 *
346 * Parameters
347 * menu main == the main menu
348 * int item == the menu item number
349 * menu submenu == the submenu
350 */
351
352 void menu_submenu(menu main,int item,menu submenu)
353 {
354 wimp_menuitem *i=menu__itmPointer(main,item);
355 if (submenu)
356 {
357 i->flags|=wimp_MSUBLINKMSG;
358 i->submenu=(wimp_menuptr)(submenu->syshandle);
359 submenu->submenu=TRUE;
360 }
361 else
362 {
363 i->flags&=~wimp_MSUBLINKMSG;
364 i->submenu=(wimp_menuptr)-1;
365 }
366 }
367
368 /*
369 * void menu_dispose(menu *m,BOOL recurse)
370 *
371 * Use
372 * Kill off a menu or menu tree. Won't work on submenus.
373 *
374 * Parameters
375 * menu *m == pointer to menu to Domestos-ise.
376 * BOOL recurse == do we want to kill its submenus too?
377 */
378
379 void menu_dispose(menu *m,BOOL recurse)
380 {
381 int i;
382 wimp_menuitem *itm=(wimp_menuitem *)((*m)->syshandle+1);
383 menu s;
384 if (recurse)
385 {
386 for (i=0;i<(*m)->items;i++);
387 {
388 if ((int)(itm->submenu)>=0x8000)
389 {
390 s=*((menu *)itm->submenu-1);
391 menu_dispose(&s,TRUE);
392 }
393 itm++;
394 }
395 }
396 if ((*m)->indirect)
397 mem_free((*m)->indirect);
398 mem_free(*m);
399 }
400
401 /*
402 * wimp_menustr *menu_syshandle(menu m)
403 *
404 * Use
405 * Returns pointer to actual menu structure.
406 *
407 * Parameters
408 * menu m == menu handle for which structure is required.
409 *
410 * Returns
411 * A pointer to the WIMP menu structure.
412 */
413
414 wimp_menustr *menu_syshandle(menu m)
415 {
416 return (m->syshandle);
417 }
418
419 /*
420 * void menu_extend(menu m,char *items)
421 *
422 * Use
423 * Extend the given menu by a bit.
424 *
425 * Parameters
426 * menu m == the menu to extend
427 * char *items == the items to tag on the end
428 */
429
430 void menu_extend(menu m,char *items)
431 {
432 wimp_menuitem *itm;
433 wimp_menuitem *start;
434 int i;
435 int ino=menu__ROitemCount(items);
436 menu *t=mem_reAlloc
437 (
438 (menu *)m->syshandle-1,
439 sizeof(menu)+sizeof(wimp_menuhdr)+(ino+m->items)*sizeof(wimp_menuitem)+4
440 );
441 if (!t)
442 {
443 werr(FALSE,msgs_lookup("menuNEME:Not enough memory to extend menu."));
444 return;
445 }
446 m->syshandle=(wimp_menustr *)(t+1);
447 start=itm=menu__itmPointer(m,m->items);
448 if (*items=='|')
449 {
450 itm->flags|=wimp_MSEPARATE;
451 items++;
452 }
453 for (i=0;i<ino;i++)
454 {
455 itm++;
456 if (!menu__ROparse(m,&items,itm))
457 return;
458 }
459 start->flags&=~wimp_MLAST;
460 itm->flags|=wimp_MLAST;
461 m->syshandle->hdr.width=16*m->maxlen+16;
462 }
463
464 /*
465 * void menu_setflags(menu m,int i,BOOL tick,BOOL shade)
466 *
467 * Use
468 * Changes menu item properties
469 *
470 * Parameters
471 * menu m == menu to change
472 * int i == menu item to change
473 * BOOL tick == tick the item
474 * BOOL shade == shade the item
475 */
476
477 void menu_setflags(menu m,int i,BOOL tick,BOOL shade)
478 {
479 wimp_menuitem *itm=menu__itmPointer(m,i);
480 if (tick)
481 itm->flags|=wimp_MTICK;
482 else
483 itm->flags&=~wimp_MTICK;
484 if (shade)
485 itm->iconflags|=wimp_INOSELECT;
486 else
487 itm->iconflags&=~wimp_INOSELECT;
488 }
489
490 /*
491 * void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid)
492 *
493 * Use
494 * Makes a menu entry writable (sorry about the spelling - it's Acorn's
495 * fault)
496 *
497 * Parameters
498 * menu m == the menu in question
499 * int i == the item to be handled
500 * char *buff == where the data is to reside
501 * int bufflen == max length of data that can be crammed into buff
502 * char *valid == validation string (0 for none)
503 */
504
505 void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid)
506 {
507 wimp_menuitem *itm=menu__itmPointer(m,i);
508 if (!valid)
509 valid=(char *)-1;
510 itm->iconflags|=wimp_INDIRECT;
511 itm->flags|=wimp_MWRITABLE;
512 itm->data.indirecttext.buffer=buff;
513 itm->data.indirecttext.bufflen=bufflen;
514 itm->data.indirecttext.validstring=valid;
515 }
516
517 /*
518 * void menu_make_sprite(menu m,int i,char *name)
519 *
520 * Use
521 * Turns a menu entry into a sprite. Utterly useless, but there you go...
522 *
523 * Parameters
524 * menu m == the menu we're dealing with
525 * int i == the item to sprite-ise
526 * char *name == the sprite name
527 */
528
529 void menu_make_sprite(menu m,int i,char *name)
530 {
531 wimp_menuitem *itm=menu__itmPointer(m,i);
532 itm->iconflags|=wimp_INDIRECT|wimp_ISPRITE;
533 itm->iconflags&=~wimp_ITEXT;
534 itm->data.indirectsprite.name=name;
535 itm->data.indirectsprite.spritearea=resspr_area();
536 itm->data.indirectsprite.nameisname=TRUE;
537 }
538
539 /*
540 * void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid)
541 *
542 * Use
543 * Allows you to make a menu item's data point to your workspace, so you
544 * can change the text of an item at any time. The buffer length isn't
545 * important.
546 *
547 * Parameters
548 * menu m == the menu in question
549 * int i == the item to be handled
550 * char *buff == where the data is to reside
551 * int bufflen == max length of data that can be crammed into buff
552 * char *valid == validation string (0 for none)
553 */
554
555 void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid)
556 {
557 wimp_menuitem *itm=menu__itmPointer(m,i);
558 if (!valid)
559 valid=(char *)-1;
560 itm->iconflags|=wimp_INDIRECT;
561 itm->data.indirecttext.buffer=buff;
562 itm->data.indirecttext.bufflen=bufflen;
563 itm->data.indirecttext.validstring=valid;
564 }
565
566 /*
567 * void menu_minWidth(menu m,int min)
568 *
569 * Use
570 * Sets the minimum permissable width of a menu (in characters). Note that
571 * this call will not make the menu thinner than the width calculated
572 * during menu_new or menu_extend.
573 *
574 * Parameters
575 * menu m == the menu to change
576 * int min == the minumum allowable width fro the menu in characters. If
577 * 0 is passed, the width reverts to the calculated width.
578 */
579
580 void menu_minWidth(menu m,int min)
581 {
582 if (!min)
583 min=16*m->maxlen+16;
584 else
585 {
586 min=16*min+16;
587 if (min<m->syshandle->hdr.width)
588 return;
589 }
590 m->syshandle->hdr.width=min;
591 }
592
593 /*
594 * void menu_settitle(menu m,char *title)
595 *
596 * Use
597 * Change a menu title.
598 *
599 * Parameters
600 * menu m == the menu to change
601 * char *title == the new title
602 */
603
604 void menu_settitle(menu m,char *title)
605 {
606 strncpy(m->syshandle->hdr.title,title,12);
607 }
608
609 /*
610 * int *menu__processHits(int hit[])
611 *
612 * Use
613 * Processes a hit string as necessary (translates WIMP menu items to C
614 * ones etc.)
615 *
616 * Parameters
617 * int hit[] == PBR array to process, terminated by -1.
618 *
619 * Returns
620 * The array
621 */
622
623 static int *menu__processHits(int hit[])
624 {
625 int i=0;
626 do
627 hit[i++]++;
628 while (hit[i-1]);
629 return (hit);
630 }
631
632 /*
633 * menu menu__menumaker(void *handle)
634 *
635 * Use
636 * A surrogate menu maker.
637 *
638 * Parameters
639 * void *handle == pointer to information about the real maker
640 *
641 * Returns
642 * The menu to display
643 */
644
645 _dll_static menu menu__menumaker(void *handle)
646 {
647 menu__handlerstr *m=handle;
648 return ((m->m)(m->handle));
649 }
650
651 /*
652 * void menu__menuproc(void *handle,char hit[])
653 *
654 * Use
655 * General menu handler for menus registered using the menu functions
656 * rather than the standard event ones.
657 *
658 * Parameters
659 * void *handle == pointer to the control block for this menu
660 * char hit[] == an array of menu hits (ignored)
661 */
662
663 _dll_static void menu__menuproc(void *handle,char hit[])
664 {
665 menu__handlerstr *m=handle;
666 int hits[20];
667 int minusone=-1;
668 wimp_eventstr *e=wimpt_last_event();
669 hit=hit;
670 switch (event_whyMenuEvent())
671 {
672 case event_MENUSELECT:
673 if (m->sel)
674 (m->sel)(menu__processHits(e->data.menu),m->handle);
675 break;
676 case event_MENUDELETE:
677 if (m->sel)
678 (m->sel)(menu__processHits(&minusone),m->handle);
679 break;
680 case event_MENUSUBMENU:
681 if (m->sel)
682 (m->sel)(menu__processHits(e->data.msg.data.words+3),m->handle);
683 break;
684 case event_MENUHELP:
685 if (m->help)
686 {
687 wimpt_noerr(wimp_getmenustate(1,
688 hits,
689 e->data.msg.data.helprequest.m.w,
690 e->data.msg.data.helprequest.m.i));
691 (m->help)(menu__processHits(hits),m->handle);
692 }
693 break;
694 default:
695 werr(TRUE,msgs_lookup("menuUKNME:(menu__menuproc): "
696 "Unknown menu event type."));
697 }
698 }
699
700 /*
701 * void menu_attach
702 * (
703 * wimp_w w,
704 * menu m,
705 * menu_selectProc sel,
706 * menu_helpProc help,
707 * void *handle
708 * )
709 *
710 * Use
711 * Basically equivalent to event_attachmenu, only it handles help requests
712 * neatly etc. Source code compatibility *cannot* be assured, because I
713 * want to be able to expand this routine to cater for later changes. I
714 * will try to soften the blow (if any) by supplying macros that will work
715 * with older programs, but I can't guarantee anything.
716 *
717 * Parameters
718 * wimp_w w == the window to attach to
719 * menu m == the menu to attach
720 * menu_selectProc sel == procedure to handle most selection-type events
721 * menu_helpProc help == procedure to handle help requests for the menu
722 */
723
724 void menu_attach
725 (
726 wimp_w w,
727 menu m,
728 menu_selectProc sel,
729 menu_helpProc help,
730 void *handle
731 )
732 {
733 menu__handlerstr *h=0;
734 void *old;
735 menu om;
736 event_menu_maker omm;
737 event_menu_proc omp;
738 if (m)
739 {
740 if (h=mem_alloc(sizeof(menu__handlerstr)),!h)
741 {
742 werr
743 (
744 FALSE,
745 msgs_lookup("menuNEM:Not enough memory to construct menu.")
746 );
747 return;
748 }
749 h->sel=sel;
750 h->help=help;
751 h->handle=handle;
752 }
753 event_attachedMenu(w,&om,&omm,&omp,&old);
754 if (omp==menu__menuproc)
755 mem_free(old);
756 event_attachmenu(w,m,_dllEntry(menu__menuproc),h);
757 }
758
759 /*
760 * void menu_attachMaker
761 * (
762 * wimp_w w,
763 * event_menu_maker m,
764 * menu_selectProc sel,
765 * menu_helpProc help,
766 * void *handle
767 * )
768 *
769 * Use
770 * This routine deals with event_attachmenumaker as menu_attach deals with
771 * event_attachmenu.
772 *
773 * Parameters
774 * wimp_w w == the window to attach to
775 * menu m == the menu to attach
776 * menu_selectProc sel == procedure to handle most selection-type events
777 * menu_helpProc help == procedure to handle help requests for the menu
778 */
779
780 void menu_attachMaker
781 (
782 wimp_w w,
783 event_menu_maker m,
784 menu_selectProc sel,
785 menu_helpProc help,
786 void *handle
787 )
788 {
789 menu__handlerstr *h=0;
790 void *old;
791 menu om;
792 event_menu_maker omm;
793 event_menu_proc omp;
794 if (m)
795 {
796 if (h=mem_alloc(sizeof(menu__handlerstr)),!h)
797 {
798 werr
799 (
800 FALSE,
801 msgs_lookup("menuNEM:Not enough memory to construct menu.")
802 );
803 return;
804 }
805 h->sel=sel;
806 h->help=help;
807 h->handle=handle;
808 h->m=m;
809 }
810 event_attachedMenu(w,&om,&omm,&omp,&old);
811 if (omp==menu__menuproc)
812 mem_free(old);
813 event_attachmenumaker(w,
814 _dllEntry(menu__menumaker),
815 _dllEntry(menu__menuproc),
816 h);
817 }
818
819 /*
820 * void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle)
821 *
822 * Use
823 * Analagous to event_openMenu().
824 *
825 * Parameters
826 * As above.
827 */
828
829 void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle)
830 {
831 menu__instant.sel=sel;
832 menu__instant.help=help;
833 menu__instant.handle=handle;
834 event_openMenu(m,_dllEntry(menu__menuproc),&menu__instant);
835 }
836
837 /*
838 * void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle)
839 *
840 * Use
841 * Analagous to event_makeMenu().
842 *
843 * Parameters
844 * As above.
845 */
846
847 void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle)
848 {
849 menu__instant.sel=sel;
850 menu__instant.help=help;
851 menu__instant.handle=handle;
852 menu__instant.m=m;
853 event_makeMenu(_dllEntry(menu__menumaker),
854 _dllEntry(menu__menuproc),
855 &menu__instant);
856 }
857
858 /*
859 * void menu_saveHandler(wimp_w w,menu_handler *h)
860 *
861 * Use
862 * Saves information about the menu handle for the given window in the
863 * block specified. This can be used *only* to restore the handler for a
864 * window later (although it needn't be the same one). Note too that the
865 * window need not have to have menu handlers registered using the menu
866 * calls, or even have any at all.
867 *
868 * Parameters
869 * wimp_w w == the window whose menu handlers we are to save
870 * menu_handler *h == pointer to a chunk of memory to fill in.
871 */
872
873 void menu_saveHandler(wimp_w w,menu_handler *h)
874 {
875 event_menu_maker mk;
876 event_menu_proc p;
877 menu m;
878 void *hand;
879 menu__handlerstr *ha;
880 event_attachedMenu(w,&m,&mk,&p,&hand);
881 if (p==_dllEntry(menu__menuproc))
882 {
883 ha=hand;
884 h->doneByMenu=TRUE;
885 h->info.m.m=m;
886 h->info.m.make=ha->m;
887 h->info.m.sel=ha->sel;
888 h->info.m.help=ha->help;
889 h->info.m.handle=ha->handle;
890 }
891 else
892 {
893 h->doneByMenu=FALSE;
894 h->info.e.m=m;
895 h->info.e.make=mk;
896 h->info.e.proc=p;
897 h->info.e.handle=hand;
898 }
899 }
900
901 /*
902 * void menu_restoreHandler(wimp_w w,menu_handler *h)
903 *
904 * Use
905 * Restores handlers from a structure filled in by menu_saveHandler.
906 *
907 * Parameters
908 * wimp_w w == the window whose handlers we are to set up.
909 * menu_handler *h == pointer to a chunk of memory filled in correctly.
910 */
911
912 void menu_restoreHandler(wimp_w w,menu_handler *h)
913 {
914 if (h->doneByMenu)
915 {
916 if (h->info.m.m)
917 {
918 menu_attach(w,
919 h->info.m.m,
920 h->info.m.sel,
921 h->info.m.help,
922 h->info.m.handle);
923 }
924 else
925 {
926 menu_attachMaker(w,
927 h->info.m.make,
928 h->info.m.sel,
929 h->info.m.help,
930 h->info.m.handle);
931 }
932 }
933 else
934 {
935 if (h->info.e.m)
936 event_attachmenu(w,h->info.e.m,h->info.e.proc,h->info.e.handle);
937 else
938 {
939 event_attachmenumaker(w,
940 h->info.e.make,
941 h->info.e.proc,
942 h->info.e.handle);
943 }
944 }
945 }