/*
	$Id: callback.c,v 1.4 2001/09/03 18:52:36 rogue Exp $

	Copyright (c) 1999 - 2001 Xforge project
*/

#include <Xm/Xm.h>
#include <Xm/MessageB.h>
#include <Xm/List.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "xforge.h"
#include "callback.h"
#include "bufutil.h"
#include "glob.h"

static XmString xmstring1;
static XmString xmstring2;
static Boolean okprompts = True;

/*
	numchk() checks if string p has only numeric [0123456789] characters,
	and only zero or one '.' and returns 0 in this case, -1 otherwise.
*/

static int numchk(const char *p) {
	int numdots = 0;

	while (*p)
		if (isdigit(*p))
			p++;
		else
			if (*p == '.') {
				numdots++;
				p++;
			} else
				return -1;
	if (numdots > 1)
		return -1;
	return 0;
}

/*
	use_xcwatch() applies XC_watch X cursor for all windows.
	Note you cannot call this if toplevel is unmanaged.
*/

static void use_xcwatch(void) {
	struct buffer *p;

	for (p = root; p; p = p->succ) {
		XDefineCursor(XtDisplay(p->top_wid),
			XtWindow(p->top_wid),
			xcwatch);
		if (XtIsManaged(p->param_dialog))
			XDefineCursor(XtDisplay(p->param_dialog),
				XtWindow(p->param_dialog),
				xcwatch);
		if (XtIsManaged(p->resample_dialog))
			XDefineCursor(XtDisplay(p->resample_dialog),
				XtWindow(p->resample_dialog),
				xcwatch);
		if (XtIsManaged(p->mono_dialog))
			XDefineCursor(XtDisplay(p->mono_dialog),
				XtWindow(p->mono_dialog),
				xcwatch);
		if (XtIsManaged(p->mix_dialog))
			XDefineCursor(XtDisplay(p->mix_dialog),
				XtWindow(p->mix_dialog),
				xcwatch);
		if (XtIsManaged(p->vol_dialog))
			XDefineCursor(XtDisplay(p->vol_dialog),
				XtWindow(p->vol_dialog),
				xcwatch);
		if (XtIsManaged(p->echo_dialog))
			XDefineCursor(XtDisplay(p->echo_dialog),
				XtWindow(p->echo_dialog),
				xcwatch);
		if (XtIsManaged(p->rev_dialog))
			XDefineCursor(XtDisplay(p->rev_dialog),
				XtWindow(p->rev_dialog),
				xcwatch);
		if (XtIsManaged(p->flan_dialog))
			XDefineCursor(XtDisplay(p->flan_dialog),
				XtWindow(p->flan_dialog),
				xcwatch);
		if (XtIsManaged(p->filt_dialog))
			XDefineCursor(XtDisplay(p->filt_dialog),
				XtWindow(p->filt_dialog),
				xcwatch);
		if (XtIsManaged(p->comp_dialog))
			XDefineCursor(XtDisplay(p->comp_dialog),
				XtWindow(p->comp_dialog),
				xcwatch);
		XFlush(XtDisplay(p->top_wid));
	}
}

/*
	use_pointer() reverts to default X pointer in all windows.
	Note you cannot call this if toplevel is unmanaged.
*/

static void use_pointer(void) {
	struct buffer *p;

	for (p = root; p; p = p->succ) {
		XUndefineCursor(XtDisplay(p->top_wid),
			XtWindow(p->top_wid));
		if (XtIsManaged(p->param_dialog))
			XUndefineCursor(XtDisplay(p->param_dialog),
				XtWindow(p->param_dialog));
		if (XtIsManaged(p->resample_dialog))
			XUndefineCursor(XtDisplay(p->resample_dialog),
				XtWindow(p->resample_dialog));
		if (XtIsManaged(p->mono_dialog))
			XUndefineCursor(XtDisplay(p->mono_dialog),
				XtWindow(p->mono_dialog));
		if (XtIsManaged(p->mix_dialog))
			XUndefineCursor(XtDisplay(p->mix_dialog),
				XtWindow(p->mix_dialog));
		if (XtIsManaged(p->vol_dialog))
			XUndefineCursor(XtDisplay(p->vol_dialog),
				XtWindow(p->vol_dialog));
		if (XtIsManaged(p->echo_dialog))
			XUndefineCursor(XtDisplay(p->echo_dialog),
				XtWindow(p->echo_dialog));
		if (XtIsManaged(p->flan_dialog))
			XUndefineCursor(XtDisplay(p->flan_dialog),
				XtWindow(p->flan_dialog));
		if (XtIsManaged(p->rev_dialog))
			XUndefineCursor(XtDisplay(p->rev_dialog),
				XtWindow(p->rev_dialog));
		if (XtIsManaged(p->filt_dialog))
			XUndefineCursor(XtDisplay(p->filt_dialog),
				XtWindow(p->filt_dialog));
		if (XtIsManaged(p->comp_dialog))
			XUndefineCursor(XtDisplay(p->comp_dialog),
				XtWindow(p->comp_dialog));
		XFlush(XtDisplay(p->top_wid));
	}
}

void set_window_title(struct buffer *buf) {
	char buffer[256];

	XtVaSetValues(buf->top_wid, XtNtitle, buf->name, NULL);

	sprintf(buffer, "%s: Open wave", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->open_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Save wave", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->save_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->clear_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->close_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Params", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->param_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Resample", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->resample_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Convert To Mono", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->mono_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Mix", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->mix_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Volume", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->vol_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Echo", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->echo_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Flange", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->flan_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Reverb", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->rev_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Filter", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->filt_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);

	sprintf(buffer, "%s: Compress", buf->name);
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->comp_dialog, XmNdialogTitle, xmstring1, NULL);
	XmStringFree(xmstring1);
}

/* actual callback routines start here */

/*
	render_buffer(w, buf) renders the waveform of buf
*/

