[BACK]Return to gui_athena.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

File: [local] / src / usr.bin / vim / Attic / gui_athena.c (download)

Revision 1.1.1.1 (vendor branch), Sat Sep 7 21:40:28 1996 UTC (27 years, 9 months ago) by downsj
Branch: VIM
CVS Tags: VIM42
Changes since 1.1: +0 -0 lines

Initial import of vim 4.2.

This is meant to replace nvi in the tree.  Vim, in general, works better,
provides more features, and does not suffer from the license problems
being imposed upon nvi.

On the other hand, vim lacks a non-visual ex mode, in addition to open mode.

This includes the GUI (X11) code, but doesn't try to compile it.


/*	$OpenBSD: gui_athena.c,v 1.1.1.1 1996/09/07 21:40:28 downsj Exp $	*/
/* vi:set ts=4 sw=4:
 *
 * VIM - Vi IMproved			by Bram Moolenaar
 *								GUI/Motif support by Robert Webb
 *								Athena port by Bill Foster
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Box.h>

#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "option.h"
#include "ops.h"
#include "gui_at_sb.h"

#define puller_width	19
#define puller_height	19

static char puller_bits[] =
{
	0x00,0x00,0xf8,0x00,0x00,0xf8,0xf8,0x7f,0xf8,0x04,0x80,0xf8,0x04,0x80,0xf9,
	0x84,0x81,0xf9,0x84,0x83,0xf9,0x84,0x87,0xf9,0x84,0x8f,0xf9,0x84,0x8f,0xf9,
	0x84,0x87,0xf9,0x84,0x83,0xf9,0x84,0x81,0xf9,0x04,0x80,0xf9,0x04,0x80,0xf9,
	0xf8,0xff,0xf9,0xf0,0x7f,0xf8,0x00,0x00,0xf8,0x00,0x00,0xf8
};

extern Widget vimShell;

static Widget vimPanes;
static Widget vimForm = (Widget)NULL;
static Widget textArea;
static Widget scrollbarBox[3];		/* Left, right & bottom scrollbar boxes */
static Widget bottomScrollbar;			/* Bottom scrollbar */
static Widget leftBottomScrollFiller;	/* Left filler for bottom scrollbar */
static Widget rightBottomScrollFiller;	/* Right filler for bottom scrollbar */
static Widget leftScrollbarFiller;		/* Filler for left scrollbar */
static Widget rightScrollbarFiller;		/* Filler for right scrollbar */
static Widget menuBar;

static void gui_athena_scroll_cb_jump   __ARGS((Widget, XtPointer, XtPointer));
static void gui_athena_scroll_cb_scroll __ARGS((Widget, XtPointer, XtPointer));
static void gui_athena_reorder_menus    __ARGS((void));
static void	gui_athena_pullright_action __ARGS((Widget, XEvent *, String *,
												Cardinal *));

static XtActionsRec		pullAction = { "menu-pullright",
								(XtActionProc)gui_athena_pullright_action };
static XtTranslations	parentTrans, menuTrans;
static Pixmap			pullerBitmap;

/*
 * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
 * left or middle mouse button.
 */
	static void
gui_athena_scroll_cb_jump(w, client_data, call_data)
	Widget		w;
	XtPointer	client_data, call_data;
{
	char_u		bytes[4 + sizeof(long_u)];
	WIN			*wp;
	GuiScrollbar *sb;
	int			sb_num;
	int         i;
	int         byte_count;
	long_u		value;

	gui.dragged_sb = SB_NONE;
	for (i = 0; i <= SB_BOTTOM; i++)
		if (XtParent(w) == scrollbarBox[i])
		{
			gui.dragged_sb = i;
			break;
		}

	switch (gui.dragged_sb)
	{
		case SB_LEFT:
		case SB_RIGHT:
			gui.dragged_wp = (WIN *)client_data;
			sb_num = 0;
			wp = firstwin;
			for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
				sb_num++;

			if (gui.dragged_wp == NULL)
				return;

			sb = &wp->w_scrollbar;

			value = *((float *)call_data) * (float)sb->max + 0.5;
			++value;						/* range is 1 to line_count */
			sb->value = value;
			
			bytes[0] = CSI;
			bytes[1] = KS_SCROLLBAR;
			bytes[2] = K_FILLER;
			bytes[3] = (char_u)sb_num;
			byte_count = 4;
			break;

		case SB_BOTTOM:
											/* why not use sb->max? */
			value = *((float *)call_data) *
									(float)(gui_get_max_horiz_scroll()) + 0.5;
			bytes[0] = CSI;
			bytes[1] = KS_HORIZ_SCROLLBAR;
			bytes[2] = K_FILLER;
			byte_count = 3;
			break;

		case SB_NONE:
		default:
			return;
	}

	add_long_to_buf(value, bytes + byte_count);
	add_to_input_buf(bytes, byte_count + sizeof(long_u));
}

