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