void render_buffer(Widget w, struct buffer *buf) {
	int i, j;
	Dimension height, width;
	XPoint *points;
	double p, s;

	XtVaGetValues(w, XmNheight, &height, XmNwidth, &width, NULL);
	if (!(points = malloc(width * sizeof(*points)))) {
		syserr(EMEM_MSG);
		return;
	}

	XClearArea(buf->display, XtWindow(w), 0, 0, width, height, FALSE);

	/* render horizontal line(s) */
	for (i = 0; i < buf->channels; i++) {
		points[0].x = 0;
		points[0].y = (1 + 2 * i) * height / buf->channels / 2;
		points[1].x = width - 1;
		points[1].y = points[0].y;
		XDrawLines(buf->display, XtWindow(w), buf->lgc, points, 2,
			CoordModeOrigin);
	}

	/* render waveform */
	if (buf->data && width > 1) {
		/* FIXME: is double always accurate enough? */
		s = (double)(buf->dispend - buf->dispstart) /
			(double)(width - 1);
		for (i = 0; i < buf->channels; i++) {
			p = (double)(buf->dispstart + i * buf->len);
			for (j = 0; j < width; j++) {
				points[j].x = j;
				points[j].y = (short)((1 + 2 * i) * height /
					buf->channels / 2 + height /
					buf->channels / 2 * buf->data[(int)p]);
				p += s;
			}
			XDrawLines(buf->display, XtWindow(w), buf->lgc, points,
				width, CoordModeOrigin);
		}
	}
	free(points);
}

/*
	render_selection(w, buf, modify) will render the selection of
	buf. If modify is nonzero, only the changed portion of selection
	is redrawn, otherwise the entire selection is rendered.
*/

void render_selection(Widget w, struct buffer *buf, int modify) {
	Dimension height, width;
	short selx0, selx1, selw;

	XtVaGetValues(w, XmNheight, &height, XmNwidth, &width, NULL);

	if (buf->data) {
		/* convert new selection to coordinates -- use double? */
		if (buf->dispstart == buf->dispend) {
			selx0 = buf->selstart < buf->dispstart ? 0 : width + 1;
			selx1 = buf->selend > buf->dispend ? width : width + 1;
		} else {
			selx0 = (double)(buf->selstart - buf->dispstart) *
				(double)width / (double)(buf->dispend -
				buf->dispstart);
			selx1 = (double)(buf->selend - buf->dispstart) *
				(double)width / (double)(buf->dispend -
				buf->dispstart);
		}
		/* do nothing if selection is not visible */
		if ((selx0 < 0 && selx1 < 0) ||
			(selx0 > width && selx1 > width))
			return;
		/* truncate visible selection to canvas */
		if (selx0 < 0)
			selx0 = 0;
		if (selx1 >= width)
			selx1 = width - 1;
		selw = selx1 - selx0 + 1;
		/* just modifying selection? do not redraw everything */
		if (modify) {
			if (buf->channels == 1 && buf->old_selmask) {
				/* grow left */
				if (selx0 < buf->old_selx0) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						selx0, 0,
						buf->old_selx0 - selx0,
						height);
				}
				/* shrink left */
				if (selx0 > buf->old_selx0) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						buf->old_selx0, 0,
						selx0 - buf->old_selx0,
						height);
				}
				/* shrink right */
				if (selx1 < buf->old_selx1) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						selx1 + 1, 0,
						buf->old_selx1 - selx1,
						height);
				}
				/* grow right */
				if (selx1 > buf->old_selx1) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						buf->old_selx1 + 1, 0,
						selx1 - buf->old_selx1,
						height);
				}
			} else {
				/* left: grow left */
				if (buf->old_selmask & 0x1 &&
					selx0 < buf->old_selx0) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						selx0, 0,
						buf->old_selx0 - selx0,
						height / 2);
				}
				/* left: shrink left */
				if (buf->old_selmask & 0x1 &&
					selx0 > buf->old_selx0) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						buf->old_selx0, 0,
						selx0 - buf->old_selx0,
						height / 2);
				}
				/* left: shrink right */
				if (buf->old_selmask & 0x1 &&
					selx1 < buf->old_selx1) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						selx1 + 1, 0,
						buf->old_selx1 - selx1,
						height / 2);
				}
				/* left: grow right */
				if (buf->old_selmask & 0x1 &&
					selx1 > buf->old_selx1) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						buf->old_selx1 + 1, 0,
						selx1 - buf->old_selx1,
						height / 2);
				}
				/* right: grow left */
				if (buf->old_selmask & 0x2 &&
					selx0 < buf->old_selx0) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						selx0, height / 2,
						buf->old_selx0 - selx0,
						height / 2);
				}
				/* right: shrink left */
				if (buf->old_selmask & 0x2 &&
					selx0 > buf->old_selx0) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						buf->old_selx0, height / 2,
						selx0 - buf->old_selx0,
						height / 2);
				}
				/* right: shrink right */
				if (buf->old_selmask & 0x2 &&
					selx1 < buf->old_selx1) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						selx1 + 1, height / 2,
						buf->old_selx1 - selx1,
						height / 2);
				}
				/* right: grow right */
				if (buf->old_selmask & 0x2 &&
					selx1 > buf->old_selx1) {
					XFillRectangle(buf->display,
						XtWindow(w), buf->sgc,
						buf->old_selx1 + 1, height / 2,
						selx1 - buf->old_selx1,
						height / 2);
				}
			}
		} else {	/* modify */
			if (buf->channels == 1) {
				if (buf->selmask) {
					XFillRectangle(buf->display,
						XtWindow(w),
						buf->sgc, selx0, 0,
						selw, height);
				}
			} else {
				if (buf->selmask & 0x1) {
					XFillRectangle(buf->display,
						XtWindow(w),
						buf->sgc, selx0, 0,
						selw, height / 2);
				}
				if (buf->selmask & 0x2) {
					XFillRectangle(buf->display,
						XtWindow(w),
						buf->sgc, selx0, height / 2,
						selw, height / 2);
				}
			}
		}
		buf->old_selx0 = selx0;
		buf->old_selx1 = selx1;
		buf->old_selw = selw;
		buf->old_selmask = buf->selmask;
	}
}