/*
 * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
 * right mouse buttons.
 */
	static void
gui_athena_scroll_cb_scroll(w, client_data, call_data)
	Widget		w;
	XtPointer	client_data, call_data;
{
	char_u		bytes[4 + sizeof(long_u)];
	WIN			*wp;
	GuiScrollbar *sb;
	int			sb_num;
	int         i;
	int         byte_count;
	long		value;
	int			data = (int)call_data;

	for (i = 0; i <= SB_BOTTOM; i++)
		if (XtParent(w) == scrollbarBox[i])
		{
			gui.dragged_sb = i;
			break;
		}

	switch (gui.dragged_sb)
	{
		case SB_LEFT:
		case SB_RIGHT:
			gui.dragged_wp = (WIN *)client_data;
			sb_num = 0;
			wp = firstwin;
			for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
				sb_num++;

			if (gui.dragged_wp == NULL)
				return;

			sb = &wp->w_scrollbar;
			
			if (sb->size > 5)
				i = sb->size - 2;		/* use two lines of context */
			else
				i = sb->size;
			switch (data)
			{
				case  ONE_LINE_DATA: data = 1; break;
				case -ONE_LINE_DATA: data = -1; break;
				case  ONE_PAGE_DATA: data = i; break;
				case -ONE_PAGE_DATA: data = -i; break;
				case  END_PAGE_DATA: data = sb->max; break;
				case -END_PAGE_DATA: data = -sb->max; break;
							default: data = 0; break;
			}
			value = sb->value + data;
			if (value > sb->max)
				value = sb->max;
			else if (value < 1)			/* range is 1 to line_count */
				value = 1;

			bytes[0] = CSI;
			bytes[1] = KS_SCROLLBAR;
			bytes[2] = K_FILLER;
			bytes[3] = (char_u)sb_num;
			byte_count = 4;
			break;

		case SB_BOTTOM:
			if (data < -1)
				data = -(Columns - 5);
			else if (data > 1)
				data = (Columns - 5);
			value = curwin->w_leftcol + data;
			if (value < 0)				/* range is 0 to max_col */
				value = 0;
			else
			{
				int max;
										/* why not use sb->max here? */
				max = gui_get_max_horiz_scroll();
				if (value >= max)
					value = max;
			}

			bytes[0] = CSI;
			bytes[1] = KS_HORIZ_SCROLLBAR;
			bytes[2] = K_FILLER;
			byte_count = 3;
			break;

		case SB_NONE:
		default:
			return;
	}

	/*
	 * This type of scrolling doesn't move the thumb automatically so we need
	 * make sure the scrollbar still gets updated.
	 */
	gui.dragged_sb = SB_NONE;

	add_long_to_buf((long_u)value, bytes + byte_count);
	add_to_input_buf(bytes, byte_count + sizeof(long_u));
}

/*
 * Create all the Athena widgets necessary.
 */
	void
