screen.c revision d859ff80
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    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[12];
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	    sprintf(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 = (Scrn *)
298	XtRealloc((char *) scrnList, (unsigned) numScrns*sizeof(Scrn));
299    scrn = scrnList[numScrns - 1] = XtNew(ScrnRec);
300    bzero((char *)scrn, sizeof(ScrnRec));
301    scrn->kind = kind;
302    if (numScrns == 1) scrn->parent = toplevel;
303    else scrn->parent = XtCreatePopupShell(
304				   progName, topLevelShellWidgetClass,
305				   toplevel, arglist, XtNumber(arglist));
306    XtAugmentTranslations(scrn->parent,
307			  app_resources.wm_protocols_translations);
308    scrn->widget =
309	XtCreateManagedWidget(progName, panedWidgetClass, scrn->parent,
310			      (ArgList) NULL, (Cardinal) 0);
311
312    switch (kind) {
313	case STtocAndView: 	MakeTocAndView(scrn); break;
314	case STview:		MakeView(scrn); break;
315	case STcomp:		MakeComp(scrn);	break;
316	default: break;
317    }
318
319    if (kind != STpick) {
320	int	theight, min, max;
321	Arg	args[1];
322
323	DEBUG("Realizing...")
324	XtRealizeWidget(scrn->parent);
325	DEBUG(" done.\n")
326
327	switch (kind) {
328	  case STtocAndView:
329	    BBoxLockSize(scrn->mainbuttons);
330	    BBoxLockSize(scrn->folderbuttons);
331	    theight = GetHeight(scrn->tocwidget) + GetHeight(scrn->viewwidget);
332	    theight = app_resources.toc_percentage * theight / 100;
333	    XawPanedGetMinMax((Widget) scrn->tocwidget, &min, &max);
334	    XawPanedSetMinMax((Widget) scrn->tocwidget, theight, theight);
335	    XawPanedSetMinMax((Widget) scrn->tocwidget, min, max);
336	    if (scrn->miscbuttons)
337		BBoxLockSize(scrn->miscbuttons);
338
339	    /* fall through */
340
341	  case STview:
342
343	    /* Install accelerators; not active while editing in the view */
344
345	    XtSetArg(args[0], XtNtranslations, &(scrn->edit_translations));
346	    XtGetValues(scrn->viewwidget, args, (Cardinal) 1);
347	    XtInstallAllAccelerators(scrn->widget, scrn->widget);
348	    if (kind == STtocAndView)
349		XtInstallAllAccelerators(scrn->tocwidget, scrn->widget);
350	    XtInstallAllAccelerators(scrn->viewwidget, scrn->widget);
351	    XtSetArg(args[0], XtNtranslations, &(scrn->read_translations));
352	    XtGetValues(scrn->viewwidget, args, (Cardinal) 1);
353
354	    if (kind == STview)
355		BBoxLockSize(scrn->viewbuttons);
356	    break;
357
358	  case STcomp:
359	    BBoxLockSize(scrn->viewbuttons);
360	    XtInstallAllAccelerators(scrn->viewwidget, scrn->widget);
361	    XtSetKeyboardFocus(scrn->parent, scrn->viewwidget);
362	    break;
363
364	  default:
365	    break;
366	}
367
368	InitBusyCursor(scrn);
369	XDefineCursor(XtDisplay(scrn->parent), XtWindow(scrn->parent),
370		      app_resources.cursor);
371	(void) XSetWMProtocols(XtDisplay(scrn->parent), XtWindow(scrn->parent),
372			       protocolList, XtNumber(protocolList));
373    }
374    scrn->mapped = False;
375    return scrn;
376}
377
378
379Scrn NewViewScrn(void)
380{
381    return CreateNewScrn(STview);
382}
383
384Scrn NewCompScrn(void)
385{
386    Scrn scrn;
387    scrn = CreateNewScrn(STcomp);
388    scrn->assocmsg = (Msg)NULL;
389    return scrn;
390}
391
392void ScreenSetAssocMsg(Scrn scrn, Msg msg)
393{
394    scrn->assocmsg = msg;
395}
396
397/* Destroy the screen.  If unsaved changes are in a msg, too bad. */
398
399void DestroyScrn(Scrn scrn)
400{
401    if (scrn->mapped) {
402	scrn->mapped = False;
403	XtPopdown(scrn->parent);
404	TocSetScrn((Toc) NULL, scrn);
405	MsgSetScrnForce((Msg) NULL, scrn);
406	lastInput.win = -1;
407    }
408}
409
410
411void MapScrn(Scrn scrn)
412{
413    if (!scrn->mapped) {
414	XtPopup(scrn->parent, XtGrabNone);
415	scrn->mapped = True;
416    }
417}
418
419
420Scrn ScrnFromWidget(Widget w) /* heavily used, should be efficient */
421{
422    register int i;
423    while (w && ! XtIsTopLevelShell(w))
424	w = XtParent(w);
425    if (w) {
426	for (i=0 ; i<numScrns ; i++) {
427	    if (w == (Widget) scrnList[i]->parent)
428		return scrnList[i];
429	}
430    }
431    Punt("ScrnFromWidget failed!");
432    return NULL;
433}
434
435
436/* Figure out which buttons should and shouldn't be enabled in the given
437 * screen.  This should be called whenever something major happens to the
438 * screen.
439 */
440
441
442/*ARGSUSED*/
443static void EnableCallback(Widget w, XtPointer data, XtPointer junk)
444{
445  EnableProperButtons( (Scrn) data);
446}
447
448#define SetButton(buttonbox, name, value) \
449    if (value) BBoxEnable(BBoxFindButtonNamed(buttonbox, name)); \
450    else BBoxDisable(BBoxFindButtonNamed(buttonbox, name));
451
452
453void EnableProperButtons(Scrn scrn)
454{
455    int value, changed, reapable;
456    Button	button;
457
458    if (scrn) {
459	switch (scrn->kind) {
460	  case STtocAndView:
461	    button = BBoxFindButtonNamed
462		(scrn->mainbuttons, MenuBoxButtons[XMH_TOC].button_name);
463	    value = TocCanIncorporate(scrn->toc);
464	    SendMenuEntryEnableMsg(button, "inc", value);
465
466	    button = BBoxFindButtonNamed
467		(scrn->mainbuttons, MenuBoxButtons[XMH_SEQUENCE].button_name);
468	    value = TocHasSequences(scrn->toc);
469	    SendMenuEntryEnableMsg(button, "openSeq", value);
470	    SendMenuEntryEnableMsg(button, "addToSeq", value);
471	    SendMenuEntryEnableMsg(button, "removeFromSeq", value);
472	    SendMenuEntryEnableMsg(button, "deleteSeq", value);
473
474	    button = BBoxFindButtonNamed
475		 (scrn->mainbuttons, MenuBoxButtons[XMH_VIEW].button_name);
476	    value = (scrn->msg != NULL && !MsgGetEditable(scrn->msg));
477	    SendMenuEntryEnableMsg(button, "edit", value);
478	    SendMenuEntryEnableMsg(button, "save",
479				   scrn->msg != NULL && !value);
480	    break;
481	  case STview:
482	    value = (scrn->msg != NULL && !MsgGetEditable(scrn->msg));
483	    SetButton(scrn->viewbuttons, "edit", value);
484	    SetButton(scrn->viewbuttons, "save", scrn->msg != NULL && !value);
485	    break;
486	  case STcomp:
487	    if (scrn->msg != NULL) {
488		changed = MsgChanged(scrn->msg);
489		reapable = MsgGetReapable(scrn->msg);
490		SetButton(scrn->viewbuttons, "send", changed || !reapable);
491		SetButton(scrn->viewbuttons, "save", changed || reapable);
492		SetButton(scrn->viewbuttons, "insert",
493			  scrn->assocmsg != NULL ? True : False);
494
495		if (!changed)
496		    MsgSetCallOnChange(scrn->msg, EnableCallback,
497				       (XtPointer) scrn);
498		else
499		    MsgSetCallOnChange(scrn->msg, (XtCallbackProc) NULL,
500				       (XtPointer) NULL);
501
502	    } else {
503		BBoxDisable( BBoxFindButtonNamed(scrn->viewbuttons, "send"));
504		BBoxDisable( BBoxFindButtonNamed(scrn->viewbuttons, "save"));
505		BBoxDisable( BBoxFindButtonNamed(scrn->viewbuttons, "insert"));
506	    }
507	    break;
508	  default:
509	    break;
510	}
511    }
512}
513