/*
	render_statbar(buf) updates the information of buf in statbar.
*/

void render_statbar(struct buffer *buf) {
	char *formatname = "empty buffer", buffer[256];

	if (buf->data)
		switch (buf->filef) {
			case FILEF_RAW:
				formatname = "Raw data";
				break;
			case FILEF_SUN:
				formatname = "Sun Audio";
				break;
			case FILEF_RIFF:
				formatname = "RIFF";
				break;
			case FILEF_RIFX:
				formatname = "RIFX";
				break;
			case FILEF_AIFF:
				formatname = "AIFF";
				break;
			case FILEF_AIFC:
				formatname = "AIFF-C";
				break;
		}

	sprintf(buffer, "Length: %d DispStart: %d DispEnd: %d SelStart: %d "
		"SelEnd: %d %s %d S/s %s", buf->len, buf->dispstart,
		buf->dispend, buf->selstart, buf->selend, formatname,
		buf->rate, buf->mod ? "(Modified)" : "");
	xmstring1 = XmStringCreateLocalized(buffer);
	XtVaSetValues(buf->statlabel, XmNlabelString, xmstring1, NULL);
	XmStringFree(xmstring1);
}

/*
	refresh_scrollbar(buf) updates the horizontal scrollbar position
	to reflect the displayed portion of wave.
*/

void refresh_scrollbar(struct buffer *buf) {
	if (buf->data && buf->len) {
		XtVaSetValues(buf->scrollbar,
			XmNminimum, 0,
			XmNmaximum, buf->len,
			XmNvalue, buf->dispstart,
			XmNsliderSize, buf->dispend - buf->dispstart + 1,
			XmNincrement, buf->len / 100,
			XmNpageIncrement, buf->dispend - buf->dispstart + 1,
			NULL);
	} else {
		XtVaSetValues(buf->scrollbar,
			XmNminimum, 0,
			XmNmaximum, 10,
			XmNvalue, 0,
			XmNsliderSize, 10,
			NULL);
	}
}

/*
	render_all(w, buf) redraws the entire window.
*/

void render_all(Widget w, struct buffer *buf) {
	render_buffer(w, buf);
	render_selection(w, buf, 0);
	render_statbar(buf);
	refresh_scrollbar(buf);
}

/*
	scroll_canvas(w, buf, cbs) will scroll the displayed portion
	of wave according to the position of horizontal scrollbar.
*/

void scroll_canvas(Widget w, struct buffer *buf,
	XmScrollBarCallbackStruct *cbs) {
	int value, diff;

	XtVaGetValues(w, XmNvalue, &value, NULL);
	diff = value - buf->dispstart;
	buf->dispstart += diff;
	buf->dispend += diff;
	render_all(buf->canvas, buf);
}

/* menu callbacks */

/*
	new_window(w, buf) - spawn a new window.
*/

void new_window(Widget w, struct buffer *buf) {
	spawn_gui(NULL);
}

/*
	open_help(w, buf) opens help dialog for Open
*/

void open_help(Widget w, struct buffer *buf) {
	spawn_help(LIBDIR "/hopen");
}

/*
	open_hide_dialog(w, buf) unmanages the open dialog of this buffer.
*/

void open_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->open_dialog);
}

/*
	open_really(w, buf, cbs) attempts to load a waveform to new
	window if current is not empty, or to current window if it is
	empty.
*/

void open_really(Widget w, struct buffer *buf,
	XmFileSelectionBoxCallbackStruct *cbs) {
	char *path;

	XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &path);
	XtUnmanageChild(buf->open_dialog);
	/* if buffer is empty, load the file in this buffer */
	/* else spawn another window */
	if (buf->data) {
		spawn_gui(path);
	} else {
		use_xcwatch();
		if (io_openfile(buf, path) == -1) {
			use_pointer();
			return;
		}
		set_window_title(buf);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

/*
	open_query(w, buf) manages the open dialog for this buffer.
*/

void open_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->open_dialog);
}

/*
	save_hide_dialog(w, buf) unmanages the save dialog for this buffer.
*/

void save_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->save_dialog);
}

/*
	save_really(w, buf, cbs) attempts to save the current buffer to
	selected file name.
*/

void save_really(Widget w, struct buffer *buf,
	XmFileSelectionBoxCallbackStruct *cbs) {
	char *path;

	XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &path);
	XtUnmanageChild(buf->save_dialog);
	use_xcwatch();
	if (!io_savefile(buf, path))
		set_window_title(buf);
	render_all(buf->canvas, buf);
	use_pointer();
}

/*
	save_inst(w, buf) attempts to save the current buffer. The file name
	used is buf->data, or if that is NULL, the name is queried with the
	save dialog.
*/

void save_inst(Widget w, struct buffer *buf) {
	if (buf->data) {
		if (buf->path) {
			use_xcwatch();
			io_savefile(buf, buf->path);
			render_all(buf->canvas, buf);
			use_pointer();
		} else
			XtManageChild(buf->save_dialog);
	}
}

/*
	save_query(w, buf) manages the save dialog for this buffer.
*/

void save_query(Widget w, struct buffer *buf) {
	if (buf->data)
		XtManageChild(buf->save_dialog);
}

/*
	revert_destroy_dialog(w, buf) unmanages and destroys the revert
	dialog for this buffer.
*/

void revert_destroy_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(w);
	XtDestroyWidget(w);
}

/*
	revert_really(w, buf) attempts to revert the current buffer to its
	in-disk state.
*/

void revert_really(Widget w, struct buffer *buf) {
	if (w)
		revert_destroy_dialog(w, buf);
	use_xcwatch();
	io_openfile(buf, buf->path);
	if (buf->selend >= buf->len)
		buf->selend = buf->len - 1;
	render_all(buf->canvas, buf);
	use_pointer();
}

/*
	revert_query(w, buf) creates and manages a revert dialog for this
	buffer.
*/