gui_mch_create_widgets()
{
	Dimension	base_width, base_height;

	/*
	 * We don't have any borders handled internally by the textArea to worry
	 * about so only skip over the configured border width.
	 */
	gui.border_offset = gui.border_width;

	base_width  = 2 * gui.border_offset;
	base_height = 2 * gui.border_offset;

	XtInitializeWidgetClass(panedWidgetClass);
	XtInitializeWidgetClass(simpleMenuWidgetClass);
	XtInitializeWidgetClass(vim_scrollbarWidgetClass);
	XtInitializeWidgetClass(labelWidgetClass);

	/* Panes for menu bar, middle stuff, and bottom scrollbar box */
	vimPanes = XtVaCreateManagedWidget("vimPanes",
		panedWidgetClass,	vimShell,
		XtNorientation,		XtorientVertical,
		NULL);

	/* The top menu bar */
	menuBar = XtVaCreateManagedWidget("menuBar",
		boxWidgetClass,			vimPanes,
		XtNmin,					gui.menu_height,
		XtNborderWidth,			1,
		XtNallowResize,			True,
		XtNresizeToPreferred,	True,
		XtNskipAdjust,			True,
		XtNshowGrip,			False,
		XtNforeground,			gui.menu_fg_pixel,
		XtNbackground,			gui.menu_bg_pixel,
		XtNborderColor,			gui.menu_fg_pixel,
		NULL);

	/*
	 * Panes for the middle stuff (left scrollbar box, text area, and right
	 * scrollbar box.
	 */
	vimForm = XtVaCreateManagedWidget("vimForm",
		panedWidgetClass,		vimPanes,
		XtNallowResize,			True,
		XtNorientation,			XtorientHorizontal,
		XtNborderWidth,			0,
		XtNdefaultDistance,		0,
		XtNshowGrip,			False,
		NULL);

	/* Panes for the left window scrollbars. */
	scrollbarBox[SB_LEFT] = XtVaCreateWidget("scrollBarBox",
		panedWidgetClass,		vimForm,
		XtNpreferredPaneSize,	gui.scrollbar_width,
		XtNallowResize,			True,
		XtNskipAdjust,			True,
		XtNborderWidth,			1,
		XtNshowGrip,			False,
		XtNforeground,			gui.scroll_fg_pixel,
		XtNbackground,			gui.scroll_fg_pixel,
		XtNborderColor,			gui.scroll_fg_pixel,
		NULL);

	/* The text area. */
	textArea = XtVaCreateManagedWidget("textArea",
		coreWidgetClass,		vimForm,
		XtNallowResize,			True,
		XtNshowGrip,			False,
		XtNbackground,			gui.back_pixel,
		XtNborderWidth,			0,
		XtNheight,				Rows * gui.char_height + base_height,
		XtNwidth,				Columns * gui.char_width + base_width,
		NULL);

	/* Panes for the right window scrollbars. */
	scrollbarBox[SB_RIGHT] = XtVaCreateWidget("scrollBarBox",
		panedWidgetClass,		vimForm,
		XtNpreferredPaneSize,	gui.scrollbar_width,
		XtNallowResize,			True,
		XtNskipAdjust,			True,
		XtNborderWidth,			1,
		XtNresizeToPreferred,	True,
		XtNshowGrip,			False,
		XtNforeground,			gui.scroll_fg_pixel,
		XtNbackground,			gui.scroll_fg_pixel,
		XtNborderColor,			gui.scroll_fg_pixel,
		NULL);

	/* Panes for the bottom scrollbar and fillers on each side. */
	scrollbarBox[SB_BOTTOM] = XtVaCreateWidget("scrollBarBox",
		panedWidgetClass,		vimPanes,
		XtNpreferredPaneSize,	gui.scrollbar_width,
		XtNallowResize,			True,
		XtNskipAdjust,			True,
		XtNborderWidth,			1,
		XtNresizeToPreferred,	True,
		XtNshowGrip,			False,
		XtNforeground, 			gui.scroll_fg_pixel,
		XtNbackground, 			gui.scroll_fg_pixel,
		XtNborderColor,			gui.scroll_fg_pixel,
		XtNorientation, 		XtorientHorizontal,
		NULL);

	/* A filler for the gap on the left side of the bottom scrollbar. */
	leftBottomScrollFiller = XtVaCreateManagedWidget("",
		labelWidgetClass,	scrollbarBox[SB_BOTTOM],
		XtNshowGrip,		False,
		XtNresize,			False,
		XtNborderWidth,		4,
		XtNmin,				gui.scrollbar_width + 1,
		XtNmax,				gui.scrollbar_width + 1,
		XtNforeground,		gui.scroll_fg_pixel,
		XtNbackground,		gui.scroll_fg_pixel,
		XtNborderColor,		gui.scroll_fg_pixel,
		NULL);

	/* The bottom scrollbar. */
	bottomScrollbar = XtVaCreateManagedWidget("bottomScrollBar",
		vim_scrollbarWidgetClass,	scrollbarBox[SB_BOTTOM],
		XtNresizeToPreferred,	True,
		XtNallowResize,			True,
		XtNskipAdjust,			True,
		XtNshowGrip,			False,
		XtNorientation,			XtorientHorizontal,
		XtNforeground,			gui.scroll_fg_pixel,
		XtNbackground,			gui.scroll_bg_pixel,
		NULL);

	XtAddCallback(bottomScrollbar, XtNjumpProc,
			gui_athena_scroll_cb_jump, (XtPointer)NULL);
	XtAddCallback(bottomScrollbar, XtNscrollProc,
			gui_athena_scroll_cb_scroll, (XtPointer)NULL);

	vim_XawScrollbarSetThumb(bottomScrollbar, 0., 1., 0.);

	/* A filler for the gap on the right side of the bottom scrollbar. */
	rightBottomScrollFiller = XtVaCreateManagedWidget("",
		labelWidgetClass,	scrollbarBox[SB_BOTTOM],
		XtNshowGrip,		False,
		XtNresize,			False,
		XtNborderWidth,		4,
		XtNmin,				gui.scrollbar_width + 1,
		XtNmax,				gui.scrollbar_width + 1,
		XtNforeground,		gui.scroll_fg_pixel,
		XtNbackground,		gui.scroll_fg_pixel,
		NULL);

	/* A filler for the gap on the bottom of the left scrollbar. */
	leftScrollbarFiller = XtVaCreateManagedWidget("",
		labelWidgetClass,	scrollbarBox[SB_LEFT],
		XtNshowGrip,		False,
		XtNresize,			False,
		XtNborderWidth,		4,
		XtNmin,				gui.scrollbar_width + 1,
		XtNmax,				gui.scrollbar_width + 1,
		XtNforeground,		gui.scroll_fg_pixel,
		XtNbackground,		gui.scroll_fg_pixel,
		NULL);

	/* A filler for the gap on the bottom of the right scrollbar. */
	rightScrollbarFiller = XtVaCreateManagedWidget("",
		labelWidgetClass,	scrollbarBox[SB_RIGHT],
		XtNshowGrip,		False,
		XtNresize,			False,
		XtNborderWidth,		4,
		XtNmin,				gui.scrollbar_width + 1,
		XtNmax,				gui.scrollbar_width + 1,
		XtNforeground,		gui.scroll_fg_pixel,
		XtNbackground,		gui.scroll_fg_pixel,
		NULL);

	gui.num_scrollbars = 0;

	/*
	 * Text area callbacks
	 */
	XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
		gui_x11_visibility_cb, (XtPointer)0);

	XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
		(XtPointer)0);

	XtAddEventHandler(textArea, StructureNotifyMask, FALSE,
		gui_x11_resize_window_cb, (XtPointer)0);

	XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
		(XtPointer)0);

	XtAddEventHandler(vimPanes, KeyPressMask, FALSE, gui_x11_key_hit_cb,
		(XtPointer)0);

	XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
		ButtonMotionMask, FALSE, gui_x11_mouse_cb, (XtPointer)0);

	parentTrans = XtParseTranslationTable("<BtnMotion>: highlight() menu-pullright()");
	menuTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight() MenuPopdown()\n<BtnUp>: notify() unhighlight() MenuPopdown()\n<BtnMotion>: highlight()");

	XtAppAddActions(XtWidgetToApplicationContext(vimForm), &pullAction, 1);

	pullerBitmap = XCreateBitmapFromData(gui.dpy, DefaultRootWindow(gui.dpy),
							(char *)puller_bits, puller_width, puller_height);
}

	int
