util.c revision f14f4646
1/* $XConsortium: util.c,v 1.16 92/08/12 16:46:22 converse Exp $ */
2
3/*
4 *			  COPYRIGHT 1987
5 *		   DIGITAL EQUIPMENT CORPORATION
6 *		       MAYNARD, MASSACHUSETTS
7 *			ALL RIGHTS RESERVED.
8 *
9 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
10 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
11 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
12 * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
13 *
14 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
15 * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
16 * SET FORTH ABOVE.
17 *
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/xedit/util.c,v 1.26 2003/05/07 20:54:43 herrb Exp $ */
28
29#include <stdio.h>
30#include <stdarg.h>
31
32#include <libgen.h>		/* POSIX basename() */
33#include <stdlib.h>		/* for realpath() */
34#include <errno.h>		/* for ENOENT */
35#include "xedit.h"
36
37#include <X11/Xfuncs.h>
38#include <X11/Xos.h>		/* for types.h */
39
40#include <sys/stat.h>
41#include <X11/Xmu/CharSet.h>
42#include <X11/Xaw/SmeBSB.h>
43#include <X11/Xaw/SimpleMenu.h>
44
45/*
46 * Prototypes
47 */
48static void SwitchSourceCallback(Widget, XtPointer, XtPointer);
49static int WindowIndex(Widget);
50static void ChangeTextWindow(Widget);
51
52/*
53 * External
54 */
55extern void _XawTextShowPosition(TextWidget);
56
57/*
58 * Initialization
59 */
60extern Widget scratch;
61extern Widget vpanes[2], labels[3], texts[3], forms[3];
62extern XawTextWrapMode wrapmodes[3];
63
64#ifndef va_copy
65# ifdef __va_copy
66#  define va_copy __va_copy
67# else
68#  error "no working va_copy was found"
69# endif
70#endif
71
72/*
73 * Implementation
74 */
75void
76XeditPrintf(const char *format, ...)
77{
78    static struct {
79	XawTextPosition	last;
80	int		size;
81	int		length;
82	int		repeat;
83	char		*buffer;
84    } info;
85
86    size_t		size;
87    va_list		va;
88    XawTextBlock	text;
89    XawTextPosition	left, right;
90    char		buffer[BUFSIZ];
91    char		*string, rbuffer[32];
92
93    va_start(va, format);
94    size = vsnprintf(buffer, sizeof(buffer), format, va);
95    va_end(va);
96
97    /* Should never happen... */
98    if (size >= sizeof(buffer)) {
99	strcpy(buffer + sizeof(buffer) - 5, "...\n");
100	size = sizeof(buffer) - 1;
101    }
102    else if (size) {
103	left = right = XawTextSourceScan(XawTextGetSource(messwidget),
104					 0, XawstAll, XawsdRight, 1, True);
105
106	if (left == info.last &&
107	    info.buffer &&
108	    strcmp(buffer, info.buffer) == 0) {
109	    string = rbuffer;
110	    if (info.repeat == 1)
111		left -= info.buffer[strlen(info.buffer) - 1] == '\n';
112	    else
113		left -= info.length;
114	    size = info.length = XmuSnprintf(rbuffer, sizeof(rbuffer),
115					     " [%d times]\n", ++info.repeat);
116	}
117	else {
118	    string = buffer;
119	    if (size >= info.size)
120		info.buffer = XtMalloc(size + 1);
121	    strcpy(info.buffer, buffer);
122	    info.repeat = 1;
123	}
124
125	text.length = size;
126	text.ptr = string;
127	text.firstPos = 0;
128	text.format = FMT8BIT;
129
130	XawTextReplace(messwidget, left, right, &text);
131
132	info.last = left + text.length;
133	XawTextSetInsertionPoint(messwidget, info.last);
134    }
135}
136
137Widget
138MakeCommandButton(Widget box, char *name, XtCallbackProc function)
139{
140  Widget w = XtCreateManagedWidget(name, commandWidgetClass, box, NULL, ZERO);
141  if (function != NULL)
142    XtAddCallback(w, XtNcallback, function, (caddr_t) NULL);
143  else
144    XtVaSetValues(w, XtNsensitive, False, NULL);
145  return w;
146}
147
148Widget
149MakeStringBox(Widget parent, String name, String string)
150{
151  Arg args[5];
152  Cardinal numargs = 0;
153  Widget StringW;
154
155  XtSetArg(args[numargs], XtNeditType, XawtextEdit); numargs++;
156  XtSetArg(args[numargs], XtNstring, string); numargs++;
157
158  StringW = XtCreateManagedWidget(name, asciiTextWidgetClass,
159				  parent, args, numargs);
160  return(StringW);
161}
162
163/*	Function Name: GetString
164 *	Description: retrieves the string from a asciiText widget.
165 *	Arguments: w - the ascii text widget.
166 *	Returns: the filename.
167 */
168
169String
170GetString(Widget w)
171{
172  String str;
173  Arg arglist[1];
174
175  XtSetArg(arglist[0], XtNstring, &str);
176  XtGetValues( w, arglist, ONE);
177  return(str);
178}
179
180/*	Function Name: MaybeCreateFile
181 *	Description: Checks to see if file exists, and if not, creates it.
182 *	Arguments: file - name of file to check.
183 *	Returns: permissions status
184 */
185
186FileAccess
187MaybeCreateFile(char *file)
188{
189    Boolean exists;
190    int fd;
191
192    if (access(file, F_OK) != 0) {
193	fd = creat(file, 0666);
194	if (fd != -1)
195	    close(fd);
196    }
197
198    return(CheckFilePermissions(file, &exists));
199}
200
201
202FileAccess
203CheckFilePermissions(char *file, Boolean *exists)
204{
205    char temp[BUFSIZ], *ptr;
206
207    if (access(file, F_OK) == 0) {
208	*exists = TRUE;
209
210	if (access(file, R_OK) != 0)
211	    return(NO_READ);
212
213	if (access(file, R_OK | W_OK) == 0)
214	    return(WRITE_OK);
215	return(READ_OK);
216    }
217
218    *exists = FALSE;
219
220    strncpy(temp, file, sizeof(temp) - 1);
221    temp[sizeof(temp) - 1] = '\0';
222    if ( (ptr = rindex(temp, '/')) == NULL)
223	strcpy(temp, ".");
224    else
225	*ptr = '\0';
226
227    if (access(temp, R_OK | W_OK | X_OK) == 0)
228	return(WRITE_OK);
229    return(NO_READ);
230}
231
232xedit_flist_item *
233AddTextSource(Widget source, char *name, char *filename, int flags,
234	      FileAccess file_access)
235{
236    xedit_flist_item *item;
237    char *wid_name;
238
239    item = (xedit_flist_item*)XtMalloc(sizeof(xedit_flist_item));
240    item->source = source;
241    item->name = XtNewString(name);
242    item->filename = XtNewString(filename);
243    item->flags = flags;
244    item->file_access = file_access;
245    item->display_position = item->insert_position = 0;
246    item->mode = 0;
247    item->mtime = 0;
248    item->properties = NULL;
249    item->xldata = NULL;
250    /* Try to load associated tags file */
251    SearchTagsFile(item);
252
253    flist.itens = (xedit_flist_item**)
254	XtRealloc((char*)flist.itens, sizeof(xedit_flist_item*)
255		  * (flist.num_itens + 1));
256
257    flist.itens[flist.num_itens++] = item;
258
259    if (!flist.popup) {
260	flist.popup = XtCreatePopupShell("fileMenu", simpleMenuWidgetClass,
261					 topwindow, NULL, 0);
262	/* XXX hack: this don't allow setting the geometry of the popup widget
263	 * as it will override any settings when a menu entry is inserted
264	 * or deleted, but saves us the trouble generated by a resource
265	 * setting like: '*geometry: <width>x<height>'
266	 */
267	XtRealizeWidget(flist.popup);
268    }
269    if ((wid_name = strrchr(item->name, '/')) == NULL)
270	wid_name = item->name;
271    else
272	++wid_name;
273    item->sme = XtVaCreateManagedWidget(wid_name, smeBSBObjectClass,
274					flist.popup, XtNlabel, item->filename,
275					NULL, NULL);
276    XtAddCallback(item->sme, XtNcallback,
277		  SwitchSourceCallback, (XtPointer)item);
278
279    SetTextProperties(item);
280
281    return (item);
282}
283
284Bool
285KillTextSource(xedit_flist_item *item)
286{
287    xedit_flist_item *nitem = NULL;
288    unsigned idx, i;
289    Arg targs[3];
290    Cardinal tnum_args;
291    Arg largs[2];
292    Cardinal lnum_args;
293    char label_buf[BUFSIZ];
294
295    for (idx = 0; idx < flist.num_itens; idx++)
296	if (flist.itens[idx] == item) {
297	    if (idx + 1 < flist.num_itens)
298		nitem = flist.itens[idx + 1];
299	    else if (idx >= 1)
300		nitem = flist.itens[idx - 1];
301	    break;
302	}
303
304    if (idx >= flist.num_itens)
305	return (False);
306
307    flist.current = nitem;
308    if (item == flist.other)
309	flist.other = NULL;
310
311    if (nitem->file_access == READ_OK)
312	XmuSnprintf(label_buf, sizeof(label_buf), "%s       READ ONLY",
313		    nitem->name);
314    else if (nitem->file_access == WRITE_OK)
315	XmuSnprintf(label_buf, sizeof(label_buf), "%s       Read - Write",
316		    nitem->name);
317    lnum_args = 0;
318    XtSetArg(largs[lnum_args], XtNlabel, label_buf);		++lnum_args;
319    if (nitem->flags & CHANGED_BIT)
320	XtSetArg(largs[lnum_args], XtNleftBitmap, flist.pixmap);
321    else
322	XtSetArg(largs[lnum_args], XtNleftBitmap, None);
323    ++lnum_args;
324
325    tnum_args = 0;
326    XtSetArg(targs[tnum_args], XtNtextSource,
327	     nitem->source);				++tnum_args;
328    XtSetArg(targs[tnum_args], XtNdisplayPosition,
329	     nitem->display_position);			++tnum_args;
330    XtSetArg(targs[tnum_args], XtNinsertPosition,
331	     nitem->insert_position);			++tnum_args;
332    for (i = 0; i < 3; i++)
333	if (XawTextGetSource(texts[i]) == item->source) {
334	    XtSetValues(labels[i], largs, lnum_args);
335	    XawTextDisableRedisplay(texts[i]);
336	    XtSetValues(texts[i], targs, tnum_args);
337
338	    UpdateTextProperties(0);
339
340	    _XawTextShowPosition((TextWidget)texts[i]);
341	    XawTextEnableRedisplay(texts[i]);
342	    if (texts[i] == textwindow) {
343		Arg args[1];
344
345		if (nitem->source != scratch)
346		    XtSetArg(args[0], XtNstring, nitem->name);
347		else
348		    XtSetArg(args[0], XtNstring, NULL);
349		XtSetValues(filenamewindow, args, 1);
350	    }
351	}
352
353    UnsetTextProperties(item);
354    XtFree(item->name);
355    XtFree(item->filename);
356    XtDestroyWidget(item->sme);
357    XtDestroyWidget(item->source);
358    XtFree((char*)item);
359
360    if (idx < flist.num_itens - 1)
361	memmove(&flist.itens[idx], &flist.itens[idx + 1],
362		(flist.num_itens - idx) * sizeof(xedit_flist_item*));
363
364    --flist.num_itens;
365
366    return (True);
367}
368
369xedit_flist_item *
370FindTextSource(Widget source, char *filename)
371{
372    unsigned i;
373
374    if (source) {
375	for (i = 0; i < flist.num_itens; i++)
376	    if (flist.itens[i]->source == source)
377		return (flist.itens[i]);
378    }
379    else if (filename) {
380	for (i = 0; i < flist.num_itens; i++)
381	    if (strcmp(flist.itens[i]->filename, filename) == 0)
382		return (flist.itens[i]);
383    }
384
385    return (NULL);
386}
387
388void
389SwitchTextSource(xedit_flist_item *item)
390{
391    Arg args[4];
392    Cardinal num_args;
393    char label_buf[BUFSIZ];
394    xedit_flist_item *old_item =
395	FindTextSource(XawTextGetSource(textwindow), NULL);
396    int i;
397
398    if (old_item != item)
399	flist.other = old_item;
400    flist.current = item;
401
402    XawTextDisableRedisplay(textwindow);
403    if (item->file_access == READ_OK)
404	XmuSnprintf(label_buf, sizeof(label_buf), "%s       READ ONLY",
405		    item->name);
406    else if (item->file_access == WRITE_OK)
407	XmuSnprintf(label_buf, sizeof(label_buf), "%s       Read - Write",
408		    item->name);
409    num_args = 0;
410    XtSetArg(args[num_args], XtNlabel, label_buf);		++num_args;
411    if (item->flags & CHANGED_BIT)
412	XtSetArg(args[num_args], XtNleftBitmap, flist.pixmap);
413    else
414	XtSetArg(args[num_args], XtNleftBitmap, None);
415    ++num_args;
416    XtSetValues(labelwindow, args, num_args);
417
418    for (i = 0; i < 3; i++)
419	if (XawTextGetSource(texts[i]) == item->source
420	    && XtIsManaged(texts[i]))
421	    break;
422
423    if (i < 3) {
424	num_args = 0;
425	XtSetArg(args[num_args], XtNdisplayPosition,
426	     &(item->display_position));			++num_args;
427	XtSetArg(args[num_args], XtNinsertPosition,
428	     &(item->insert_position));				++num_args;
429	XtGetValues(texts[i], args, num_args);
430    }
431    if (old_item != item) {
432	int count, idx = 0;
433
434	num_args = 0;
435	XtSetArg(args[num_args], XtNdisplayPosition,
436	     &(old_item->display_position));			++num_args;
437	XtSetArg(args[num_args], XtNinsertPosition,
438	     &(old_item->insert_position));			++num_args;
439	XtGetValues(textwindow, args, num_args);
440
441	for (count = 0, i = 0; i < 3; i++)
442	    if (XawTextGetSource(texts[i]) == old_item->source
443		&& XtIsManaged(texts[i])) {
444		if (++count > 1)
445		    break;
446		idx = i;
447	    }
448
449	if (count == 1) {
450	    num_args = 0;
451	    XtSetArg(args[num_args], XtNdisplayPosition,
452		     &(old_item->display_position));		++num_args;
453		XtSetArg(args[num_args], XtNinsertPosition,
454		     &(old_item->insert_position));		++num_args;
455	    XtGetValues(texts[idx], args, num_args);
456	}
457    }
458
459    num_args = 0;
460    XtSetArg(args[num_args], XtNtextSource, item->source);	++num_args;
461    XtSetArg(args[num_args], XtNdisplayPosition, item->display_position);
462    ++num_args;
463    XtSetArg(args[num_args], XtNinsertPosition, item->insert_position);
464    ++num_args;
465    if (item->flags & WRAP_BIT)
466	XtSetArg(args[num_args], XtNwrap, item->wrap);
467    else
468	XtSetArg(args[num_args], XtNwrap, wrapmodes[WindowIndex(textwindow)]);
469    ++num_args;
470    XtSetValues(textwindow, args, num_args);
471
472    UpdateTextProperties(0);
473
474    _XawTextShowPosition((TextWidget)textwindow);
475    XawTextEnableRedisplay(textwindow);
476
477    num_args = 0;
478    if (item->source != scratch) {
479	XtSetArg(args[num_args], XtNstring, item->name);	++num_args;
480    }
481    else {
482	XtSetArg(args[num_args], XtNstring, NULL);		++num_args;
483    }
484    XtSetValues(filenamewindow, args, num_args);
485    /* XXX This probably should be done by the TextWidget, i.e. notice
486     * if the cursor became inivisible due to an horizontal scroll */
487    _XawTextShowPosition((TextWidget)filenamewindow);
488}
489
490char *
491ResolveName(char *filename)
492{
493#ifndef __UNIXOS2__
494    static char *name;
495    char	*result, *tmp = name;
496#endif
497
498    if (filename == NULL)
499	filename = GetString(filenamewindow);
500
501#ifndef __UNIXOS2__
502    /* Ensure not passing the same pointer again to realpath */
503    name = XtMalloc(BUFSIZ);
504    XtFree(tmp);
505    result = realpath(filename, name);
506
507    if (result == NULL && errno == ENOENT) {
508	int	length;
509	char	*dir, *file;
510
511	length = strlen(filename);
512	tmp = dir = XtMalloc(length + 1);
513	strcpy(dir, filename);
514
515	file = basename(filename);
516	dir = dirname(tmp);
517
518	/* Creating a new file? */
519	if (dir && file && strcmp(dir, file) &&
520	    access(dir, F_OK) == 0 &&
521	    (result = realpath(dir, name)) == name) {
522	    int	length = strlen(result);
523
524	    XmuSnprintf(result + length, BUFSIZ - length, "%s%s",
525			dir[length - 1] == '/' ? "" : "/", file);
526	}
527
528	XtFree(tmp);
529    }
530
531    return (result);
532#else
533    return filename;
534#endif
535}
536
537static void
538ChangeTextWindow(Widget w)
539{
540    Arg args[1];
541
542    if (textwindow != w) {
543	xedit_flist_item *other, *current;
544
545	other = FindTextSource(XawTextGetSource(textwindow), NULL);
546	current = FindTextSource(XawTextGetSource(w), NULL);
547	if (other != current)
548	    flist.other = other;
549	if (current)
550	    flist.current = current;
551	XtSetArg(args[0], XtNdisplayCaret, False);
552	XtSetValues(textwindow, args, 1);
553	XtSetArg(args[0], XtNdisplayCaret, True);
554	XtSetValues(w, args, 1);
555	XawTextUnsetSelection(textwindow);
556	textwindow = w;
557    }
558}
559
560/*ARGSUSED*/
561void
562XeditFocus(Widget w, XEvent *event, String *params, Cardinal *num_params)
563{
564    Arg args[1];
565    xedit_flist_item *item;
566    int idx = WindowIndex(w);
567
568    XtSetKeyboardFocus(topwindow, w);
569
570    ChangeTextWindow(w);
571
572    labelwindow = labels[idx];
573    item = FindTextSource(XawTextGetSource(textwindow), NULL);
574
575    if (item->source != scratch)
576	XtSetArg(args[0], XtNstring, item->name);
577    else
578	XtSetArg(args[0], XtNstring, NULL);
579
580    XtSetValues(filenamewindow, args, 1);
581
582    line_edit = False;
583}
584
585void
586PopupMenu(Widget w, XEvent *event, String *params, Cardinal *num_params)
587{
588    Cardinal n_params = num_params ? *num_params : 0;
589
590    if (*num_params && XmuCompareISOLatin1(*params, "editMenu") == 0)
591	SetEditMenu();
592
593    XtCallActionProc(w, "XawPositionSimpleMenu", event, params, n_params);
594    XtCallActionProc(w, "XtMenuPopup", event, params, n_params);
595}
596
597/*ARGSUSED*/
598static void
599SwitchSourceCallback(Widget entry, XtPointer client_data, XtPointer call_data)
600{
601    SwitchTextSource((xedit_flist_item*)client_data);
602}
603
604static int
605WindowIndex(Widget w)
606{
607    int i;
608
609    for (i = 0; i < 3; i++)
610	if (texts[i] == w)
611	    return (i);
612
613    return (-1);
614}
615
616void
617DeleteWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
618{
619    Widget unmanage[2];
620    int idx = WindowIndex(w), uidx;
621    Bool current = False;
622
623    if (*num_params == 1 && (*params[0] == 'd' || *params[0] == 'D')) {
624	if (XtIsManaged(XtParent(dirwindow)))
625	    SwitchDirWindow(False);
626	return;
627    }
628
629    if (idx < 0 || (!XtIsManaged(texts[1]) && !XtIsManaged(texts[2]))) {
630	Feep();
631	return;
632    }
633
634    if (num_params && *num_params == 1 &&
635	(*params[0] == 'o' || *params[0] == 'O'))
636	current = True;
637
638    uidx = XtIsManaged(texts[1]) ? 1 : 2;
639
640    unmanage[0] = forms[uidx];
641    unmanage[1] = texts[uidx];
642    XtUnmanageChildren(unmanage, 2);
643
644    if (!XtIsManaged(texts[2]))
645	XtUnmanageChild(vpanes[1]);
646
647    if ((!current && idx == 0) || (current && idx != 0)) {
648	Arg args[4];
649	Cardinal num_args;
650	String label_str;
651	Pixmap label_pix;
652	XawTextPosition d_pos, i_pos;
653	Widget source;
654	xedit_flist_item *item;
655
656	num_args = 0;
657	XtSetArg(args[num_args], XtNlabel, &label_str);		++num_args;
658	XtSetArg(args[num_args], XtNleftBitmap, &label_pix);	++num_args;
659	XtGetValues(labels[current ? idx : uidx], args, num_args);
660
661	num_args = 0;
662	XtSetArg(args[num_args], XtNlabel, label_str);		++num_args;
663	XtSetArg(args[num_args], XtNleftBitmap, label_pix);	++num_args;
664	XtSetValues(labels[0], args, num_args);
665
666	num_args = 0;
667	XtSetArg(args[num_args], XtNdisplayPosition, &d_pos);	++num_args;
668	XtSetArg(args[num_args], XtNinsertPosition, &i_pos);	++num_args;
669	XtSetArg(args[num_args], XtNtextSource, &source);	++num_args;
670	XtGetValues(texts[current ? idx : uidx], args, num_args);
671
672	num_args = 0;
673	XtSetArg(args[num_args], XtNdisplayPosition, d_pos);	++num_args;
674	XtSetArg(args[num_args], XtNinsertPosition, i_pos);	++num_args;
675	XtSetArg(args[num_args], XtNtextSource, source);	++num_args;
676
677	item = FindTextSource(source, NULL);
678	if (item && (item->flags & WRAP_BIT))
679	    XtSetArg(args[num_args], XtNwrap, item->wrap);
680	else
681	    XtSetArg(args[num_args], XtNwrap,
682		     wrapmodes[WindowIndex(texts[current ? idx : uidx])]);
683	XtSetValues(texts[0], args, num_args);
684
685	UpdateTextProperties(0);
686    }
687
688    labelwindow = labels[0];
689    XeditFocus(texts[0], NULL, NULL, NULL);
690}
691
692void
693SwitchSource(Widget w, XEvent *event, String *params, Cardinal *num_params)
694{
695    int idx = WindowIndex(w);
696    Widget source;
697    int i;
698
699    if (idx < 0 || textwindow != texts[idx]) {
700	Feep();
701	return;
702    }
703
704    source = XawTextGetSource(textwindow);
705
706    for (i = 0; i < flist.num_itens; i++)
707	if (flist.itens[i]->source == source) {
708	    if (i > 0 && i == flist.num_itens - 1)
709		i = 0;
710	    else if (i < flist.num_itens - 1)
711		++i;
712	    else {
713		Feep();
714		return;
715	    }
716	    break;
717	}
718
719    if (i >= flist.num_itens) {
720	Feep();
721	return;
722    }
723
724    SwitchTextSource(flist.itens[i]);
725}
726
727void
728OtherWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
729{
730    int oidx, idx = WindowIndex(w);
731
732    if (idx < 0 || (!XtIsManaged(texts[1]) && !XtIsManaged(texts[2]))) {
733	Feep();
734	return;
735    }
736
737    if (idx == 0)
738	oidx = XtIsManaged(texts[1]) ? 1 : 2;
739    else
740	oidx = 0;
741
742    XeditFocus(texts[oidx], event, params, num_params);
743}
744
745void
746SplitWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
747{
748    Arg args[6];
749    Cardinal num_args;
750    Widget nlabel, ntext, source, sink, manage[2];
751    Dimension width, height, bw;
752    XawTextPosition i_pos, d_pos;
753    String label_str;
754    Pixmap label_pix;
755    int idx = WindowIndex(w), dimension;
756    Bool vert = True;
757    xedit_flist_item *item;
758
759    if (num_params && *num_params == 1
760	&& (*params[0] == 'h' || *params[0] == 'H'))
761	vert = False;
762
763    if (idx < 0
764	|| (vert && XtIsManaged(texts[1]))
765	|| (!vert && XtIsManaged(vpanes[1]))) {
766	Feep();
767	return;
768    }
769
770    if (vert) {
771	nlabel = labels[1];
772	ntext = texts[1];
773    }
774    else {
775	nlabel = labels[2];
776	ntext = texts[2];
777    }
778    ChangeTextWindow(texts[idx]);
779    labelwindow = labels[idx];
780
781    num_args = 0;
782    XtSetArg(args[num_args], XtNinsertPosition, &i_pos);	++num_args;
783    XtSetArg(args[num_args], XtNdisplayPosition, &d_pos);	++num_args;
784    XtSetArg(args[num_args], XtNtextSource, &source);		++num_args;
785    XtSetArg(args[num_args], XtNtextSink, &sink);		++num_args;
786    XtSetArg(args[num_args], XtNwidth, &width);			++num_args;
787    XtSetArg(args[num_args], XtNheight, &height);		++num_args;
788    XtGetValues(w, args, num_args);
789
790    num_args = 0;
791    XtSetArg(args[num_args], XtNinternalBorderWidth, &bw);	++num_args;
792    XtGetValues(XtParent(w), args, num_args);
793
794    if (vert) {
795	dimension = (int)height - (((int)bw) << 1);
796	num_args = 0;
797	XtSetArg(args[num_args], XtNheight, &height);		++num_args;
798	XtGetValues(labelwindow, args, num_args);
799	dimension -= (int)height;
800    }
801    else
802	dimension = (int)width - (int)bw;
803
804    dimension >>= 1;
805
806    if (dimension <= 0 || dimension < XawTextSinkMaxHeight(sink, 3)) {
807	Feep();
808	return;
809    }
810
811    num_args = 0;
812    XtSetArg(args[num_args], XtNlabel, &label_str);		++num_args;
813    XtSetArg(args[num_args], XtNleftBitmap, &label_pix);	++num_args;
814    XtGetValues(labelwindow, args, num_args);
815
816    if (vert) {
817	if (XtIsManaged(texts[2])) {
818	    manage[0] = forms[2];
819	    manage[1] = texts[2];
820	    XtUnmanageChildren(manage, 2);
821	    XtUnmanageChild(vpanes[1]);
822	}
823    }
824    else {
825	if (XtIsManaged(texts[1])) {
826	    manage[0] = forms[1];
827	    manage[1] = texts[1];
828	    XtUnmanageChildren(manage, 2);
829	}
830    }
831
832    XawTextDisableRedisplay(texts[0]);
833    XawTextDisableRedisplay(ntext);
834    if (textwindow == texts[1] || textwindow == texts[2]) {
835	num_args = 0;
836	XtSetArg(args[num_args], XtNdisplayPosition, d_pos);	++num_args;
837	XtSetArg(args[num_args], XtNinsertPosition, i_pos);	++num_args;
838	XtSetArg(args[num_args], XtNtextSource, source);	++num_args;
839	ChangeTextWindow(texts[0]);
840	XtSetValues(textwindow, args, num_args);
841	XtSetKeyboardFocus(topwindow, textwindow);
842
843	num_args = 0;
844	XtSetArg(args[num_args], XtNlabel, label_str);		++num_args;
845	XtSetArg(args[num_args], XtNleftBitmap, label_pix);	++num_args;
846	XtSetValues(labelwindow = labels[0], args, num_args);
847    }
848
849    num_args = 0;
850    XtSetArg(args[num_args], XtNlabel, label_str);		++num_args;
851    XtSetArg(args[num_args], XtNleftBitmap, label_pix);		++num_args;
852    XtSetValues(nlabel, args, num_args);
853
854    num_args = 0;
855    XtSetArg(args[num_args], XtNmin, dimension);		++num_args;
856    XtSetArg(args[num_args], XtNmax, dimension);		++num_args;
857    if (!vert)
858	XtSetValues(vpanes[1], args, num_args);
859    else
860	XtSetValues(ntext, args, num_args);
861
862    manage[0] = XtParent(nlabel);
863    manage[1] = ntext;
864    XtManageChildren(manage, 2);
865    if (!vert)
866	XtManageChild(vpanes[1]);
867
868    num_args = 0;
869    XtSetArg(args[num_args], XtNmin, 1);			++num_args;
870    XtSetArg(args[num_args], XtNmax, 65535);			++num_args;
871    if (!vert) {
872	XtSetValues(vpanes[1], args, num_args);
873	num_args = 0;
874    }
875    XtSetArg(args[num_args], XtNtextSource, source);		++num_args;
876    XtSetArg(args[num_args], XtNdisplayPosition, d_pos);	++num_args;
877    XtSetArg(args[num_args], XtNinsertPosition, i_pos);		++num_args;
878    item = FindTextSource(source, NULL);
879    if (item && (item->flags & WRAP_BIT))
880	XtSetArg(args[num_args], XtNwrap, item->wrap);
881    else
882	XtSetArg(args[num_args], XtNwrap, wrapmodes[WindowIndex(ntext)]);
883    ++num_args;
884    XtSetValues(ntext, args, num_args);
885
886    UpdateTextProperties(0);
887
888    _XawTextShowPosition((TextWidget)textwindow);
889    _XawTextShowPosition((TextWidget)ntext);
890
891    XawTextEnableRedisplay(textwindow);
892    XawTextEnableRedisplay(ntext);
893}
894
895void
896SwitchDirWindow(Bool show)
897{
898    static int map;	/* There must be one instance of this
899			 * variable per top level window */
900    Widget manage[2];
901
902    if (!show && XtIsManaged(XtParent(dirwindow))) {
903	manage[0] = dirlabel;
904	manage[1] = XtParent(dirwindow);
905	XtUnmanageChildren(manage, 2);
906	XtUnmanageChild(vpanes[1]);
907
908	XtManageChild(vpanes[0]);
909	if (map == 2) {
910	    Arg args[2];
911	    Dimension width, bw;
912
913	    XtSetArg(args[0], XtNwidth, &width);
914	    XtGetValues(texts[0], args, 1);
915	    XtSetArg(args[0], XtNinternalBorderWidth, &bw);
916	    XtGetValues(XtParent(texts[0]), args, 1);
917	    width = (width - bw) >> 1;
918	    XtSetArg(args[0], XtNmin, width);
919	    XtSetArg(args[0], XtNmax, width);
920	    XtSetValues(vpanes[0], args, 1);
921	    manage[0] = forms[2];
922	    manage[1] = texts[2];
923	    XtManageChildren(manage, 2);
924	    XtManageChild(vpanes[1]);
925	    XtSetArg(args[0], XtNmin, 1);
926	    XtSetArg(args[0], XtNmax, 65535);
927	    XtSetValues(vpanes[0], args, 1);
928	}
929    }
930    else if (show && !XtIsManaged(XtParent(dirwindow))) {
931	XtUnmanageChild(vpanes[0]);
932	if (XtIsManaged(texts[2])) {
933	    manage[0] = forms[2];
934	    manage[1] = texts[2];
935	    XtUnmanageChildren(manage, 2);
936	    map = 2;
937	}
938	else {
939	    map = XtIsManaged(texts[1]);
940	    XtManageChild(vpanes[1]);
941	}
942
943	manage[0] = dirlabel;
944	manage[1] = XtParent(dirwindow);
945	XtManageChildren(manage, 2);
946    }
947}
948
949/*ARGSUSED*/
950void
951DirWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
952{
953    Arg args[1];
954    char path[BUFSIZ + 1], *dir;
955
956    if (XtIsManaged(XtParent(dirwindow)))
957	return;
958
959    if (*num_params == 1) {
960	strncpy(path, params[0], sizeof(path) - 2);
961	path[sizeof(path) - 2] = '\0';
962    }
963    else {
964	char *slash;
965	xedit_flist_item *item = FindTextSource(XawTextGetSource(textwindow), NULL);
966
967	if (item == NULL || item->source == scratch
968	    || (slash = rindex(item->filename, '/')) == NULL)
969	    strcpy(path, "./");
970	else {
971	    int len = slash - item->filename + 1;
972
973	    if (len > sizeof(path) - 2)
974		len = sizeof(path) - 2;
975	    strncpy(path, item->filename, len);
976	    path[len] = '\0';
977	}
978    }
979
980    dir = ResolveName(path);
981    if (dir != NULL) {
982	strncpy(path, dir, sizeof(path) - 2);
983	path[sizeof(path) - 2] = '\0';
984	if (*path && path[strlen(path) - 1] != '/')
985	    strcat(path, "/");
986
987	XtSetArg(args[0], XtNlabel, "");
988	XtSetValues(dirlabel, args, 1);
989
990	SwitchDirWindow(True);
991	DirWindowCB(dirwindow, path, NULL);
992    }
993    else
994	Feep();
995}
996