void revert_query(Widget w, struct buffer *buf) {
	Widget widget;
	char buffer[256];

	/* do nothing if buffer is not modified or is not from disk */
	if (buf->mod && buf->path) {
		if (okprompts) {
			sprintf(buffer, "Revert to %.240s?", buf->path);
			widget = XmCreateQuestionDialog(buf->top_wid,
				"revertDialog", NULL, 0);
			xmstring1 = XmStringCreateLocalized(buffer);
			xmstring2 = XmStringCreateLocalized(DEFAULT_TITLE);
			XtVaSetValues(widget, XmNmessageString, xmstring1,
				XmNdialogTitle, xmstring2, NULL);
			XmStringFree(xmstring1);
			XmStringFree(xmstring2);
			XtAddCallback(widget, XmNokCallback,
				(XtCallbackProc)revert_really, buf);
			XtAddCallback(widget, XmNcancelCallback,
				(XtCallbackProc)revert_destroy_dialog, buf);
			XtManageChild(widget);
		} else {
			revert_really(NULL, buf);
		}
	}
}

/*
	quit_really() quits Xforge.
*/

void quit_really(void) {
	/* FIXME: warning, buf is NULL */
	oss_play_stop(NULL);
	exit(EXIT_SUCCESS);
}

/*
	quit_query(w, buf) manages the quit dialog of Xforge.
*/

void quit_query(Widget w, struct buffer *buf) {
	if (okprompts)
		XtManageChild(quit_dialog);
	else
		quit_really();
}

/*
	buf_undo(w, buf) undoes the last operation for this buffer.
*/

void buf_undo(Widget w, struct buffer *buf) {
	undo(buf);
	buf->selmask = 0x0;
	buf->dispstart = buf->selstart = 0;
	if (buf->len)
		buf->dispend = buf->selend = buf->len - 1;
	else
		buf->dispend = buf->selend = 0;
	render_all(buf->canvas, buf);
}

/*
	clip_copy(w, buf) calls the buffer copy operation.
*/

void clip_copy(Widget w, struct buffer *buf) {
	if (buf->data) {
		use_xcwatch();
		buf_copy(buf);
		use_pointer();
	}
}

/*
	clip_cut(w, buf) calls the buffer cut operation.
*/