gui_mch_get_winsize()
{
	Dimension	base_width, base_height;
	Dimension	total_width, total_height;
	Dimension	left_width = 0, right_width = 0;
	Dimension	bottom_height = 0, menu_height = 0;

	base_height = 2 * gui.border_offset;
	base_width  = 2 * gui.border_offset;

	if (gui.which_scrollbars[SB_LEFT])
		XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);

	if (gui.which_scrollbars[SB_RIGHT])
		XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);

	if (gui.which_scrollbars[SB_BOTTOM])
		XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);

	if (XtIsManaged(menuBar))
		XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);

	base_width  += left_width + right_width;
	base_height += menu_height + bottom_height;

	XtVaGetValues(vimShell,
		XtNheight, &total_height,
		XtNwidth,  &total_width,
		NULL);

	gui.num_rows = (total_height - base_height) / gui.char_height;
	gui.num_cols = (total_width  - base_width)  / gui.char_width;

	Rows    = gui.num_rows;
	Columns = gui.num_cols;
	gui_reset_scroll_region();

	return OK;
}

	void
gui_mch_set_winsize()
{
	Dimension	left_width = 0, right_width = 0;
	Dimension	bottom_height = 0, menu_height = 0;
	Dimension	base_width, base_height;

	base_width  = 2 * gui.border_offset;
	base_height = 2 * gui.border_offset;

	if (gui.which_scrollbars[SB_LEFT])
		XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);

	if (gui.which_scrollbars[SB_RIGHT])
		XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);

	if (gui.which_scrollbars[SB_BOTTOM])
		XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);

	if (XtIsManaged(menuBar))
		XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);

	base_width  += left_width + right_width;
	base_height += menu_height + bottom_height;

	XtVaSetValues(vimShell,
		XtNwidthInc,   gui.char_width,
		XtNheightInc,  gui.char_height,
		XtNbaseWidth,  base_width,
		XtNbaseHeight, base_height,
		XtNminWidth,   base_width  + MIN_COLUMNS * gui.char_width,
		XtNminHeight,  base_height + MIN_ROWS    * gui.char_height,
		XtNwidth,	   base_width  + Columns     * gui.char_width,
		XtNheight,	   base_height + Rows        * gui.char_height,
		NULL);
}

