1/*
2 * $XConsortium: screen.c,v 2.65 95/01/06 16:39:19 swick Exp $
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/screen.c,v 1.2 2001/10/28 03:34:39 tsi Exp $ */
28
29/* scrn.c -- management of scrns. */
30
31#include "xmh.h"
32
33XmhMenuEntryRec	folderMenu[] = {
34    {"open",			DoOpenFolder},
35    {"openInNew", 		DoOpenFolderInNewWindow},
36    {"create",			DoCreateFolder},
37    {"delete",			DoDeleteFolder},
38    {"line",			(XtCallbackProc) NULL},
39    {"close",			DoClose},
40};
41
42XmhMenuEntryRec	tocMenu[] = {
43    {"inc",			DoIncorporateNewMail},
44    {"commit",			DoCommit},
45    {"pack",			DoPack},
46    {"sort",			DoSort},
47    {"rescan",			DoForceRescan},
48};
49
50XmhMenuEntryRec	messageMenu[] = {
51    {"compose",			DoComposeMessage},
52    {"next",			DoNextView},
53    {"prev",			DoPrevView},
54    {"delete",			DoDelete},
55    {"move",			DoMove},
56    {"copy",			DoCopy},
57    {"unmark",			DoUnmark},
58    {"viewNew",			DoViewNew},
59    {"reply",			DoReply},
60    {"forward",			DoForward},
61    {"useAsComp",		DoTocUseAsComp},
62    {"print",			DoPrint},
63};
64
65XmhMenuEntryRec	sequenceMenu[] = {
66    {"pick",			DoPickMessages},
67    {"openSeq",			DoOpenSeq},
68    {"addToSeq",		DoAddToSeq},
69    {"removeFromSeq",		DoRemoveFromSeq},
70    {"deleteSeq",		DoDeleteSeq},
71    {"line",			(XtCallbackProc) NULL},
72    {"all",			DoSelectSequence},
73};
74
75XmhMenuEntryRec	viewMenu[] = {
76    {"reply",			DoViewReply},
77    {"forward",			DoViewForward},
78    {"useAsComp",		DoViewUseAsComposition},
79    {"edit",			DoEditView},
80    {"save",			DoSaveView},
81    {"print",			DoPrintView},
82};
83
84XmhMenuEntryRec	optionMenu[] = {
85    {"reverse",			DoReverseReadOrder},
86};
87
88XmhMenuButtonDescRec	MenuBoxButtons[] = {
89    {"folderButton",	"folderMenu",	XMH_FOLDER,	folderMenu,
90	 XtNumber(folderMenu) },
91    {"tocButton",	"tocMenu",	XMH_TOC,	tocMenu,
92	 XtNumber(tocMenu) },
93    {"messageButton",	"messageMenu",	XMH_MESSAGE,	messageMenu,
94	 XtNumber(messageMenu) },
95    {"sequenceButton",	"sequenceMenu",	XMH_SEQUENCE,	sequenceMenu,
96	 XtNumber(sequenceMenu) },
97    {"viewButton",	"viewMenu",	XMH_VIEW,	viewMenu,
98	 XtNumber(viewMenu) },
99    {"optionButton",	"optionMenu",	XMH_OPTION,	optionMenu,
100	 XtNumber(optionMenu) },
101};
102
103
104/* Fill in the buttons for the view commands. */
105
106static void FillViewButtons(
107Scrn scrn)
108{
109    ButtonBox buttonbox = scrn->viewbuttons;
110    BBoxAddButton(buttonbox, "close", commandWidgetClass, True);
111    BBoxAddButton(buttonbox, "reply", commandWidgetClass, True);
112    BBoxAddButton(buttonbox, "forward", commandWidgetClass, True);
113    BBoxAddButton(buttonbox, "useAsComp", commandWidgetClass, True);
114    BBoxAddButton(buttonbox, "edit", commandWidgetClass, True);
115    BBoxAddButton(buttonbox, "save", commandWidgetClass, False);
116    BBoxAddButton(buttonbox, "print", commandWidgetClass, True);
117    BBoxAddButton(buttonbox, "delete", commandWidgetClass, True);
118}
119
120
121
122static void FillCompButtons(
123Scrn scrn)
124{
125    ButtonBox buttonbox = scrn->viewbuttons;
126    BBoxAddButton(buttonbox, "close", commandWidgetClass, True);
127    BBoxAddButton(buttonbox, "send", commandWidgetClass, True);
128    BBoxAddButton(buttonbox, "reset", commandWidgetClass, True);
129    BBoxAddButton(buttonbox, "compose", commandWidgetClass, True);
130    BBoxAddButton(buttonbox, "save", commandWidgetClass, True);
131    BBoxAddButton(buttonbox, "insert", commandWidgetClass, True);
132}
133
134
135static void MakeCommandMenu(
136    Scrn		scrn,
137    XmhMenuButtonDesc	mbd)
138{
139    register Cardinal i;
140    Cardinal	 n;
141    Widget	menu;
142    ButtonBox	buttonbox = scrn->mainbuttons;
143    XmhMenuEntry	e;
144    Boolean	indent;
145    WidgetClass	widgetclass;
146    Arg		args[4];
147    static XtCallbackRec callbacks[] = {
148	{ (XtCallbackProc) NULL, (XtPointer) NULL},
149	{ (XtCallbackProc) NULL, (XtPointer) NULL},
150	{ (XtCallbackProc) NULL, (XtPointer) NULL},
151    };
152
153    /* Menus are created as children of the Paned widget of the scrn in order
154     * that they can be used both as pop-up and as pull-down menus.
155     */
156
157    n = 0;
158    if (mbd->id == XMH_SEQUENCE) {
159	XtSetArg(args[n], XtNallowShellResize, True); 	n++;
160    }
161    menu = XtCreatePopupShell(mbd->menu_name, simpleMenuWidgetClass,
162			      scrn->widget, args, n);
163
164    indent = (mbd->id == XMH_SEQUENCE || mbd->id == XMH_OPTION) ? True : False;
165    e = mbd->entry;
166    for (i=0; i < mbd->num_entries; i++, e++) {
167	n = 0;
168	if (e->function) {
169	    callbacks[0].callback = e->function;
170	    callbacks[0].closure  = (XtPointer) scrn;
171	    callbacks[1].callback = (app_resources.sticky_menu
172				     ? (XtCallbackProc) DoRememberMenuSelection
173				     : (XtCallbackProc) NULL);
174	    XtSetArg(args[n], XtNcallback, callbacks);	n++;
175
176	    if (indent) { XtSetArg(args[n], XtNleftMargin, 18);	n++; }
177	    widgetclass = smeBSBObjectClass;
178	} else
179	    widgetclass = smeLineObjectClass;
180	XtCreateManagedWidget(e->name, widgetclass, menu, args, n);
181    }
182
183    AttachMenuToButton( BBoxFindButtonNamed( buttonbox, mbd->button_name),
184		       menu, mbd->menu_name);
185    if (mbd->id == XMH_OPTION && app_resources.reverse_read_order)
186	ToggleMenuItem(XtNameToWidget(menu, "reverse"), True);
187}
188
189
190/* Create subwidgets for a toc&view window. */
191
192static void MakeTocAndView(Scrn scrn)
193{
194    register int	i;
195    XmhMenuButtonDesc	mbd;
196    ButtonBox		buttonbox;
197    const char		*name;
198    static XawTextSelectType sarray[] = {XawselectLine,
199					XawselectPosition,
200					XawselectAll,
201					XawselectNull};
202    static Arg args[] = {
203	{ XtNselectTypes,	(XtArgVal) sarray},
204	{ XtNdisplayCaret,	(XtArgVal) False}
205    };
206
207    scrn->mainbuttons   = BBoxCreate(scrn, "menuBox");
208    scrn->folderlabel   = CreateTitleBar(scrn, "folderTitlebar");
209    scrn->folderbuttons = BBoxCreate(scrn, "folders");
210    scrn->toclabel      = CreateTitleBar(scrn, "tocTitlebar");
211    scrn->tocwidget	= CreateTextSW(scrn, "toc", args, XtNumber(args));
212    if (app_resources.command_button_count > 0)
213	scrn->miscbuttons = BBoxCreate(scrn, "commandBox");
214    scrn->viewlabel     = CreateTitleBar(scrn, "viewTitlebar");
215    scrn->viewwidget    = CreateTextSW(scrn, "view", args, (Cardinal) 0);
216
217    /* the command buttons and menus */
218
219    buttonbox = scrn->mainbuttons;
220    mbd = MenuBoxButtons;
221    for (i=0; i < XtNumber(MenuBoxButtons); i++, mbd++) {
222	name = mbd->button_name;
223	BBoxAddButton(buttonbox, name, menuButtonWidgetClass, True);
224	MakeCommandMenu(scrn, mbd);
225    }
226
227    /* the folder buttons; folder menus are created on demand. */
228
229    buttonbox = scrn->folderbuttons;
230    for (i=0 ; i<numFolders ; i++) {
231	name = TocName(folderList[i]);
232	if (! IsSubfolder(name))
233	    BBoxAddButton(buttonbox, name, menuButtonWidgetClass, True);
234	if (app_resources.new_mail_check &&
235	    numScrns > 1 &&
236	    TocCanIncorporate(folderList[i]))
237	    BBoxMailFlag(buttonbox, name, TocHasMail(folderList[i]));
238    }
239
240    /* the optional miscellaneous command buttons */
241
242    if (app_resources.command_button_count > 0) {
243	char	name[18];
244	if (app_resources.command_button_count > 500)
245	    app_resources.command_button_count = 500;
246	for (i=1; i <= app_resources.command_button_count; i++) {
247	    snprintf(name, sizeof(name), "button%d", i);
248	    BBoxAddButton(scrn->miscbuttons, name, commandWidgetClass, True);
249	}
250    }
251}
252
253static void MakeView(Scrn scrn)
254{
255    scrn->viewlabel = CreateTitleBar(scrn, "viewTitlebar");
256    scrn->viewwidget = CreateTextSW(scrn, "view", (ArgList)NULL, (Cardinal)0);
257    scrn->viewbuttons = BBoxCreate(scrn, "viewButtons");
258    FillViewButtons(scrn);
259}
260
261
262static void MakeComp(Scrn scrn)
263{
264    scrn->viewlabel = CreateTitleBar(scrn, "composeTitlebar");
265    scrn->viewwidget = CreateTextSW(scrn, "comp", (ArgList)NULL, (Cardinal)0);
266    scrn->viewbuttons = BBoxCreate(scrn, "compButtons");
267    FillCompButtons(scrn);
268}
269
270
271/* Create a scrn of the given type. */
272
273Scrn CreateNewScrn(ScrnKind kind)
274{
275    int i;
276    Scrn scrn;
277    static Arg arglist[] = {
278	{ XtNgeometry,	(XtArgVal) NULL},
279	{ XtNinput,	(XtArgVal) True}
280    };
281
282    for (i=0 ; i<numScrns ; i++)
283	if (scrnList[i]->kind == kind && !scrnList[i]->mapped)
284	    return scrnList[i];
285    switch (kind) {
286       case STtocAndView: arglist[0].value =
287			   (XtArgVal)app_resources.toc_geometry;	break;
288       case STview:	  arglist[0].value =
289			   (XtArgVal)app_resources.view_geometry;	break;
290       case STcomp:	  arglist[0].value =
291			   (XtArgVal)app_resources.comp_geometry;	break;
292       case STpick:	  arglist[0].value =
293			   (XtArgVal)app_resources.pick_geometry;	break;
294    }
295
296    numScrns++;
297    scrnList = XtReallocArray(scrnList, numScrns, sizeof(Scrn));
298    scrn = scrnList[numScrns - 1] = XtNew(ScrnRec);
299    bzero((char *)scrn, sizeof(ScrnRec));
300    scrn->kind = kind;
301    if (numScrns == 1) scrn->parent = toplevel;
302    else scrn->parent = XtCreatePopupShell(
303				   progName, topLevelShellWidgetClass,
304				   toplevel, arglist, XtNumber(arglist));
305    XtAugmentTranslations(scrn->parent,
306			  app_resources.wm_protocols_translations);
307    scrn->widget =
308	XtCreateManagedWidget(progName, panedWidgetClass, scrn->parent,
309			      (ArgList) NULL, (Cardinal) 0);
310
311    switch (kind) {
312	case STtocAndView: 	MakeTocAndView(scrn); break;
313	case STview:		MakeView(scrn); break;
314	case STcomp:		MakeComp(scrn);	break;
315	default: break;
316    }
317
318    if (kind != STpick) {
319	int	theight, min, max;
320	Arg	args[1];
321
322	DEBUG("Realizing...")
323	XtRealizeWidget(scrn->parent);
324	DEBUG(" done.\n")
325
326	switch (kind) {
327	  case STtocAndView:
328	    BBoxLockSize(scrn->mainbuttons);
329	    BBoxLockSize(scrn->folderbuttons);
330	    theight = GetHeight(scrn->tocwidget) + GetHeight(scrn->viewwidget);
331	    theight = app_resources.toc_percentage * theight / 100;
332	    XawPanedGetMinMax((Widget) scrn->tocwidget, &min, &max);
333	    XawPanedSetMinMax((Widget) scrn->tocwidget, theight, theight);
334	    XawPanedSetMinMax((Widget) scrn->tocwidget, min, max);
335	    if (scrn->miscbuttons)
336		BBoxLockSize(scrn->miscbuttons);
337
338	    /* fall through */
339
340	  case STview:
341
342	    /* Install accelerators; not active while editing in the view */
343
344	    XtSetArg(args[0], XtNtranslations, &(scrn->edit_translations));
345	    XtGetValues(scrn->viewwidget, args, (Cardinal) 1);
346	    XtInstallAllAccelerators(scrn->widget, scrn->widget);
347	    if (kind == STtocAndView)
348		XtInstallAllAccelerators(scrn->tocwidget, scrn->widget);
349	    XtInstallAllAccelerators(scrn->viewwidget, scrn->widget);
350	    XtSetArg(args[0], XtNtranslations, &(scrn->read_translations));
351	    XtGetValues(scrn->viewwidget, args, (Cardinal) 1);
352
353	    if (kind == STview)
354		BBoxLockSize(scrn->viewbuttons);
355	    break;
356
357	  case STcomp:
358	    BBoxLockSize(scrn->viewbuttons);
359	    XtInstallAllAccelerators(scrn->viewwidget, scrn->widget);
360	    XtSetKeyboardFocus(scrn->parent, scrn->viewwidget);
361	    break;
362
363	  default:
364	    break;
365	}
366
367	InitBusyCursor(scrn);
368	XDefineCursor(XtDisplay(scrn->parent), XtWindow(scrn->parent),
369		      app_resources.cursor);
370	(void) XSetWMProtocols(XtDisplay(scrn->parent), XtWindow(scrn->parent),
371			       protocolList, XtNumber(protocolList));
372    }
373    scrn->mapped = False;
374    return scrn;
375}
376
377
378Scrn NewViewScrn(void)
379{
380    return CreateNewScrn(STview);
381}
382
383Scrn NewCompScrn(void)
384{
385    Scrn scrn;
386    scrn = CreateNewScrn(STcomp);
387    scrn->assocmsg = (Msg)NULL;
388    return scrn;
389}
390
391void ScreenSetAssocMsg(Scrn scrn, Msg msg)
392{
393    scrn->assocmsg = msg;
394}
395
396/* Destroy the screen.  If unsaved changes are in a msg, too bad. */
397
398void DestroyScrn(Scrn scrn)
399{
400    if (scrn->mapped) {
401	scrn->mapped = False;
402	XtPopdown(scrn->parent);
403	TocSetScrn((Toc) NULL, scrn);
404	MsgSetScrnForce((Msg) NULL, scrn);
405	lastInput.win = -1;
406    }
407}
408
409
410void MapScrn(Scrn scrn)
411{
412    if (!scrn->mapped) {
413	XtPopup(scrn->parent, XtGrabNone);
414	scrn->mapped = True;
415    }
416}
417
418
419Scrn ScrnFromWidget(Widget w) /* heavily used, should be efficient */
420{
421    register int i;
422    while (w && ! XtIsTopLevelShell(w))
423	w = XtParent(w);
424    if (w) {
425	for (i=0 ; i<numScrns ; i++) {
426	    if (w == (Widget) scrnList[i]->parent)
427		return scrnList[i];
428	}
429    }
430    Punt("ScrnFromWidget failed!");
431    return NULL;
432}
433
434
435/* Figure out which buttons should and shouldn't be enabled in the given
436 * screen.  This should be called whenever something major happens to the
437 * screen.
438 */
439
440
441/*ARGSUSED*/
442static void EnableCallback(Widget w, XtPointer data, XtPointer junk)
443{
444  EnableProperButtons( (Scrn) data);
445}
446
447#define SetButton(buttonbox, name, value) \
448    if (value) BBoxEnable(BBoxFindButtonNamed(buttonbox, name)); \
449    else BBoxDisable(BBoxFindButtonNamed(buttonbox, name));
450
451
452void EnableProperButtons(Scrn scrn)
453{
454    int value, changed, reapable;
455    Button	button;
456
457    if (scrn) {
458	switch (scrn->kind) {
459	  case STtocAndView:
460	    button = BBoxFindButtonNamed
461		(scrn->mainbuttons, MenuBoxButtons[XMH_TOC].button_name);
462	    value = TocCanIncorporate(scrn->toc);
463	    SendMenuEntryEnableMsg(button, "inc", value);
464
465	    button = BBoxFindButtonNamed
466		(scrn->mainbuttons, MenuBoxButtons[XMH_SEQUENCE].button_name);
467	    value = TocHasSequences(scrn->toc);
468	    SendMenuEntryEnableMsg(button, "openSeq", value);
469	    SendMenuEntryEnableMsg(button, "addToSeq", value);
470	    SendMenuEntryEnableMsg(button, "removeFromSeq", value);
471	    SendMenuEntryEnableMsg(button, "deleteSeq", value);
472
473	    button = BBoxFindButtonNamed
474		 (scrn->mainbuttons, MenuBoxButtons[XMH_VIEW].button_name);
475	    value = (scrn->msg != NULL && !MsgGetEditable(scrn->msg));
476	    SendMenuEntryEnableMsg(button, "edit", value);
477	    SendMenuEntryEnableMsg(button, "save",
478				   scrn->msg != NULL && !value);
479	    break;
480	  case STview:
481	    value = (scrn->msg != NULL && !MsgGetEditable(scrn->msg));
482	    SetButton(scrn->viewbuttons, "edit", value);
483	    SetButton(scrn->viewbuttons, "save", scrn->msg != NULL && !value);
484	    break;
485	  case STcomp:
486	    if (scrn->msg != NULL) {
487		changed = MsgChanged(scrn->msg);
488		reapable = MsgGetReapable(scrn->msg);
489		SetButton(scrn->viewbuttons, "send", changed || !reapable);
490		SetButton(scrn->viewbuttons, "save", changed || reapable);
491		SetButton(scrn->viewbuttons, "insert",
492			  scrn->assocmsg != NULL ? True : False);
493
494		if (!changed)
495		    MsgSetCallOnChange(scrn->msg, EnableCallback,
496				       (XtPointer) scrn);
497		else
498		    MsgSetCallOnChange(scrn->msg, (XtCallbackProc) NULL,
499				       (XtPointer) NULL);
500
501	    } else {
502		BBoxDisable( BBoxFindButtonNamed(scrn->viewbuttons, "send"));
503		BBoxDisable( BBoxFindButtonNamed(scrn->viewbuttons, "save"));
504		BBoxDisable( BBoxFindButtonNamed(scrn->viewbuttons, "insert"));
505	    }
506	    break;
507	  default:
508	    break;
509	}
510    }
511}
512