1/*
2 * $XConsortium: tocfuncs.c /main/36 1996/02/02 14:27:42 kaleb $
3 *
4 *
5 *			COPYRIGHT 1987, 1989
6 *		   DIGITAL EQUIPMENT CORPORATION
7 *		       MAYNARD, MASSACHUSETTS
8 *			ALL RIGHTS RESERVED.
9 *
10 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
11 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
12 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
13 * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
14 *
15 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
16 * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
17 * ADDITION TO THAT SET FORTH ABOVE.
18 *
19 * Permission to use, copy, modify, and distribute this software and its
20 * documentation for any purpose and without fee is hereby granted, provided
21 * that the above copyright notice appear in all copies and that both that
22 * copyright notice and this permission notice appear in supporting
23 * documentation, and that the name of Digital Equipment Corporation not be
24 * used in advertising or publicity pertaining to distribution of the software
25 * without specific, written prior permission.
26 */
27/* $XFree86: xc/programs/xmh/tocfuncs.c,v 1.3 2001/10/28 03:34:39 tsi Exp $ */
28
29/* tocfuncs.c -- action procedures concerning things in the toc widget. */
30
31#include "xmh.h"
32#include "tocutil.h"
33#include "actions.h"
34
35#define MAX_SYSTEM_LEN 510
36
37Boolean UserWantsAction(
38    Widget	w,
39    Scrn	scrn)
40{
41    /* Commands in the command menus invoke callbacks directly.
42     * Keyboard accelerators use the command menus as source widgets.
43     * Actions can also be specified in the translations for menu buttons.
44     * Actions can also be specified in the translations for menus.
45     * In fact, the user can attach actions to any (reasonable) widget.
46     *
47     * The purpose of this check is to prevent actions specified as
48     * translations for folder menus and for folder buttons from executing
49     * after the mouse pointer has left the folder button or the when the
50     * mouse button is released outside of the folder menu.
51     *
52     * The side effect of this routine is that it restricts keyboard
53     * accelerators from originating from folder buttons or folder menus.
54     */
55
56    if (XtIsSubclass(w, menuButtonWidgetClass) && /* w is a menu button */
57	w != LastMenuButtonPressed)		  /* pointer left the window */
58	return False;
59
60    if (XtIsSubclass(w, simpleMenuWidgetClass) &&	/* w is a menu */
61	(! XawSimpleMenuGetActiveEntry(w)) &&	/* no entry was selected */
62	(BBoxIsGrandparent(scrn->folderbuttons, w)))  /* w is a folder menu */
63	return False;
64
65    return True;
66}
67
68
69/*ARGSUSED*/
70static void NextAndPreviousView(
71    Scrn	scrn,
72    Boolean	next)	/* if true, next or forward; if false, previous */
73{
74    Toc		toc = scrn->toc;
75    MsgList	mlist;
76    FateType	fate = Fignore;
77    Msg		msg;
78
79    if (toc == NULL) return;
80    mlist = TocCurMsgList(toc);
81    if (mlist->nummsgs)
82	msg = (next ? mlist->msglist[0] : mlist->msglist[mlist->nummsgs - 1]);
83    else {
84	msg = TocGetCurMsg(toc);
85	if (msg && msg == scrn->msg)
86	    msg = (next ? TocMsgAfter(toc, msg) : TocMsgBefore(toc, msg));
87	if (msg) fate = MsgGetFate(msg, (Toc *)NULL);
88	while (msg && ((app_resources.skip_deleted && fate == Fdelete)
89		|| (app_resources.skip_moved && fate == Fmove)
90		|| (app_resources.skip_copied && fate == Fcopy))) {
91	    msg = (next ? TocMsgAfter(toc, msg) : TocMsgBefore(toc, msg));
92	    if (msg) fate = MsgGetFate(msg, (Toc *)NULL);
93	}
94    }
95
96    if (msg) {
97	XtCallbackRec	confirms[2];
98	if (next)
99	    confirms[0].callback = (XtCallbackProc) DoNextView;
100	else
101	    confirms[0].callback = (XtCallbackProc) DoPrevView;
102	confirms[0].closure = (XtPointer) scrn;
103	confirms[1].callback = (XtCallbackProc) NULL;
104	confirms[1].closure = (XtPointer) NULL;
105	if (MsgSetScrn(msg, scrn, confirms, (XtCallbackList) NULL) !=
106	    NEEDS_CONFIRMATION) {
107	    TocUnsetSelection(toc);
108	    TocSetCurMsg(toc, msg);
109	}
110    }
111    FreeMsgList(mlist);
112}
113
114
115/*ARGSUSED*/
116void DoReverseReadOrder(
117    Widget	widget,		/* the menu entry widget */
118    XtPointer	client_data,
119    XtPointer	call_data)
120{
121    app_resources.reverse_read_order =
122	(app_resources.reverse_read_order ? False : True);
123    ToggleMenuItem(widget, app_resources.reverse_read_order);
124}
125
126
127/*ARGSUSED*/
128void DoNextView(
129    Widget	widget,		/* unused */
130    XtPointer	client_data,
131    XtPointer	call_data)	/* unused */
132{
133    NextAndPreviousView((Scrn) client_data,
134			(app_resources.reverse_read_order ? False : True));
135}
136
137/*ARGSUSED*/
138void XmhViewNextMessage(
139    Widget	w,
140    XEvent	*event,
141    String	*params,
142    Cardinal	*num_params)
143{
144    Scrn scrn = ScrnFromWidget(w);
145    if (UserWantsAction(w, scrn))
146	DoNextView(w, (XtPointer) scrn, (XtPointer) NULL);
147}
148
149/*ARGSUSED*/
150void DoPrevView(
151    Widget	widget,		/* unused */
152    XtPointer	client_data,
153    XtPointer	call_data)	/* unused */
154{
155    NextAndPreviousView((Scrn) client_data,
156			(app_resources.reverse_read_order ? True : False));
157}
158
159/*ARGSUSED*/
160void XmhViewPreviousMessage(
161    Widget	w,
162    XEvent	*event,
163    String	*params,
164    Cardinal	*num_params)
165{
166    Scrn scrn = ScrnFromWidget(w);
167    if (UserWantsAction(w, scrn))
168	DoPrevView(w, (XtPointer) scrn, (XtPointer) NULL);
169}
170
171
172/*ARGSUSED*/
173void DoViewNew(
174    Widget	w,
175    XtPointer	client_data,
176    XtPointer	call_data)
177{
178    Scrn	scrn = (Scrn) client_data;
179    Toc		toc = scrn->toc;
180    Scrn	vscrn;
181    MsgList	mlist;
182
183    if (toc == NULL) return;
184    mlist = CurMsgListOrCurMsg(toc);
185    if (mlist->nummsgs) {
186	vscrn = NewViewScrn();
187	(void) MsgSetScrn(mlist->msglist[0], vscrn, (XtCallbackList) NULL,
188			  (XtCallbackList) NULL);
189	MapScrn(vscrn);
190    }
191    FreeMsgList(mlist);
192}
193
194
195/*ARGSUSED*/
196void XmhViewInNewWindow(
197    Widget	w,
198    XEvent	*event,
199    String	*params,
200    Cardinal	*num_params)
201{
202    Scrn scrn = ScrnFromWidget(w);
203    if (UserWantsAction(w, scrn))
204	DoViewNew(w, (XtPointer) scrn, (XtPointer) NULL);
205}
206
207
208static void DoForwardMsg(
209    Scrn	scrn,
210    String	*params,
211    Cardinal	num_params)
212{
213    Toc		toc = scrn->toc;
214    MsgList	mlist;
215
216    if (toc == NULL) return;
217    mlist = CurMsgListOrCurMsg(toc);
218    if (mlist->nummsgs)
219	CreateForward(mlist, params, num_params);
220    FreeMsgList(mlist);
221}
222
223
224/*ARGSUSED*/
225void DoForward(
226    Widget	w,
227    XtPointer	client_data,
228    XtPointer	call_data)
229{
230    DoForwardMsg((Scrn) client_data, (String *)NULL, (Cardinal)0);
231}
232
233
234/*ARGSUSED*/
235void XmhForward(
236    Widget	w,
237    XEvent	*event,
238    String	*params,
239    Cardinal	*num_params)
240{
241    Scrn scrn = ScrnFromWidget(w);
242    if (UserWantsAction(w, scrn))
243	DoForwardMsg(scrn, params, *num_params);
244}
245
246
247/*ARGSUSED*/
248void DoTocUseAsComp(
249    Widget	w,
250    XtPointer	client_data,
251    XtPointer	call_data)
252{
253    Scrn	scrn = (Scrn) client_data;
254    Toc		toc = scrn->toc;
255    Scrn	vscrn;
256    MsgList	mlist;
257    Msg		msg;
258
259    if (toc == NULL) return;
260    mlist = CurMsgListOrCurMsg(toc);
261    if (mlist->nummsgs) {
262	vscrn = NewCompScrn();
263	if (DraftsFolder == toc) {
264	    msg = mlist->msglist[0];
265	} else {
266	    msg = TocMakeNewMsg(DraftsFolder);
267	    MsgLoadCopy(msg, mlist->msglist[0]);
268	    MsgSetTemporary(msg);
269	}
270	MsgSetScrnForComp(msg, vscrn);
271	MapScrn(vscrn);
272    }
273    FreeMsgList(mlist);
274}
275
276
277/*ARGSUSED*/
278void XmhUseAsComposition(
279    Widget	w,
280    XEvent	*event,
281    String	*params,
282    Cardinal	*num_params)
283{
284    Scrn scrn = ScrnFromWidget(w);
285    if (UserWantsAction(w, scrn))
286	DoTocUseAsComp(w, (XtPointer) scrn, (XtPointer) NULL);
287}
288
289
290/* Utility: change the fate of a set of messages. */
291
292static void MarkMessages(Scrn scrn, FateType fate, int skip)
293{
294    Toc toc = scrn->toc;
295    Toc desttoc;
296    int i;
297    MsgList mlist;
298    Msg msg;
299    if (toc == NULL) return;
300    if (fate == Fcopy || fate == Fmove)
301	desttoc = SelectedToc(scrn);
302    else
303	desttoc = NULL;
304    if (desttoc == toc)
305	Feep(XkbBI_MinorError,0,None);
306    else {
307	mlist = TocCurMsgList(toc);
308	if (mlist->nummsgs == 0) {
309	    msg = TocGetCurMsg(toc);
310	    if (msg) {
311		MsgSetFate(msg, fate, desttoc);
312		if (skip)
313		    DoNextView(scrn->widget, (XtPointer) scrn,
314			       (XtPointer) NULL);
315	    }
316	} else {
317	    for (i = 0; i < mlist->nummsgs; i++)
318		MsgSetFate(mlist->msglist[i], fate, desttoc);
319	}
320	FreeMsgList(mlist);
321    }
322}
323
324
325/*ARGSUSED*/
326void XmhMarkDelete(
327    Widget	w,
328    XEvent	*event,
329    String	*params,
330    Cardinal	*num_params)
331{
332    Scrn scrn = ScrnFromWidget(w);
333    if (UserWantsAction(w, scrn))
334	DoDelete(w, (XtPointer) scrn, (XtPointer) NULL);
335}
336
337
338/*ARGSUSED*/
339void DoDelete(
340    Widget	w,
341    XtPointer	client_data,
342    XtPointer	call_data)
343{
344    Scrn scrn = (Scrn) client_data;
345    MarkMessages(scrn, Fdelete, app_resources.skip_deleted);
346}
347
348
349/*ARGSUSED*/
350void DoCopy(
351    Widget	w,
352    XtPointer	client_data,
353    XtPointer	call_data)
354{
355    Scrn scrn = (Scrn) client_data;
356    MarkMessages(scrn, Fcopy, app_resources.skip_copied);
357}
358
359
360/*ARGSUSED*/
361void XmhMarkCopy(
362    Widget	w,
363    XEvent	*event,
364    String	*params,
365    Cardinal	*num_params)
366{
367    Scrn scrn = ScrnFromWidget(w);
368    if (UserWantsAction(w, scrn))
369	DoCopy(w, (XtPointer) scrn, (XtPointer) NULL);
370}
371
372
373/*ARGSUSED*/
374void DoMove(
375    Widget	w,
376    XtPointer	client_data,
377    XtPointer	call_data)
378{
379    Scrn scrn = (Scrn) client_data;
380    MarkMessages(scrn, Fmove, app_resources.skip_moved);
381}
382
383
384/*ARGSUSED*/
385void XmhMarkMove(
386    Widget	w,
387    XEvent	*event,
388    String	*params,
389    Cardinal	*num_params)
390{
391    Scrn scrn = ScrnFromWidget(w);
392    if (UserWantsAction(w, scrn))
393	DoMove(w, (XtPointer) scrn, (XtPointer) NULL);
394}
395
396
397/*ARGSUSED*/
398void DoUnmark(
399    Widget	w,
400    XtPointer	client_data,
401    XtPointer	call_data)
402{
403    Scrn scrn = (Scrn) client_data;
404    MarkMessages(scrn, Fignore, FALSE);
405}
406
407
408/*ARGSUSED*/
409void XmhUnmark(
410    Widget	w,
411    XEvent	*event,
412    String	*params,
413    Cardinal	*num_params)
414{
415    Scrn scrn = ScrnFromWidget(w);
416    if (UserWantsAction(w, scrn))
417	DoUnmark(w, (XtPointer) scrn, (XtPointer) NULL);
418}
419
420
421/*ARGSUSED*/
422void DoCommit(
423    Widget	w,
424    XtPointer	client_data,
425    XtPointer	 call_data)
426{
427    Scrn	scrn = (Scrn) client_data;
428    TocCommitChanges(w, (XtPointer) scrn->toc, (XtPointer) NULL);
429}
430
431
432/*ARGSUSED*/
433void XmhCommitChanges(
434    Widget	w,
435    XEvent	*event,
436    String	*params,
437    Cardinal	*num_params)
438{
439    Scrn scrn = ScrnFromWidget(w);
440    if (UserWantsAction(w, scrn))
441	TocCommitChanges(w, (XtPointer) scrn->toc, (XtPointer) NULL);
442}
443
444
445/*ARGSUSED*/
446void XmhShellCommand(
447    Widget	w,	 /* any widget on same scrn as the messages */
448    XEvent	*event,	 /* unused */
449    String	*params, /* shell command to execute with msgs appended */
450    Cardinal	*num_params)
451{
452    int		i, len, used;
453    MsgList	mlist;
454    String	*p;
455    Scrn 	scrn = ScrnFromWidget(w);
456    char	str[MAX_SYSTEM_LEN];
457
458    if (! UserWantsAction(w, scrn) || ! scrn->toc)
459	return;
460    if (! *num_params) {
461	PopupError(scrn->parent, "XmhShellCommand: no command given.");
462	return;
463    }
464    used = 0;
465    p = params;
466    for (i = *num_params; --i >= 0; p++) {
467	len = strlen(*p);
468	if ((used + len + 1) >= MAX_SYSTEM_LEN) {
469	    PopupError(scrn->parent, "XmhShellCommand: command too long.");
470	    return;
471	}
472	strncpy(&str[used], *p, len);
473	str[(used += len)] = ' ';
474	used++;
475    }
476    str[used] = '\0';
477
478    mlist = CurMsgListOrCurMsg(scrn->toc);
479    if (mlist->nummsgs) {
480	char *msg;
481	int prefix = used;
482	i = 0;
483	while (i < mlist->nummsgs) {
484	    used = prefix;
485	    while (i < mlist->nummsgs &&
486		   (msg = MsgFileName(mlist->msglist[i])) &&
487		   (used + (len = strlen(msg)) + 1) < MAX_SYSTEM_LEN) {
488		strncpy(&str[used], msg, len);
489		str[(used += len)] = ' ';
490		used++;
491		i++;
492	    }
493	    if (used != prefix) {
494		char **argv;
495		str[used] = '\0';
496		DEBUG( str );
497		argv = MakeArgv(3);
498		argv[0] = "/bin/sh";
499		argv[1] = "-c";	/* commands are read from the next argument */
500		argv[2] = str;
501		(void) DoCommand(argv, (char*)NULL, (char*)NULL);
502		/* a "notice" popup should appear with stderr output */
503		XtFree((char*)argv);
504	    }
505	}
506    } else
507	PopupError(scrn->parent, "XmhShellCommand: no messages selected.");
508
509    FreeMsgList(mlist);
510}
511
512
513void XmhPrint(
514    Widget	w,
515    XEvent	*event,
516    String	*params,
517    Cardinal	*num_params)
518{
519    if (! num_params || ! *num_params) {
520	/* use the print command specified in application resources */
521	Cardinal argc = 1;
522	char **argv = MakeArgv(argc);
523	argv[0] = app_resources.print_command;
524	XmhShellCommand(w, event, (String *) argv, &argc);
525	XtFree((char *) argv);
526    } else {
527	/* do whatever the user has specified as action parameters */
528	XmhShellCommand(w, event, params, num_params);
529    }
530}
531
532
533/*ARGSUSED*/
534void DoPrint(
535    Widget	w,
536    XtPointer	client_data,
537    XtPointer	call_data)	/* unused */
538{
539    Scrn	scrn = (Scrn) client_data;
540    Cardinal	num_params = 0;
541    /* The callback interface will not be entered unless the user requested
542     * the action, so pass a widget which will succeed the test in
543     * UserWantsAction.
544     */
545    XmhPrint(scrn->parent, (XEvent*)NULL, (String*)NULL, &num_params);
546}
547
548
549/*ARGSUSED*/
550void DoPack(
551    Widget	widget,
552    XtPointer	client_data,
553    XtPointer	call_data)	/* unused */
554{
555    Scrn	scrn = (Scrn) client_data;
556    Toc		toc = scrn->toc;
557    XtCallbackRec confirms[2];
558    char	**argv;
559
560    if (toc == NULL) return;
561    confirms[0].callback = (XtCallbackProc) DoPack;
562    confirms[0].closure = (XtPointer) scrn;
563    confirms[1].callback = (XtCallbackProc) NULL;
564    confirms[1].closure = (XtPointer) NULL;
565    if (TocConfirmCataclysm(toc, confirms, (XtCallbackRec *) NULL))
566	return;
567    argv = MakeArgv(4);
568    argv[0] = "folder";
569    argv[1] = TocMakeFolderName(toc);
570    argv[2] = "-pack";
571    argv[3] = "-fast";
572    if (app_resources.block_events_on_busy) ShowBusyCursor();
573
574    DoCommand(argv, (char *) NULL, (char *) NULL);
575    XtFree(argv[1]);
576    XtFree((char *) argv);
577    TocForceRescan(toc);
578
579    if (app_resources.block_events_on_busy) UnshowBusyCursor();
580
581}
582
583
584/*ARGSUSED*/
585void XmhPackFolder(
586    Widget	w,
587    XEvent	*event,
588    String	*params,
589    Cardinal	*num_params)
590{
591    Scrn scrn = ScrnFromWidget(w);
592    if (UserWantsAction(w, scrn))
593	DoPack(w, (XtPointer) scrn, (XtPointer) NULL);
594}
595
596
597/*ARGSUSED*/
598void DoSort(
599    Widget	widget,
600    XtPointer	client_data,
601    XtPointer	call_data)	/* unused */
602{
603    Scrn	scrn = (Scrn) client_data;
604    Toc		toc = scrn->toc;
605    char **	argv;
606    XtCallbackRec confirms[2];
607
608    if (toc == NULL) return;
609    confirms[0].callback = (XtCallbackProc) DoSort;
610    confirms[0].closure = (XtPointer) scrn;
611    confirms[1].callback = (XtCallbackProc) NULL;
612    confirms[1].closure = (XtPointer) NULL;
613    if (TocConfirmCataclysm(toc, confirms, (XtCallbackRec *) NULL))
614	return;
615    argv = MakeArgv(3);
616    argv[0] = "sortm";
617    argv[1] = TocMakeFolderName(toc);
618    argv[2] = "-noverbose";
619    if (app_resources.block_events_on_busy) ShowBusyCursor();
620
621    DoCommand(argv, (char *) NULL, (char *) NULL);
622    XtFree(argv[1]);
623    XtFree((char *) argv);
624    TocForceRescan(toc);
625
626    if (app_resources.block_events_on_busy) UnshowBusyCursor();
627}
628
629
630/*ARGSUSED*/
631void XmhSortFolder(
632    Widget	w,
633    XEvent	*event,
634    String	*params,
635    Cardinal	*num_params)
636{
637    Scrn scrn = ScrnFromWidget(w);
638    if (UserWantsAction(w, scrn))
639	DoSort(w, (XtPointer) scrn, (XtPointer) NULL);
640}
641
642
643/*ARGSUSED*/
644void XmhForceRescan(
645    Widget	w,
646    XEvent	*event,
647    String	*params,
648    Cardinal	*num_params)
649{
650    Scrn scrn = ScrnFromWidget(w);
651    if (UserWantsAction(w, scrn))
652	DoForceRescan(w, (XtPointer) scrn, (XtPointer) NULL);
653}
654
655/*ARGSUSED*/
656void DoForceRescan(
657    Widget	w,
658    XtPointer	client_data,
659    XtPointer	call_data)
660{
661    Scrn	scrn = (Scrn) client_data;
662    Toc		toc = scrn->toc;
663    if (toc == NULL) return;
664    if (app_resources.block_events_on_busy) ShowBusyCursor();
665
666    TocForceRescan(toc);
667
668    if (app_resources.block_events_on_busy) UnshowBusyCursor();
669}
670
671/*ARGSUSED*/
672void XmhCheckForNewMail(
673    Widget w,
674    XEvent *e,
675    String *p,
676    Cardinal *n)
677{
678    TocCheckForNewMail(True);
679}
680
681/* Incorporate new mail. */
682
683/*ARGSUSED*/
684void XmhIncorporateNewMail(
685    Widget	w,
686    XEvent	*event,
687    String	*params,
688    Cardinal	*num_params)
689{
690    Scrn scrn = ScrnFromWidget(w);
691    if (UserWantsAction(w, scrn)) {
692	if (TocCanIncorporate(scrn->toc))
693	    DoIncorporateNewMail(w, (XtPointer) scrn, (XtPointer) NULL);
694    }
695}
696
697
698void DoIncorporateNewMail(
699    Widget	w,		/* unused */
700    XtPointer	client_data,	/* screen */
701    XtPointer	call_data)	/* unused */
702{
703    Scrn scrn = (Scrn) client_data;
704    Toc toc = scrn->toc;
705    int i;
706    int newmail;
707
708    if (! toc) return;
709    newmail = TocIncorporate(toc);
710
711    if (app_resources.show_on_inc && newmail)
712	DoNextView(w, client_data, call_data);
713
714    if (app_resources.new_mail_check)
715	/* update the folder button */
716	for (i=0; i < numScrns; i++) {
717	    scrn = scrnList[i];
718	    if (scrn->kind == STtocAndView)
719		/* give visual indication of no mail waiting */
720		BBoxMailFlag(scrn->folderbuttons, TocName(toc), False);
721	}
722
723    if (app_resources.mail_waiting_flag)
724	/* update the icon */
725	TocCheckForNewMail(False);
726}
727
728
729static void DoReplyMsg(
730    Scrn	scrn,
731    String	*params,
732    Cardinal	num_params)
733{
734    Toc		toc = scrn->toc;
735    Scrn	nscrn;
736    MsgList	mlist;
737    Msg		msg;
738
739    if (toc == NULL) return;
740    mlist = CurMsgListOrCurMsg(toc);
741    if (mlist->nummsgs) {
742	nscrn = NewCompScrn();
743	ScreenSetAssocMsg(nscrn, mlist->msglist[0]);
744	msg = TocMakeNewMsg(DraftsFolder);
745	MsgSetTemporary(msg);
746	MsgLoadReply(msg, mlist->msglist[0], params, num_params);
747	MsgSetScrnForComp(msg, nscrn);
748	MapScrn(nscrn);
749    }
750    FreeMsgList(mlist);
751}
752
753
754/*ARGSUSED*/
755void DoReply(
756    Widget	w,
757    XtPointer	client_data,
758    XtPointer	call_data)
759{
760    DoReplyMsg((Scrn) client_data, (String *)NULL, (Cardinal)0);
761}
762
763
764/*ARGSUSED*/
765void XmhReply(
766    Widget	w,
767    XEvent	*event,
768    String	*params,
769    Cardinal	*num_params)
770{
771    Scrn scrn = ScrnFromWidget(w);
772    if (UserWantsAction(w, scrn))
773	DoReplyMsg(scrn, params, *num_params);
774}
775
776
777/*ARGSUSED*/
778void DoPickMessages(
779    Widget	w,
780    XtPointer	client_data,
781    XtPointer	call_data)
782{
783    Scrn	scrn = (Scrn) client_data;
784    Toc		toc = scrn->toc;
785    Scrn	nscrn;
786    const char *toseq;
787    Sequence	selectedseq;
788    Boolean	recycled;
789
790    if (toc == NULL) return;
791    if ((selectedseq = TocSelectedSequence(toc)) == NULL)
792	toseq = "temp";
793    else {
794	toseq = selectedseq->name;
795	if (strcmp(toseq, "all") == 0)
796	    toseq = "temp";
797    }
798    nscrn = CreateNewScrn(STpick);
799    recycled = (nscrn->pick) ? True : False;
800    AddPick(nscrn, toc, (TocViewedSequence(toc))->name, toseq);
801    DEBUG("Realizing Pick...")
802    XtRealizeWidget(nscrn->parent);
803    DEBUG(" done.\n")
804    if (! recycled) {
805	InitBusyCursor(nscrn);
806	XDefineCursor(XtDisplay(nscrn->parent), XtWindow(nscrn->parent),
807		      app_resources.cursor);
808	(void) XSetWMProtocols(XtDisplay(toplevel), XtWindow(nscrn->parent),
809			       protocolList, XtNumber(protocolList));
810    }
811    MapScrn(nscrn);
812}
813
814
815/*ARGSUSED*/
816void XmhPickMessages(
817    Widget	w,
818    XEvent	*event,
819    String	*params,
820    Cardinal	*num_params)
821{
822    Scrn scrn = ScrnFromWidget(w);
823    if (UserWantsAction(w, scrn))
824	DoPickMessages(w, (XtPointer) scrn, (XtPointer) NULL);
825}
826
827
828/*ARGSUSED*/
829void DoSelectSequence(
830    Widget	widget,		/* sequence menu entry object */
831    XtPointer	client_data,	/* the screen */
832    XtPointer	call_data)
833{
834    Scrn	scrn = (Scrn) client_data;
835    Toc		toc  = (Toc) scrn->toc;
836    Sequence	seq;
837
838    if ((seq = TocSelectedSequence(toc)) != NULL) {
839	Widget	item, menu;
840	Button	button;
841
842	button = BBoxFindButtonNamed
843	    (scrn->mainbuttons, MenuBoxButtons[XMH_SEQUENCE].button_name);
844	menu = BBoxMenuOfButton(button);
845	if ((item = XtNameToWidget(menu, seq->name)) != NULL)
846	    ToggleMenuItem(item, False);
847    }
848
849    ToggleMenuItem(widget, True);
850    TocSetSelectedSequence(toc, TocGetSeqNamed(toc, XtName(widget)));
851}
852
853
854/*ARGSUSED*/
855void DoOpenSeq(
856    Widget	w,
857    XtPointer	client_data,
858    XtPointer	call_data)
859{
860    Scrn	scrn = (Scrn) client_data;
861    Toc		toc = scrn->toc;
862    if (toc == NULL) return;
863    TocChangeViewedSeq(toc, TocSelectedSequence(toc));
864}
865
866
867/*ARGSUSED*/
868void XmhOpenSequence(
869    Widget	w,
870    XEvent	*event,
871    String	*params,
872    Cardinal	*num_params)
873{
874    Widget	entry_object;
875    Scrn	scrn = ScrnFromWidget(w);
876    Sequence	selected_sequence;
877
878    /* In case this action is called from translations defined by the
879     * user on folder menu buttons or on folder menu widgets.
880     */
881    if (! UserWantsAction(w, scrn))
882	return;
883
884    /* In case there is nothing to do anyway. */
885    if (! TocHasSequences(scrn->toc))
886	return;
887
888    /* In case the action was given the name of a sequence to open. */
889    if (*num_params) {
890	Toc	toc = scrn->toc;
891	if ((selected_sequence = TocGetSeqNamed(toc, params[0]))) {
892	    TocSetSelectedSequence(toc, selected_sequence);
893	    TocChangeViewedSeq(toc, selected_sequence);
894	}
895	return;
896    }
897
898    /* In case this action is a translation on the sequence menu.  */
899
900    if ((strcmp(XtName(w), "sequenceMenu") == 0) &&
901	(event->type == ButtonRelease)) {
902
903	/* The user released the mouse button.  We must distinguish between
904	 * a button release on a selectable menu entry, and a button release
905	 * occurring elsewhere.  The button releases occurring elsewhere are
906	 * either outside of the menu, or on unselectable menu entries.
907	 */
908
909	if ((entry_object = XawSimpleMenuGetActiveEntry(w)) == NULL)
910	    return;
911
912	/* Some entry in the menu was selected.  The menu entry's callback
913	 * procedure has already executed.  If a sequence name was selected,
914	 * the callback procedure has caused that sequence to become the
915	 * currently selected sequence.  If selected menu entry object's
916	 * name matches the currently selected sequence, we should open
917	 * that sequence.  Otherwise, the user must have selected a sequence
918	 * manipulation command, such as Pick.  The assumptions here are that
919	 * the name of a menu entry object which represents a sequence is
920	 * identical to the name of the sequence, and in the translations,
921	 * that the notify() action was specified before this action.
922	 */
923
924	if ((selected_sequence = TocSelectedSequence(scrn->toc)) &&
925	    (strcmp(XtName(entry_object), selected_sequence->name) == 0))
926	    DoOpenSeq(w, (XtPointer) scrn, (XtPointer) NULL);
927	return;
928    }
929
930    /* An accelerator open sequence function */
931
932    DoOpenSeq(w, (XtPointer) scrn, (XtPointer) NULL);
933}
934
935
936typedef enum {ADD, REMOVE, DELETE} TwiddleOperation;
937
938static void TwiddleSequence(Scrn scrn, TwiddleOperation op)
939{
940    Toc toc = scrn->toc;
941    char **argv;
942    int i;
943    MsgList mlist;
944    Sequence	selectedseq;
945
946    if (toc == NULL || ((selectedseq = TocSelectedSequence(toc)) == NULL))
947	return;
948    if (strcmp(selectedseq->name, "all") == 0) {
949	Feep(XkbBI_MinorError,0,None);
950	return;
951    }
952    if (op == DELETE)
953	mlist = MakeNullMsgList();
954    else {
955	mlist = CurMsgListOrCurMsg(toc);
956	if (mlist->nummsgs == 0) {
957	    FreeMsgList(mlist);
958	    Feep(XkbBI_MinorError,0,None);
959	    return;
960	}
961    }
962    argv = MakeArgv(6 + mlist->nummsgs);
963    argv[0] = "mark";
964    argv[1] = TocMakeFolderName(toc);
965    argv[2] = "-sequence";
966    argv[3] = __UNCONST(selectedseq->name);
967    switch (op) {
968      case ADD:
969	argv[4] = "-add";
970	argv[5] = "-nozero";
971	break;
972      case REMOVE:
973	argv[4] = "-delete";
974	argv[5] = "-nozero";
975	break;
976      case DELETE:
977	argv[4] = "-delete";
978	argv[5] = "all";
979	break;
980    }
981    for (i = 0; i < mlist->nummsgs; i++) {
982	char *str;
983	XtAsprintf(&str, "%d", MsgGetId(mlist->msglist[i]));
984	argv[6 + i] = str;
985    }
986    DoCommand(argv, (char *) NULL, (char *) NULL);
987    for (i = 0; i < mlist->nummsgs; i++)
988        XtFree((char *) argv[6 + i]);
989    XtFree(argv[1]);
990    XtFree((char *) argv);
991    FreeMsgList(mlist);
992    TocReloadSeqLists(toc);
993}
994
995
996/*ARGSUSED*/
997void DoAddToSeq(
998    Widget	w,
999    XtPointer	client_data,
1000    XtPointer	call_data)
1001{
1002    Scrn	scrn = (Scrn) client_data;
1003    TwiddleSequence(scrn, ADD);
1004}
1005
1006
1007/*ARGSUSED*/
1008void XmhAddToSequence(
1009    Widget	w,
1010    XEvent	*event,
1011    String	*params,
1012    Cardinal	*num_params)
1013{
1014    Scrn scrn = ScrnFromWidget(w);
1015    if (! UserWantsAction(w, scrn))
1016	return;
1017    if ((strcmp(XtName(w), "sequenceMenu") == 0) &&
1018	(event->type == ButtonRelease) &&
1019	(XawSimpleMenuGetActiveEntry(w) == NULL))
1020	return;
1021    if (TocHasSequences(scrn->toc))
1022	TwiddleSequence(scrn, ADD);
1023}
1024
1025
1026/*ARGSUSED*/
1027void DoRemoveFromSeq(
1028    Widget	w,
1029    XtPointer	client_data,
1030    XtPointer	call_data)
1031{
1032    Scrn	scrn = (Scrn) client_data;
1033    TwiddleSequence(scrn, REMOVE);
1034}
1035
1036
1037/*ARGSUSED*/
1038void XmhRemoveFromSequence(
1039    Widget	w,
1040    XEvent	*event,
1041    String	*params,
1042    Cardinal	*num_params)
1043{
1044    Scrn scrn = ScrnFromWidget(w);
1045    if (UserWantsAction(w, scrn))
1046	if (TocHasSequences(scrn->toc))
1047	    TwiddleSequence(scrn, REMOVE);
1048}
1049
1050
1051/*ARGSUSED*/
1052void DoDeleteSeq(
1053    Widget	w,
1054    XtPointer	client_data,
1055    XtPointer	call_data)
1056{
1057    Scrn	scrn = (Scrn) client_data;
1058    TwiddleSequence(scrn, DELETE);
1059    TUCheckSequenceMenu(scrn->toc);
1060}
1061
1062
1063/*ARGSUSED*/
1064void XmhDeleteSequence(
1065    Widget	w,
1066    XEvent	*event,
1067    String	*params,
1068    Cardinal	*num_params)
1069{
1070    Scrn scrn = ScrnFromWidget(w);
1071    if (! UserWantsAction(w, scrn))
1072	return;
1073    if ((strcmp(XtName(w), "sequenceMenu") == 0) &&
1074	(event->type == ButtonRelease) &&
1075	(XawSimpleMenuGetActiveEntry(w) == NULL))
1076	return;
1077    if (TocHasSequences(scrn->toc))
1078	DoDeleteSeq(w, (XtPointer) scrn, (XtPointer) NULL);
1079}
1080