/*
 * Menu stuff.
 */

	void
gui_mch_add_menu(menu, parent)
	GuiMenu	*menu;
	GuiMenu	*parent;
{
	char_u	*pullright_name;

	if (parent == NULL)
	{
		menu->id = XtVaCreateManagedWidget(menu->name,
			menuButtonWidgetClass, menuBar,
			XtNmenuName, menu->name,
			XtNforeground, gui.menu_fg_pixel,
			XtNbackground, gui.menu_bg_pixel,
			NULL);

		menu->submenu_id = XtVaCreatePopupShell(menu->name,
			simpleMenuWidgetClass, menu->id,
			XtNforeground, gui.menu_fg_pixel,
			XtNbackground, gui.menu_bg_pixel,
			NULL);

		gui_athena_reorder_menus();
	}
	else
	{
		menu->id = XtVaCreateManagedWidget(menu->name,
			smeBSBObjectClass, parent->submenu_id,
			XtNforeground, gui.menu_fg_pixel,
			XtNbackground, gui.menu_bg_pixel,
			XtNrightMargin, puller_width,
			XtNrightBitmap, pullerBitmap,

			NULL);
		XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
			(XtPointer)menu);

		pullright_name = strnsave(menu->name, strlen(menu->name) +
														strlen("-pullright"));
		strcat(pullright_name, "-pullright");
		menu->submenu_id = XtVaCreatePopupShell(pullright_name,
			simpleMenuWidgetClass, parent->submenu_id,
			XtNforeground, gui.menu_fg_pixel,
			XtNbackground, gui.menu_bg_pixel,
			XtNtranslations, menuTrans,
			NULL);
		vim_free(pullright_name);

		XtOverrideTranslations(parent->submenu_id, parentTrans);
	}
}

	void
gui_mch_add_menu_item(menu, parent)
	GuiMenu	*menu;
	GuiMenu	*parent;
{
	menu->submenu_id = (Widget)0;
	menu->id = XtVaCreateManagedWidget(menu->name,
		smeBSBObjectClass, parent->submenu_id,
		XtNforeground, gui.menu_fg_pixel,
		XtNbackground, gui.menu_bg_pixel,
		NULL);
	XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
		(XtPointer)menu);
}

/*
 * Destroy the machine specific menu widget.
 */
	void
