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(const 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(const 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, const char *name, const 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, const 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    static char *name;
494    char	*result, *tmp = name;
495
496    if (filename == NULL)
497	filename = GetString(filenamewindow);
498
499    /* Ensure not passing the same pointer again to realpath */
500    name = XtMalloc(BUFSIZ);
501    XtFree(tmp);
502    result = realpath(filename, name);
503
504    if (result == NULL && errno == ENOENT) {
505	int	length;
506	char	*dir, *file, *fname;
507
508	length = strlen(filename);
509	tmp = dir = XtMalloc(length + 1);
510	strcpy(dir, filename);
511	fname = strdup(filename);
512
513	file = basename(fname);
514	dir = dirname(tmp);
515
516	/* Creating a new file? */
517	if (dir && file && strcmp(dir, file) &&
518	    access(dir, F_OK) == 0 &&
519	    (result = realpath(dir, name)) == name) {
520	    int	length = strlen(result);
521
522	    XmuSnprintf(result + length, BUFSIZ - length, "%s%s",
523			result[length - 1] == '/' ? "" : "/", file);
524	}
525
526	XtFree(tmp);
527	free(fname);
528    }
529
530    return (result);
531}
532
533static void
534ChangeTextWindow(Widget w)
535{
536    Arg args[1];
537
538    if (textwindow != w) {
539	xedit_flist_item *other, *current;
540
541	other = FindTextSource(XawTextGetSource(textwindow), NULL);
542	current = FindTextSource(XawTextGetSource(w), NULL);
543	if (other != current)
544	    flist.other = other;
545	if (current)
546	    flist.current = current;
547	XtSetArg(args[0], XtNdisplayCaret, False);
548	XtSetValues(textwindow, args, 1);
549	XtSetArg(args[0], XtNdisplayCaret, True);
550	XtSetValues(w, args, 1);
551	XawTextUnsetSelection(textwindow);
552	textwindow = w;
553    }
554}
555
556/*ARGSUSED*/
557void
558XeditFocus(Widget w, XEvent *event, String *params, Cardinal *num_params)
559{
560    Arg args[1];
561    xedit_flist_item *item;
562    int idx = WindowIndex(w);
563
564    XtSetKeyboardFocus(topwindow, w);
565
566    ChangeTextWindow(w);
567
568    labelwindow = labels[idx];
569    item = FindTextSource(XawTextGetSource(textwindow), NULL);
570
571    if (item->source != scratch)
572	XtSetArg(args[0], XtNstring, item->name);
573    else
574	XtSetArg(args[0], XtNstring, NULL);
575
576    XtSetValues(filenamewindow, args, 1);
577
578    line_edit = False;
579}
580
581void
582PopupMenu(Widget w, XEvent *event, String *params, Cardinal *num_params)
583{
584    Cardinal n_params = num_params ? *num_params : 0;
585
586    if (*num_params && XmuCompareISOLatin1(*params, "editMenu") == 0)
587	SetEditMenu();
588
589    XtCallActionProc(w, "XawPositionSimpleMenu", event, params, n_params);
590    XtCallActionProc(w, "XtMenuPopup", event, params, n_params);
591}
592
593/*ARGSUSED*/
594static void
595SwitchSourceCallback(Widget entry, XtPointer client_data, XtPointer call_data)
596{
597    SwitchTextSource((xedit_flist_item*)client_data);
598}
599
600static int
601WindowIndex(Widget w)
602{
603    int i;
604
605    for (i = 0; i < 3; i++)
606	if (texts[i] == w)
607	    return (i);
608
609    return (-1);
610}
611
612void
613DeleteWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
614{
615    Widget unmanage[2];
616    int idx = WindowIndex(w), uidx;
617    Bool current = False;
618
619    if (*num_params == 1 && (*params[0] == 'd' || *params[0] == 'D')) {
620	if (XtIsManaged(XtParent(dirwindow)))
621	    SwitchDirWindow(False);
622	return;
623    }
624
625    if (idx < 0 || (!XtIsManaged(texts[1]) && !XtIsManaged(texts[2]))) {
626	Feep();
627	return;
628    }
629
630    if (num_params && *num_params == 1 &&
631	(*params[0] == 'o' || *params[0] == 'O'))
632	current = True;
633
634    uidx = XtIsManaged(texts[1]) ? 1 : 2;
635
636    unmanage[0] = forms[uidx];
637    unmanage[1] = texts[uidx];
638    XtUnmanageChildren(unmanage, 2);
639
640    if (!XtIsManaged(texts[2]))
641	XtUnmanageChild(vpanes[1]);
642
643    if ((!current && idx == 0) || (current && idx != 0)) {
644	Arg args[4];
645	Cardinal num_args;
646	String label_str;
647	Pixmap label_pix;
648	XawTextPosition d_pos, i_pos;
649	Widget source;
650	xedit_flist_item *item;
651
652	num_args = 0;
653	XtSetArg(args[num_args], XtNlabel, &label_str);		++num_args;
654	XtSetArg(args[num_args], XtNleftBitmap, &label_pix);	++num_args;
655	XtGetValues(labels[current ? idx : uidx], args, num_args);
656
657	num_args = 0;
658	XtSetArg(args[num_args], XtNlabel, label_str);		++num_args;
659	XtSetArg(args[num_args], XtNleftBitmap, label_pix);	++num_args;
660	XtSetValues(labels[0], args, num_args);
661
662	num_args = 0;
663	XtSetArg(args[num_args], XtNdisplayPosition, &d_pos);	++num_args;
664	XtSetArg(args[num_args], XtNinsertPosition, &i_pos);	++num_args;
665	XtSetArg(args[num_args], XtNtextSource, &source);	++num_args;
666	XtGetValues(texts[current ? idx : uidx], args, num_args);
667
668	num_args = 0;
669	XtSetArg(args[num_args], XtNdisplayPosition, d_pos);	++num_args;
670	XtSetArg(args[num_args], XtNinsertPosition, i_pos);	++num_args;
671	XtSetArg(args[num_args], XtNtextSource, source);	++num_args;
672
673	item = FindTextSource(source, NULL);
674	if (item && (item->flags & WRAP_BIT))
675	    XtSetArg(args[num_args], XtNwrap, item->wrap);
676	else
677	    XtSetArg(args[num_args], XtNwrap,
678		     wrapmodes[WindowIndex(texts[current ? idx : uidx])]);
679	XtSetValues(texts[0], args, num_args);
680
681	UpdateTextProperties(0);
682    }
683
684    labelwindow = labels[0];
685    XeditFocus(texts[0], NULL, NULL, NULL);
686}
687
688void
689SwitchSource(Widget w, XEvent *event, String *params, Cardinal *num_params)
690{
691    int idx = WindowIndex(w);
692    Widget source;
693    int i;
694
695    if (idx < 0 || textwindow != texts[idx]) {
696	Feep();
697	return;
698    }
699
700    source = XawTextGetSource(textwindow);
701
702    for (i = 0; i < flist.num_itens; i++)
703	if (flist.itens[i]->source == source) {
704	    if (i > 0 && i == flist.num_itens - 1)
705		i = 0;
706	    else if (i < flist.num_itens - 1)
707		++i;
708	    else {
709		Feep();
710		return;
711	    }
712	    break;
713	}
714
715    if (i >= flist.num_itens) {
716	Feep();
717	return;
718    }
719
720    SwitchTextSource(flist.itens[i]);
721}
722
723void
724OtherWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
725{
726    int oidx, idx = WindowIndex(w);
727
728    if (idx < 0 || (!XtIsManaged(texts[1]) && !XtIsManaged(texts[2]))) {
729	Feep();
730	return;
731    }
732
733    if (idx == 0)
734	oidx = XtIsManaged(texts[1]) ? 1 : 2;
735    else
736	oidx = 0;
737
738    XeditFocus(texts[oidx], event, params, num_params);
739}
740
741void
742SplitWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
743{
744    Arg args[6];
745    Cardinal num_args;
746    Widget nlabel, ntext, source, sink, manage[2];
747    Dimension width, height, bw;
748    XawTextPosition i_pos, d_pos;
749    String label_str;
750    Pixmap label_pix;
751    int idx = WindowIndex(w), dimension;
752    Bool vert = True;
753    xedit_flist_item *item;
754
755    if (num_params && *num_params == 1
756	&& (*params[0] == 'h' || *params[0] == 'H'))
757	vert = False;
758
759    if (idx < 0
760	|| (vert && XtIsManaged(texts[1]))
761	|| (!vert && XtIsManaged(vpanes[1]))) {
762	Feep();
763	return;
764    }
765
766    if (vert) {
767	nlabel = labels[1];
768	ntext = texts[1];
769    }
770    else {
771	nlabel = labels[2];
772	ntext = texts[2];
773    }
774    ChangeTextWindow(texts[idx]);
775    labelwindow = labels[idx];
776
777    num_args = 0;
778    XtSetArg(args[num_args], XtNinsertPosition, &i_pos);	++num_args;
779    XtSetArg(args[num_args], XtNdisplayPosition, &d_pos);	++num_args;
780    XtSetArg(args[num_args], XtNtextSource, &source);		++num_args;
781    XtSetArg(args[num_args], XtNtextSink, &sink);		++num_args;
782    XtSetArg(args[num_args], XtNwidth, &width);			++num_args;
783    XtSetArg(args[num_args], XtNheight, &height);		++num_args;
784    XtGetValues(w, args, num_args);
785
786    num_args = 0;
787    XtSetArg(args[num_args], XtNinternalBorderWidth, &bw);	++num_args;
788    XtGetValues(XtParent(w), args, num_args);
789
790    if (vert) {
791	dimension = (int)height - (((int)bw) << 1);
792	num_args = 0;
793	XtSetArg(args[num_args], XtNheight, &height);		++num_args;
794	XtGetValues(labelwindow, args, num_args);
795	dimension -= (int)height;
796    }
797    else
798	dimension = (int)width - (int)bw;
799
800    dimension >>= 1;
801
802    if (dimension <= 0 || dimension < XawTextSinkMaxHeight(sink, 3)) {
803	Feep();
804	return;
805    }
806
807    num_args = 0;
808    XtSetArg(args[num_args], XtNlabel, &label_str);		++num_args;
809    XtSetArg(args[num_args], XtNleftBitmap, &label_pix);	++num_args;
810    XtGetValues(labelwindow, args, num_args);
811
812    if (vert) {
813	if (XtIsManaged(texts[2])) {
814	    manage[0] = forms[2];
815	    manage[1] = texts[2];
816	    XtUnmanageChildren(manage, 2);
817	    XtUnmanageChild(vpanes[1]);
818	}
819    }
820    else {
821	if (XtIsManaged(texts[1])) {
822	    manage[0] = forms[1];
823	    manage[1] = texts[1];
824	    XtUnmanageChildren(manage, 2);
825	}
826    }
827
828    XawTextDisableRedisplay(texts[0]);
829    XawTextDisableRedisplay(ntext);
830    if (textwindow == texts[1] || textwindow == texts[2]) {
831	num_args = 0;
832	XtSetArg(args[num_args], XtNdisplayPosition, d_pos);	++num_args;
833	XtSetArg(args[num_args], XtNinsertPosition, i_pos);	++num_args;
834	XtSetArg(args[num_args], XtNtextSource, source);	++num_args;
835	ChangeTextWindow(texts[0]);
836	XtSetValues(textwindow, args, num_args);
837	XtSetKeyboardFocus(topwindow, textwindow);
838
839	num_args = 0;
840	XtSetArg(args[num_args], XtNlabel, label_str);		++num_args;
841	XtSetArg(args[num_args], XtNleftBitmap, label_pix);	++num_args;
842	XtSetValues(labelwindow = labels[0], args, num_args);
843    }
844
845    num_args = 0;
846    XtSetArg(args[num_args], XtNlabel, label_str);		++num_args;
847    XtSetArg(args[num_args], XtNleftBitmap, label_pix);		++num_args;
848    XtSetValues(nlabel, args, num_args);
849
850    num_args = 0;
851    XtSetArg(args[num_args], XtNmin, dimension);		++num_args;
852    XtSetArg(args[num_args], XtNmax, dimension);		++num_args;
853    if (!vert)
854	XtSetValues(vpanes[1], args, num_args);
855    else
856	XtSetValues(ntext, args, num_args);
857
858    manage[0] = XtParent(nlabel);
859    manage[1] = ntext;
860    XtManageChildren(manage, 2);
861    if (!vert)
862	XtManageChild(vpanes[1]);
863
864    num_args = 0;
865    XtSetArg(args[num_args], XtNmin, 1);			++num_args;
866    XtSetArg(args[num_args], XtNmax, 65535);			++num_args;
867    if (!vert) {
868	XtSetValues(vpanes[1], args, num_args);
869	num_args = 0;
870    }
871    XtSetArg(args[num_args], XtNtextSource, source);		++num_args;
872    XtSetArg(args[num_args], XtNdisplayPosition, d_pos);	++num_args;
873    XtSetArg(args[num_args], XtNinsertPosition, i_pos);		++num_args;
874    item = FindTextSource(source, NULL);
875    if (item && (item->flags & WRAP_BIT))
876	XtSetArg(args[num_args], XtNwrap, item->wrap);
877    else
878	XtSetArg(args[num_args], XtNwrap, wrapmodes[WindowIndex(ntext)]);
879    ++num_args;
880    XtSetValues(ntext, args, num_args);
881
882    UpdateTextProperties(0);
883
884    _XawTextShowPosition((TextWidget)textwindow);
885    _XawTextShowPosition((TextWidget)ntext);
886
887    XawTextEnableRedisplay(textwindow);
888    XawTextEnableRedisplay(ntext);
889}
890
891void
892SwitchDirWindow(Bool show)
893{
894    static int map;	/* There must be one instance of this
895			 * variable per top level window */
896    Widget manage[2];
897
898    if (!show && XtIsManaged(XtParent(dirwindow))) {
899	manage[0] = dirlabel;
900	manage[1] = XtParent(dirwindow);
901	XtUnmanageChildren(manage, 2);
902	XtUnmanageChild(vpanes[1]);
903
904	XtManageChild(vpanes[0]);
905	if (map == 2) {
906	    Arg args[2];
907	    Dimension width, bw;
908
909	    XtSetArg(args[0], XtNwidth, &width);
910	    XtGetValues(texts[0], args, 1);
911	    XtSetArg(args[0], XtNinternalBorderWidth, &bw);
912	    XtGetValues(XtParent(texts[0]), args, 1);
913	    width = (width - bw) >> 1;
914	    XtSetArg(args[0], XtNmin, width);
915	    XtSetArg(args[0], XtNmax, width);
916	    XtSetValues(vpanes[0], args, 1);
917	    manage[0] = forms[2];
918	    manage[1] = texts[2];
919	    XtManageChildren(manage, 2);
920	    XtManageChild(vpanes[1]);
921	    XtSetArg(args[0], XtNmin, 1);
922	    XtSetArg(args[0], XtNmax, 65535);
923	    XtSetValues(vpanes[0], args, 1);
924	}
925    }
926    else if (show && !XtIsManaged(XtParent(dirwindow))) {
927	XtUnmanageChild(vpanes[0]);
928	if (XtIsManaged(texts[2])) {
929	    manage[0] = forms[2];
930	    manage[1] = texts[2];
931	    XtUnmanageChildren(manage, 2);
932	    map = 2;
933	}
934	else {
935	    map = XtIsManaged(texts[1]);
936	    XtManageChild(vpanes[1]);
937	}
938
939	manage[0] = dirlabel;
940	manage[1] = XtParent(dirwindow);
941	XtManageChildren(manage, 2);
942    }
943}
944
945/*ARGSUSED*/
946void
947DirWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
948{
949    Arg args[1];
950    char path[BUFSIZ + 1], *dir;
951
952    if (XtIsManaged(XtParent(dirwindow)))
953	return;
954
955    if (*num_params == 1) {
956	strncpy(path, params[0], sizeof(path) - 2);
957	path[sizeof(path) - 2] = '\0';
958    }
959    else {
960	char *slash;
961	xedit_flist_item *item = FindTextSource(XawTextGetSource(textwindow), NULL);
962
963	if (item == NULL || item->source == scratch
964	    || (slash = rindex(item->filename, '/')) == NULL)
965	    strcpy(path, "./");
966	else {
967	    int len = slash - item->filename + 1;
968
969	    if (len > sizeof(path) - 2)
970		len = sizeof(path) - 2;
971	    strncpy(path, item->filename, len);
972	    path[len] = '\0';
973	}
974    }
975
976    dir = ResolveName(path);
977    if (dir != NULL) {
978	strncpy(path, dir, sizeof(path) - 2);
979	path[sizeof(path) - 2] = '\0';
980	if (*path && path[strlen(path) - 1] != '/')
981	    strcat(path, "/");
982
983	XtSetArg(args[0], XtNlabel, "");
984	XtSetValues(dirlabel, args, 1);
985
986	SwitchDirWindow(True);
987	DirWindowCB(dirwindow, path, NULL);
988    }
989    else
990	Feep();
991}
992