void clip_cut(Widget w, struct buffer *buf) {
	if (buf->data) {
		use_xcwatch();
		buf_cut(buf);
		buf->dispstart = 0;
		buf->dispend = buf->len - 1;
		buf->selend = buf->selstart;
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

/*
	clip_paste(w, buf) calls the buffer paste operation.
*/

void clip_paste(Widget w, struct buffer *buf) {
	use_xcwatch();
	buf_paste(buf);
	buf->dispstart = 0;
	buf->dispend = buf->len - 1;
	render_all(buf->canvas, buf);
	use_pointer();
}

/*
	clip_swap(w, buf) calls the buffer swap operation.
*/

void clip_swap(Widget w, struct buffer *buf) {
	buf_swaptoclip(buf);
	buf->selmask = 0x0;
	buf->dispstart = buf->selstart = 0;
	buf->dispend = buf->selend = buf->len - 1;
	render_all(buf->canvas, buf);
}

/*
	clear_really(w, buf) clears all data from this buffer.
*/

void clear_really(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->clear_dialog);
	if (undo_create(buf))
		return;
	if (buf->data)
		free(buf->data);
	buf->selmask = 0x0;
	buf->data = NULL;
	free(buf->name);
	setbufname(buf, "Xforge");
	buf->len = buf->selstart = buf->selend = buf->dispstart =
		buf->dispend = buf->mod = 0;
	set_window_title(buf);
	render_all(buf->canvas, buf);
}

/*
	clear_query(w, buf) manages the clear dialog for this buffer,
	or calls clear_really() if the data has not been modified.
*/

void clear_query(Widget w, struct buffer *buf) {
	if (buf->mod) {
		if (okprompts)
			XtManageChild(buf->clear_dialog);
		else
			clear_really(XmMessageBoxGetChild(buf->clear_dialog,
				XmDIALOG_OK_BUTTON), buf);
	} else
		clear_really(XmMessageBoxGetChild(buf->clear_dialog,
			XmDIALOG_OK_BUTTON), buf);
}

/*
	clip_delete(w, buf) calls the buffer delete operation.
*/

void clip_delete(Widget w, struct buffer *buf) {
	if (buf->data) {
		use_xcwatch();
		buf_delete(buf);
		buf->dispstart = 0;
		buf->dispend = buf->len - 1;
		buf->selend = buf->selstart;
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

/*
	select_chg(w, event, args, argc) parses mouse button event and
	modifies selection accordingly.
*/

void select_chg(Widget w, XButtonEvent *event, String *args,
	int *argc) {
	Dimension width, height;
	short xstart, xend;		/* sorted x positions */
	struct buffer *buf;
	double c;
	int selmask = 0;

	XtVaGetValues(w, XmNheight, &height, XmNwidth, &width,
			XmNuserData, &buf, NULL);

	if (strcmp(args[0], "down") == 0) {
		buf->m_x0 = event->x;
		buf->m_y0 = event->y;
	}

	if (strcmp(args[0], "motion") == 0 || strcmp(args[0], "up") == 0) {
		buf->m_x1 = event->x;
		buf->m_y1 = event->y;
		if (buf->m_x1 > buf->m_x0) {
			xstart = buf->m_x0;
			xend = buf->m_x1;
		} else {
			xstart = buf->m_x1;
			xend = buf->m_x0;
		}
		if (xstart < 0)
			xstart = 0;
		if (xend >= width)
			xend = width - 1;
		if ((buf->m_y0 < height / buf->channels) ||
			(buf->m_y1 < height / buf->channels))
			selmask |= 0x1;
		if ((buf->m_y0 >= height / buf->channels) ||
			(buf->m_y1 >= height / buf->channels))
			selmask |= 0x2;
		buf->selmask = selmask;
		c = (double)(buf->dispend - buf->dispstart) /
			(double)(width - 1);
		buf->selstart = c * xstart + buf->dispstart;
		buf->selend = c * xend + buf->dispstart;
		if (selmask == buf->old_selmask) {
			render_selection(buf->canvas, buf, 1);
			render_statbar(buf);
		} else
			render_all(buf->canvas, buf);
	}
}

/*
	select_all(w, buf) selects the entire waveform of buf. It clears
	the old selection first since render_selection() is _buggy_.
*/

void select_all(Widget w, struct buffer *buf) {
	buf->selmask = 0;
	render_all(buf->canvas, buf);
	if (buf->data) {
		if (buf->channels == 1)
			buf->selmask = 0x1;
		else
			buf->selmask = 0x3;
		buf->selstart = 0;
		buf->selend = buf->len - 1;
	}
	render_all(buf->canvas, buf);
}

/*
	select_left(w, buf) selects the left channel of buf, or entire
	waveform if the buffer has only one channel.
*/

void select_left(Widget w, struct buffer *buf) {
	if (buf->data) {
		buf->selmask = 0x1;
		buf->selstart = 0;
		buf->selend = buf->len - 1;
	}
	render_all(buf->canvas, buf);
}

/*
	select_right(w, buf) selects the right channel of buf, or entire
	waveform if the buffer has only one channel.
*/

void select_right(Widget w, struct buffer *buf) {
	if (buf->data) {
		buf->selmask = 0x2;
		buf->selstart = 0;
		buf->selend = buf->len - 1;
	}
	render_all(buf->canvas, buf);
}

/*
	select_none(w, buf) clears the selection (i.e. selects nothing)
	of buf.
*/

void select_none(Widget w, struct buffer *buf) {
	buf->selmask = 0;
	render_all(buf->canvas, buf);
}

/*
	begin_data(w, buf) selects the first sample of all channels of
	waveform.
*/

void begin_data(Widget w, struct buffer *buf) {
	if (buf->data) {
		buf->selstart = buf->selend = 0;
		/* select all channels if nothing is selected */
		if (!(buf->selmask))
			buf->selmask = (1 << buf->channels) - 1;
		render_all(buf->canvas, buf);
	}
}

/*
	ext_begin_data(w, buf) extends the current selection to beginning
	of waveform.
*/

void ext_begin_data(Widget w, struct buffer *buf) {
	if (buf->data) {
		buf->selstart = 0;
		/* select the first sample of all channels if nothing */
		/* is selected */
		if (!(buf->selmask)) {
			buf->selmask = (1 << buf->channels) - 1;
			buf->selend = 0;
		}
		render_all(buf->canvas, buf);
	}
}

/*
	end_data(w, buf) selects the last sample of all channels of
	waveform.
*/

void end_data(Widget w, struct buffer *buf) {
	if (buf->data) {
		buf->selstart = buf->selend = buf->len - 1;
		/* select all channels if nothing is selected */
		if (!(buf->selmask))
			buf->selmask = (1 << buf->channels) - 1;
		render_all(buf->canvas, buf);
	}
}

/*
	ext_end_data(w, buf) extends the current selection to end of
	waveform.
*/

void ext_end_data(Widget w, struct buffer *buf) {
	if (buf->data) {
		buf->selend = buf->len - 1;
		/* select the last sample of all channels if nothing */
		/* is selected */
		if (!(buf->selmask)) {
			buf->selmask = (1 << buf->channels) - 1;
			buf->selend = buf->len - 1;
		}
		render_all(buf->canvas, buf);
	}
}

/*
	addws_help(w, buf) opens help dialog for Add Workspace
*/

void addws_help(Widget w, struct buffer *buf) {
	spawn_help(LIBDIR "/haddws");
}

/*
	addws_really(w, buf, cbs) parses the add workspace dialog and
	calls the buffer add workspace operation.
*/

void addws_really(Widget w, struct buffer *buf,
	XmSelectionBoxCallbackStruct *cbs) {
	char *p;
	int n = 0;

	XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &p);
	XtUnmanageChild(w);
	if (numchk(p))
		xferr(ENUM_MSG);
	else
		n = atoi(p);
	if (n > 0) {
		use_xcwatch();
		buf_addws(buf, n);
		buf->dispstart = 0;
		buf->dispend = buf->len - 1;
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

/*
	addws_query(w, buf) creates and manages an add workspace dialog.
*/

void addws_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->addws_dialog);
}

/*
	clip_remdc(w, buf) calls the buffer DC remove operation.
*/

void clip_remdc(Widget w, struct buffer *buf) {
	if (buf->data) {
		use_xcwatch();
		buf_remdc(buf);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

/*
	show_range(w, buf) sets the displayed range to selected range and
	redraws everything in the window of buf.
*/

void show_range(Widget w, struct buffer *buf) {
	if (buf->selmask) {
		buf->dispstart = buf->selstart;
		buf->dispend = buf->selend;
		render_all(buf->canvas, buf);
	}
}

/*
	show_all(w, buf) sets the displayed range to entire wave and
	redraws everything in the window of buf.
*/

void show_all(Widget w, struct buffer *buf) {
	buf->dispstart = 0;
	buf->dispend = buf->len - 1;
	render_all(buf->canvas, buf);
}

/*
	zoom_out(w, buf) doubles the spanned range of displayed portion
	of wave (up to start and end limits) and redraws everything in the
	window of buf.
*/

void zoom_out(Widget w, struct buffer *buf) {
	int center, span;

	center = (buf->dispend + buf->dispstart) / 2;
	span = buf->dispend - buf->dispstart + 1;
	buf->dispstart = center - span;
	if (buf->dispstart < 0)
		buf->dispstart = 0;
	buf->dispend = center + span;
	if (buf->dispend >= buf->len)
		buf->dispend = buf->len - 1;
	render_all(buf->canvas, buf);
}

/*
	close_really(w, buf) destroys buffer buf (stopping the play if
	necessary) and all widgets associated with it.  If buf is the last
	buffer remaining, quit_query() is called.
*/

void close_really(Widget w, struct buffer *buf) {
	/* last one? then quit, otherwise just close buffer */
	if (nbuf == 1)
		quit_query(NULL, NULL);
	else {
		XtDestroyWidget(buf->top_wid);
		/* FIXME: playing could be stopped here */
		remove_buf(buf);
	}
}

/*
	close_query(w, buf) manages the buffer close dialog if ok prompts
	are enabled.
*/

void close_query(Widget w, struct buffer *buf) {
	if (buf->mod) {
		if (okprompts)
			XtManageChild(buf->close_dialog);
		else
			close_really(w, buf);
	} else
		close_really(w, buf);
}

/*
	refresh_window(w, buf) redraws everything in the window of buf.
*/

void refresh_window(Widget w, struct buffer *buf) {
	render_all(buf->canvas, buf);
}

/*
	play_stop(w, buf) playing
*/

void play_stop(Widget w, struct buffer *buf) {
	oss_play_stop(buf);
}

/*
	play_range(w, buf) attempts to play the selected range by calling
	oss_play_range(buf). It also stops current play.
*/

void play_range(Widget w, struct buffer *buf) {
	if (buf->data) {
		play_stop(NULL, buf);
		oss_play_range(buf);
	}
}

/*
	play_all(w, buf) attempts to play the entire wave by calling
	oss_play_all(buf). It also stops current play.
*/

void play_all(Widget w, struct buffer *buf) {
	if (buf->data) {
		play_stop(NULL, buf);
		oss_play_all(buf);
	}
}

/*
	play_loop(w, buf) sets the loop flag of buffer buf according to
	menu button selection.
*/

void play_loop(Widget w, struct buffer *buf) {
	Boolean loop;

	XtVaGetValues(w, XmNset, &loop, NULL);
	buf->p_loop = loop;
}

/*
	param_help(w, buf) opens help dialog for Parameters
*/

void param_help(Widget w, struct buffer *buf) {
	spawn_help(LIBDIR "/hparam");
}

/*
	param_set(w, buf, cbs) reapplies the wave parameters to buffer buf.
*/

void param_set(Widget w, struct buffer *buf, XmPushButtonCallbackStruct *cbs) {
	char *rate;
	Boolean testv;

	XtVaGetValues(buf->param_dialog_srw, XmNvalue, &rate, NULL);
	if (numchk(rate))
		xferr(ENUM_MSG);
	else
		buf->rate = atoi(rate);
	XtVaGetValues(buf->param_dialog_ch1, XmNset, &testv, NULL);
	if (testv && buf->channels == 2) {
		use_xcwatch();
		if (!buf_stomshuffle(buf)) {
			buf->channels = 1;
			/* transition from 2 channels to 1: double length */
			buf->len *= 2;
			buf->selmask = 0;
			buf->dispstart = buf->selstart = 0;
			buf->dispend = buf->selend = buf->len - 1;
		}
		if (!(buf->data));
			buf->channels = 1;
		use_pointer();
	}
	XtVaGetValues(buf->param_dialog_ch2, XmNset, &testv, NULL);
	if (testv && buf->channels == 1) {
		use_xcwatch();
		if (!buf_mtosshuffle(buf)) {
			buf->channels = 2;
			/* transition from 1 channel to 2: halve length */
			/* note this truncates wave length */
			buf->len /= 2;
			buf->selmask = 0;
			buf->dispstart = buf->selstart = 0;
			buf->dispend = buf->selend = buf->len - 1;
		}
		if (!(buf->data))
			buf->channels = 2;
		use_pointer();
	}
	XtVaGetValues(buf->param_dialog_b8, XmNset, &testv, NULL);
	if (testv)
		buf->bits = 8;
	XtVaGetValues(buf->param_dialog_b16, XmNset, &testv, NULL);
	if (testv)
		buf->bits = 16;
	XtVaGetValues(buf->param_dialog_b24, XmNset, &testv, NULL);
	if (testv)
		buf->bits = 24;
	XtVaGetValues(buf->param_dialog_b32, XmNset, &testv, NULL);
	if (testv)
		buf->bits = 32;
	XtVaGetValues(buf->param_dialog_fraw, XmNset, &testv, NULL);
	if (testv)
		buf->filef = FILEF_RAW;
	XtVaGetValues(buf->param_dialog_fsun, XmNset, &testv, NULL);
	if (testv)
		buf->filef = FILEF_SUN;
	XtVaGetValues(buf->param_dialog_friff, XmNset, &testv, NULL);
	if (testv)
		buf->filef = FILEF_RIFF;
	XtVaGetValues(buf->param_dialog_frifx, XmNset, &testv, NULL);
	if (testv)
		buf->filef = FILEF_RIFX;
	XtVaGetValues(buf->param_dialog_faiff, XmNset, &testv, NULL);
	if (testv)
		buf->filef = FILEF_AIFF;
	XtVaGetValues(buf->param_dialog_faifc, XmNset, &testv, NULL);
	if (testv)
		buf->filef = FILEF_AIFC;
	render_all(buf->canvas, buf);
}

/*
	param_hide_dialog(w, buf) unmanages the parameter dialog.
*/

void param_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->param_dialog);
}

/*
	param_query(w, buf) prepares the parameter dialog and manages it.
*/

void param_query(Widget w, struct buffer *buf) {
	char buffer[20];

	/* set widget states to those of buffer */
	sprintf(buffer, "%d", buf->rate);
	XtVaSetValues(buf->param_dialog_srw,
		XmNvalue, buffer,
		NULL);
	XtVaSetValues(buf->param_dialog_ch1,
		XmNset, (buf->channels == 1 ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_ch2,
		XmNset, (buf->channels == 2 ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_b8,
		XmNset, (buf->bits == 8 ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_b16,
		XmNset, (buf->bits == 16 ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_b24,
		XmNset, (buf->bits == 24 ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_b32,
		XmNset, (buf->bits == 32 ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_fraw,
		XmNset, (buf->filef == FILEF_RAW ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_fsun,
		XmNset, (buf->filef == FILEF_SUN ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_friff,
		XmNset, (buf->filef == FILEF_RIFF ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_frifx,
		XmNset, (buf->filef == FILEF_RIFX ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_faiff,
		XmNset, (buf->filef == FILEF_AIFF ? True : False),
		NULL);
	XtVaSetValues(buf->param_dialog_faifc,
		XmNset, (buf->filef == FILEF_AIFC ? True : False),
		NULL);

	XtManageChild(buf->param_dialog);
}

void resample_really(Widget w, struct buffer *buf) {
	char *text;
	Boolean testv;
	int newrate, wlen, wfunc = WFUNC_RECTANGULAR;

	if (buf->data) {
		XtVaGetValues(buf->resample_dialog_srw, XmNvalue, &text, NULL);
		if (numchk(text)) {
			xferr(ENUM_MSG);
			return;
		} else
			newrate = atoi(text);
		XtVaGetValues(buf->resample_dialog_wlw, XmNvalue, &text, NULL);
		if (numchk(text)) {
			xferr(ENUM_MSG);
			return;
		} else
			wlen = atoi(text);
		XtVaGetValues(buf->resample_dialog_rect, XmNset, &testv, NULL);
		if (testv)
			wfunc = WFUNC_RECTANGULAR;
		XtVaGetValues(buf->resample_dialog_bart, XmNset, &testv, NULL);
		if (testv)
			wfunc = WFUNC_BARTLETT;
		XtVaGetValues(buf->resample_dialog_black, XmNset, &testv,
			NULL);
		if (testv)
			wfunc = WFUNC_BLACKMAN;
		XtVaGetValues(buf->resample_dialog_ham, XmNset, &testv, NULL);
		if (testv)
			wfunc = WFUNC_HAMMING;
		XtVaGetValues(buf->resample_dialog_han, XmNset, &testv, NULL);
		if (testv)
			wfunc = WFUNC_HANNING;
		use_xcwatch();
		resample(buf, newrate, wlen, wfunc);
		buf->dispstart = 0;
		buf->dispend = buf->len - 1;
		buf->selstart = buf->selend = buf->selmask = 0;
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void resample_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->resample_dialog);
}

void resample_query(Widget w, struct buffer *buf) {
	char buffer[20];

	sprintf(buffer, "%d", buf->rate);
	XtVaSetValues(buf->resample_dialog_srw,
		XmNvalue, buffer,
		NULL);
	XtVaSetValues(buf->resample_dialog_wlw,
		XmNvalue, "15",
		NULL);
	XtManageChild(buf->resample_dialog);
}

void mono_really(Widget w, struct buffer *buf) {
	int ibalance;
	float balance;

	if (buf->data) {
		if (buf->channels == 2) {
			XtVaGetValues(buf->mono_dialog_bal,
				XmNvalue, &ibalance, NULL);
			balance = (float)ibalance / 1000.0f;
			use_xcwatch();
			buf_tomono(buf, balance);
			render_all(buf->canvas, buf);
			use_pointer();
		}
	} else {
		buf->channels = 1;
		render_all(buf->canvas, buf);
	}
}

void mono_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->mono_dialog);
}

void mono_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->mono_dialog);
}

void stereo_really(Widget w, struct buffer *buf) {
	if (buf->data) {
		if (buf->channels == 1) {
			use_xcwatch();
			buf_tostereo(buf);
			render_all(buf->canvas, buf);
			use_pointer();
		}
	} else {
		buf->channels = 2;
		render_all(buf->canvas, buf);
	}
}

void phase_invert(Widget w, struct buffer *buf) {
	if (buf->data) {
		use_xcwatch();
		buf_invert(buf);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void range_reverse(Widget w, struct buffer *buf) {
	if (buf->data) {
		use_xcwatch();
		buf_reverse(buf);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void mix_really(Widget w, struct buffer *buf) {
	XmString *selected;
	char *s, *t;
	Boolean autogrow;
	int isratio, n;
	float sratio;
	struct buffer *p;

	XtVaGetValues(buf->mix_dialog_list,
		XmNselectedItems, &selected,
		XmNselectedItemCount, &n,
		NULL);
	if (!n)				/* return if nothing selected */
		return;
	/* find the selected buffer */
	for (p = root; p; p = p->succ) {
		XmStringGetLtoR(*selected, XmSTRING_DEFAULT_CHARSET, &s);
		XmStringGetLtoR(p->xname, XmSTRING_DEFAULT_CHARSET, &t);
		if (!strcmp(s, t))
			break;
	}
	/* buffer destroyed between list creation and this callback? */
	if (!p)
		return;
	XtVaGetValues(buf->mix_dialog_ratio,
		XmNvalue, &isratio,
		NULL);
	XtVaGetValues(buf->mix_dialog_auto,
		XmNset, &autogrow,
		NULL);
	sratio = (float)isratio / 1000.0f;
	use_xcwatch();
	buf_mix(buf, p, sratio, autogrow);
	render_all(buf->canvas, buf);
	use_pointer();
}

void mix_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->mix_dialog);
}

void mix_query(Widget w, struct buffer *buf) {
	struct buffer *p;

	/* do nothing if dialog is already managed */
	if (XtIsManaged(buf->mix_dialog))
		return;

	/* destroy old list */
	XmListDeleteAllItems(buf->mix_dialog_list);

	/* fill the list with other nonempty buffers */
	for (p = root; p; p = p->succ)
		if (buf != p && p->data)
			XmListAddItemUnselected(buf->mix_dialog_list, p->xname,
				0);

	XtManageChild(buf->mix_dialog);
}

void vol_really(Widget w, struct buffer *buf) {
	int istart, iend;
	float fstart, fend;

	if (buf->data) {
		XtVaGetValues(buf->vol_dialog_st, XmNvalue, &istart, NULL);
		XtVaGetValues(buf->vol_dialog_end, XmNvalue, &iend, NULL);
		fstart = pow(10.0, (double)istart / 200.0);
		fend = pow(10.0, (double)iend / 200.0);
		use_xcwatch();
		eff_volume(buf, fstart, fend);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void vol_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->vol_dialog);
}

void vol_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->vol_dialog);
}

void echo_really(Widget w, struct buffer *buf) {
	int igain, ifeedback, idelay;
	float gain, feedback, delay;

	if (buf->data) {
		XtVaGetValues(buf->echo_dialog_gain, XmNvalue, &igain, NULL);
		XtVaGetValues(buf->echo_dialog_fb, XmNvalue, &ifeedback, NULL);
		XtVaGetValues(buf->echo_dialog_delay, XmNvalue, &idelay, NULL);
		if (!idelay) {
			xferr("Echo delay of zero rejected, "
				"operation aborted");
			return;
		}
		gain = pow(10.0, (double)igain / 200.0f);
		feedback = pow(10.0, (double)ifeedback / 200.0f);
		delay = (float)idelay / 1000.0f;
		use_xcwatch();
		eff_echo(buf, gain, feedback, delay);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void echo_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->echo_dialog);
}

void echo_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->echo_dialog);
}

void reverb_really(Widget w, struct buffer *buf) {
	int idry, iwet, idamp, ifb;
	float dry, wet, damp, fb;

	if (buf->data) {
		use_xcwatch();
		XtVaGetValues(buf->rev_dialog_dry, XmNvalue, &idry, NULL);
		XtVaGetValues(buf->rev_dialog_wet, XmNvalue, &iwet, NULL);
		XtVaGetValues(buf->rev_dialog_damp, XmNvalue, &idamp, NULL);
		XtVaGetValues(buf->rev_dialog_fb, XmNvalue, &ifb, NULL);
		dry = pow(10.0, (double)idry / 200.0);
		wet = pow(10.0, (double)iwet / 200.0);
		damp = (float)idamp / 100.0f;
		fb = pow(10.0, (double)ifb / 200.0);
		eff_reverb(buf, dry, wet, damp, fb);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void reverb_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->rev_dialog);
}

void reverb_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->rev_dialog);
}

void flange_really(Widget w, struct buffer *buf) {
	int idelay, idepth, ifreq;
	float delay, depth, freq;

	if (buf->data) {
		XtVaGetValues(buf->flan_dialog_delay, XmNvalue, &idelay, NULL);
		XtVaGetValues(buf->flan_dialog_depth, XmNvalue, &idepth, NULL);
		XtVaGetValues(buf->flan_dialog_freq, XmNvalue, &ifreq, NULL);
		delay = (float)idelay / 10.0f;
		depth = (float)idepth / 10.0f;
		freq = (float)ifreq / 100.0f;
		use_xcwatch();
		eff_flange(buf, delay, depth, freq);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void flange_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->flan_dialog);
}

void flange_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->flan_dialog);
}

void filt_apply(Widget w, struct buffer *buf) {
	char *freq;
	double lcf, ucf, tmp;
	Boolean testv;
	int order = 1, type = F_LP;

	if (buf->data) {
		XtVaGetValues(buf->filt_dialog_lcw, XmNvalue, &freq, NULL);
		if (numchk(freq)) {
			xferr(ENUM_MSG);
			return;
		} else
			lcf = atof(freq);
		XtVaGetValues(buf->filt_dialog_ucw, XmNvalue, &freq, NULL);
		if (numchk(freq)) {
			xferr(ENUM_MSG);
			return;
		} else
			ucf = atof(freq);
		XtVaGetValues(buf->filt_dialog_o1, XmNset, &testv, NULL);
		if (testv) {
			order = 1;
		}
		XtVaGetValues(buf->filt_dialog_o2, XmNset, &testv, NULL);
		if (testv) {
			order = 2;
		}
		XtVaGetValues(buf->filt_dialog_tlp, XmNset, &testv, NULL);
		if (testv)
			type = F_LP;
		XtVaGetValues(buf->filt_dialog_thp, XmNset, &testv, NULL);
		if (testv)
			type = F_HP;
		XtVaGetValues(buf->filt_dialog_tbp, XmNset, &testv, NULL);
		if (testv)
			type = F_BP;
		XtVaGetValues(buf->filt_dialog_tbr, XmNset, &testv, NULL);
		if (testv)
			type = F_BR;
		/* if bandpass or bandreject, ensure that lower cutoff */
		/* really is lower than higher */
		if (lcf > ucf && (type == F_BP || type == F_BR)) {
			tmp = lcf;
			lcf = ucf;
			ucf = tmp;
		}
		use_xcwatch();
		eff_bfilter(buf, (float)lcf, (float)ucf, order, type);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void filt_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->filt_dialog);
}

void filt_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->filt_dialog);
}