gui_mch_destroy_menu(menu)
	GuiMenu	*menu;
{
	if (menu->id != (Widget)NULL)
	{
		/*
		 * This is a hack for the Athena simpleMenuWidget to keep it from
		 * getting a BadValue error when it's last child is destroyed. We
		 * check to see if this is the last child and if so, go ahead and
		 * delete the parent ahead of time. The parent will delete it's
		 * children like all good widgets do.
		 */
		if (XtParent(menu->id) != menuBar)
		{
			int num_children;

			XtVaGetValues(XtParent(menu->id),
					XtNnumChildren, &num_children, NULL);
			if (num_children <= 1)
				XtDestroyWidget(XtParent(menu->id));
			else
				XtDestroyWidget(menu->id);
		}
		else
			XtDestroyWidget(menu->id);
		menu->id = (Widget)NULL;
	}
}

/*
 * Reorder the menus so "Help" is the rightmost item on the menu.
 */
	static void
gui_athena_reorder_menus()
{
	Widget	*children;
	Widget  help_widget = (Widget)NULL;
	int		num_children;
	int		i;

	XtVaGetValues(menuBar,
			XtNchildren,    &children,
			XtNnumChildren, &num_children,
			NULL);

	XtUnmanageChildren(children, num_children);

	for (i = 0; i < num_children - 1; i++)
		if (help_widget == (Widget)NULL)
		{
			if (strcmp((char *)XtName(children[i]), "Help") == 0)
			{
				help_widget = children[i];
				children[i] = children[i + 1];
			}
		}
		else
			children[i] = children[i + 1];

	if (help_widget != (Widget)NULL)
		children[num_children - 1] = help_widget;

	XtManageChildren(children, num_children);
}


/*
 * Scrollbar stuff:
 */

	void
gui_mch_create_which_components()
{
	static int prev_which_scrollbars[3] = {-1, -1, -1};
	static int prev_menu_is_active = -1;

	int		  i;
	WIN		  *wp;

	/*
	 * When removing the left/right scrollbar and creating the right/left
	 * scrollbar, we have to force a redraw (the size of the text area doesn't
	 * change).
	 */
	if (prev_which_scrollbars[SB_LEFT] != gui.which_scrollbars[SB_LEFT] &&
			prev_which_scrollbars[SB_RIGHT] != gui.which_scrollbars[SB_RIGHT])
		must_redraw = CLEAR;

	gui_x11_use_resize_callback(textArea, FALSE);

	for (i = 0; i < 3; i++)
	{
		if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
		{
			if (gui.which_scrollbars[i])
			{
				switch (i)
				{
					/* When adding the left one, we need to reorder them all */
					case SB_LEFT:
						XtUnmanageChild(textArea);
						if (gui.which_scrollbars[SB_RIGHT])
							XtUnmanageChild(scrollbarBox[SB_RIGHT]);
						XtManageChild(scrollbarBox[SB_LEFT]);
						XtManageChild(textArea);
						if (gui.which_scrollbars[SB_RIGHT])
							XtManageChild(scrollbarBox[SB_RIGHT]);

						/*
						 * When adding at the left and we have a bottom
						 * scrollbar, we need to reorder these too.
						 */
						if (gui.which_scrollbars[SB_BOTTOM])
						{
							XtUnmanageChild(bottomScrollbar);
							if (gui.which_scrollbars[SB_RIGHT])
								XtUnmanageChild(rightBottomScrollFiller);

							XtManageChild(leftBottomScrollFiller);
							XtManageChild(bottomScrollbar);
							if (gui.which_scrollbars[SB_RIGHT])
								XtManageChild(rightBottomScrollFiller);
						}
						break;

					case SB_RIGHT:
						XtManageChild(rightBottomScrollFiller);
						XtManageChild(scrollbarBox[i]);
						break;

					case SB_BOTTOM:
						/* Unmanage the bottom scrollbar and fillers */
						XtUnmanageChild(leftBottomScrollFiller);
						XtUnmanageChild(bottomScrollbar);
						XtUnmanageChild(rightBottomScrollFiller);

						/*
						 * Now manage the bottom scrollbar and fillers that
						 * are supposed to be there.
						 */
						if (gui.which_scrollbars[SB_LEFT])
							XtManageChild(leftBottomScrollFiller);
						XtManageChild(bottomScrollbar);
						if (gui.which_scrollbars[SB_RIGHT])
							XtManageChild(rightBottomScrollFiller);

						XtManageChild(scrollbarBox[i]);
						break;
				}
			}
			else
			{
				switch (i)
				{
					case SB_LEFT:
						XtUnmanageChild(leftBottomScrollFiller);
						break;

					case SB_RIGHT:
						XtUnmanageChild(rightBottomScrollFiller);
						break;
				}
				XtUnmanageChild(scrollbarBox[i]);
			}
		}
		if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
		{
			if (i == SB_LEFT || i == SB_RIGHT)
			{
				if (gui.which_scrollbars[i])
				{
					/* Scrollbar box has just appeared */
					gui.new_sb[i] = TRUE;
				}
				else if (prev_which_scrollbars[i] == TRUE)
				{
					/* Scrollbar box has just been deleted */
					for (wp = firstwin; wp != NULL; wp = wp->w_next)
						XtDestroyWidget(wp->w_scrollbar.id[i]);
				}
			}
		}
		prev_which_scrollbars[i] = gui.which_scrollbars[i];
	}

	if (gui.menu_is_active != prev_menu_is_active)
	{
		if (gui.menu_is_active)
		{
			XtUnmanageChild(menuBar);
			XtUnmanageChild(vimForm);
			if (gui.which_scrollbars[SB_BOTTOM])
				XtUnmanageChild(scrollbarBox[SB_BOTTOM]);

			XtManageChild(menuBar);
			XtManageChild(vimForm);
			if (gui.which_scrollbars[SB_BOTTOM])
				XtManageChild(scrollbarBox[SB_BOTTOM]);
		}
		else
			XtUnmanageChild(menuBar);
		prev_menu_is_active = gui.menu_is_active;
	}

	gui_x11_use_resize_callback(textArea, TRUE);
	if (vimForm != (Widget)NULL && XtIsRealized(vimForm))
		gui_mch_set_winsize();
}


/*
 * Vertical scrollbar stuff:
 */
	void
gui_mch_update_scrollbars(worst_update, which_sb)
	int		worst_update;
	int		which_sb;		/* SB_LEFT or SB_RIGHT */
{
	WIN				*wp;
	GuiScrollbar	*sb;
	int				idx;
	Dimension		h;		/* Height of scrollbar (in pixels) */
	Dimension		y;		/* Coord of top of scrollbar (in pixels) */
	int				tmp;
	float			val = 0., size = 0.;

	if (worst_update >= SB_UPDATE_HEIGHT)
	{
		XawPanedSetRefigureMode(scrollbarBox[which_sb], False);
		gui_x11_use_resize_callback(textArea, FALSE);
	}

	/*
	 * This has to get cleared manually since Athena doesn't tell us when the
	 * draggin' stops.
	 */
	gui.dragged_sb = SB_NONE;

	for (wp = firstwin, idx = 0; wp; wp = wp->w_next, idx++)
	{
		sb = &wp->w_scrollbar;
		if (sb->update[which_sb] >= SB_UPDATE_VALUE)
		{
			val = (float)(sb->value - 1) / (float)sb->max;
			size = (float)sb->size / (float)sb->max;
		}
		if (sb->update[which_sb] == SB_UPDATE_CREATE)
		{
			sb->id[which_sb] = XtVaCreateManagedWidget("scrollBar",
					vim_scrollbarWidgetClass, scrollbarBox[which_sb],
					XtNborderWidth, 1,
					XtNdefaultDistance, 0,
					XtNallowResize, True,
					XtNpreferredPaneSize, True,
					XtNresizeToPreferred, True,
					XtNskipAdjust, True,
					XtNorientation, XtorientVertical,
					XtNshowGrip, False,
					XtNforeground, gui.scroll_fg_pixel,
					XtNbackground, gui.scroll_bg_pixel,
					NULL);
			XtAddCallback(sb->id[which_sb], XtNjumpProc,
				gui_athena_scroll_cb_jump, (XtPointer)wp);
			XtAddCallback(sb->id[which_sb], XtNscrollProc,
				gui_athena_scroll_cb_scroll, (XtPointer)wp);
		}
		if (sb->update[which_sb] >= SB_UPDATE_HEIGHT)
		{
			h = sb->height * gui.char_height
					+ sb->status_height * gui.char_height / 2;
			y = wp->w_winpos * gui.char_height + gui.border_offset;

			if (wp == firstwin)
			{
				/* Height of top scrollbar includes width of top border */
				h += gui.border_offset;
			}
			else
			{
				/*
				 * Height of other scrollbars includes half of status bar above
				 */
				tmp = wp->w_prev->w_status_height * (gui.char_height + 1) / 2;
				h += tmp;
				y -= tmp;
			}

			XtVaSetValues(sb->id[which_sb],
				XtNheight, h,
				XtNmin, h,
				XtNmax, h,
				XtNy, y,
				NULL);
			vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
		}
		else if (sb->update[which_sb] == SB_UPDATE_VALUE)
		{
			vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
		}
		sb->update[which_sb] = SB_UPDATE_NOTHING;
	}

	if (worst_update >= SB_UPDATE_HEIGHT)
	{
		if (worst_update >= SB_UPDATE_CREATE)
			gui_mch_reorder_scrollbars(which_sb);
		XawPanedSetRefigureMode(scrollbarBox[which_sb], True);
		gui_x11_use_resize_callback(textArea, TRUE);
	}
}

	void