void comp_really(Widget w, struct buffer *buf) {
	int idyn, ivel;
	float fdyn, fvel;

	if (buf->data) {
		XtVaGetValues(buf->comp_dialog_dyn, XmNvalue, &idyn, NULL);
		XtVaGetValues(buf->comp_dialog_vel, XmNvalue, &ivel, NULL);
		fdyn = (float)idyn / 1000.0f;
		fvel = (float)ivel;
		use_xcwatch();
		eff_compress(buf, fdyn, fvel);
		render_all(buf->canvas, buf);
		use_pointer();
	}
}

void comp_hide_dialog(Widget w, struct buffer *buf) {
	XtUnmanageChild(buf->comp_dialog);
}

void comp_query(Widget w, struct buffer *buf) {
	XtManageChild(buf->comp_dialog);
}

void okprompt_set(Widget w, struct buffer *buf) {
	struct buffer *p;
	Widget q;

	XtVaGetValues(w, XmNset, &okprompts, NULL);
	for (p = root; p; p = p->succ) {
		q = XtNameToWidget(p->menubar, "popup_file.options.okPrompts");
		XtVaSetValues(q, XmNset, okprompts, NULL);
	}
}

void about_manage(Widget w, struct buffer *buf) {
	XtManageChild(about_dialog);
}

void about_unmanage(Widget w, struct buffer *buf) {
	XtUnmanageChild(about_dialog);
}

void license_manage(Widget w, struct buffer *buf) {
	XtManageChild(license_dialog);
}