gui_mch_reorder_scrollbars(which_sb)
	int		which_sb;
{
	WIN		*wp;

	if (which_sb == SB_LEFT)
		XtUnmanageChild(leftScrollbarFiller);
	else
		XtUnmanageChild(rightScrollbarFiller);

	for (wp = firstwin; wp != NULL; wp = wp->w_next)
		if (wp->w_scrollbar.id[which_sb] != NULL)
			XtUnmanageChild(wp->w_scrollbar.id[which_sb]);

	for (wp = firstwin; wp != NULL; wp = wp->w_next)
		if (wp->w_scrollbar.id[which_sb] != NULL)
			XtManageChild(wp->w_scrollbar.id[which_sb]);

	if (which_sb == SB_LEFT)
		XtManageChild(leftScrollbarFiller);
	else
		XtManageChild(rightScrollbarFiller);

}

	void
gui_mch_destroy_scrollbar(wp)
	WIN		*wp;
{
	if (gui.which_scrollbars[SB_LEFT])
		XtDestroyWidget(wp->w_scrollbar.id[SB_LEFT]);
	if (gui.which_scrollbars[SB_RIGHT])
		XtDestroyWidget(wp->w_scrollbar.id[SB_RIGHT]);
	gui.num_scrollbars--;
}


/*
 * Horizontal scrollbar stuff:
 */
	void
gui_mch_update_horiz_scrollbar(value, size, max)
	int		value;
	int		size;
	int		max;
{
	static int prev_value = -1, prev_size = -1, prev_max = -1;
	float val, shown, maxval;

	if (value == prev_value && size == prev_size && max == prev_max)
		return;

	prev_value = value;
	prev_size = size;
	prev_max = max;

	if (max == 1)			/* maximum is one more than maximal value */
	{
		val   = 0.0;
		shown = 1.0;
		maxval = 0.0;
	}
	else
	{
		val   = (float)value / (float)max;
		shown = (float)size  / (float)max;
		maxval = 1.0;
	}
	vim_XawScrollbarSetThumb(bottomScrollbar, val, shown, maxval);
}

	Window
gui_mch_get_wid()
{
	return( XtWindow(textArea) );
}

	static void
gui_athena_pullright_action(w, event, args, nargs)
	Widget		w;
	XEvent		*event;
	String		*args;
	Cardinal	*nargs;
{
	Widget		menuw;
	Dimension	width, height;
	char_u		*pullright_name;
	Widget		popup;

	if (event->type != MotionNotify)
		return;

	/* Get the active entry for the current menu */
	if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)NULL)
		return;

	XtVaGetValues(w,
		XtNwidth,	&width,
		XtNheight,	&height,
		NULL);

	if (event->xmotion.x >= width || event->xmotion.y >= height)
		return;

	/* We do the pull-off when the pointer is in the rightmost 1/4th */
	if (event->xmotion.x < (width * 3) / 4)
		return;

	pullright_name = strnsave(XtName(menuw), strlen(XtName(menuw)) +
													strlen("-pullright"));
	strcat(pullright_name, "-pullright");
	popup = XtNameToWidget(w, pullright_name);
	vim_free(pullright_name);

	if (popup == (Widget)NULL)
		return;

	XtVaSetValues(popup,
		XtNx, event->xmotion.x_root,
		XtNy, event->xmotion.y_root - 7,
		NULL);

	XtPopup(popup, XtGrabExclusive);
}