This is gui_athena.c in view mode; [Download] [Up]
/* 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/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 "gui_at_sb.h"
#define puller_width 19
#define puller_height 19
static char_u 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 vimForm = (Widget)NULL;
static Widget textArea;
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 void gui_athena_pullleft_action __ARGS((Widget, XEvent *, String *,
Cardinal *));
static Widget get_popup_entry __ARGS((Widget w));
static XtActionsRec pullAction[2] = {{ "menu-pullright",
(XtActionProc)gui_athena_pullright_action},
{ "menu-pullleft",
(XtActionProc)gui_athena_pullleft_action}};
static XtTranslations parentTrans, menuTrans, supermenuTrans;
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;
{
GuiScrollbar *sb, *sb_info;
long_u value;
sb = gui_find_scrollbar((long)client_data);
if (sb == NULL)
return;
else if (sb->wp != NULL) /* Left or right scrollbar */
{
/*
* Careful: need to get scrollbar info out of first (left) scrollbar
* for window, but keep real scrollbar too because we must pass it to
* gui_drag_scrollbar().
*/
sb_info = &sb->wp->w_scrollbars[0];
}
else /* Bottom scrollbar */
sb_info = sb;
value = (long_u)(*((float *)call_data) * (float)(sb_info->max + 1) + 0.001);
if (value > sb_info->max)
value = sb_info->max;
gui_drag_scrollbar(sb, value, TRUE);
}
/*
* 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;
{
GuiScrollbar *sb, *sb_info;
long value;
int data = (int)call_data;
int page;
sb = gui_find_scrollbar((long)client_data);
if (sb == NULL)
return;
else if (sb->wp != NULL) /* Left or right scrollbar */
{
/*
* Careful: need to get scrollbar info out of first (left) scrollbar
* for window, but keep real scrollbar too because we must pass it to
* gui_drag_scrollbar().
*/
sb_info = &sb->wp->w_scrollbars[0];
if (sb_info->size > 5)
page = sb_info->size - 2; /* use two lines of context */
else
page = sb_info->size;
switch (data)
{
case ONE_LINE_DATA: data = 1; break;
case -ONE_LINE_DATA: data = -1; break;
case ONE_PAGE_DATA: data = page; break;
case -ONE_PAGE_DATA: data = -page; break;
case END_PAGE_DATA: data = sb_info->max; break;
case -END_PAGE_DATA: data = -sb_info->max; break;
default: data = 0; break;
}
}
else /* Bottom scrollbar */
{
sb_info = sb;
if (data < -1)
data = -(Columns - 5);
else if (data > 1)
data = (Columns - 5);
}
value = sb_info->value + data;
if (value > sb_info->max)
value = sb_info->max;
else if (value < 0)
value = 0;
gui_drag_scrollbar(sb, value, FALSE);
}
/*
* Create all the Athena widgets necessary.
*/
void
gui_x11_create_widgets()
{
/*
* 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;
XtInitializeWidgetClass(formWidgetClass);
XtInitializeWidgetClass(boxWidgetClass);
XtInitializeWidgetClass(coreWidgetClass);
XtInitializeWidgetClass(menuButtonWidgetClass);
XtInitializeWidgetClass(simpleMenuWidgetClass);
XtInitializeWidgetClass(vim_scrollbarWidgetClass);
/* The form containing all the other widgets */
vimForm = XtVaCreateManagedWidget("vimForm",
formWidgetClass, vimShell,
XtNborderWidth, 0,
XtNforeground, gui.menu_fg_pixel,
XtNbackground, gui.menu_bg_pixel,
NULL);
/* The top menu bar */
menuBar = XtVaCreateManagedWidget("menuBar",
boxWidgetClass, vimForm,
XtNresizable, True,
XtNtop, XawChainTop,
XtNbottom, XawChainTop,
XtNleft, XawChainLeft,
XtNright, XawChainRight,
XtNforeground, gui.menu_fg_pixel,
XtNbackground, gui.menu_bg_pixel,
XtNborderColor, gui.menu_fg_pixel,
NULL);
/* The text area. */
textArea = XtVaCreateManagedWidget("textArea",
coreWidgetClass, vimForm,
XtNresizable, True,
XtNtop, XawChainTop,
XtNbottom, XawChainTop,
XtNleft, XawChainLeft,
XtNright, XawChainLeft,
XtNbackground, gui.back_pixel,
XtNborderWidth, 0,
NULL);
/*
* Callbacks for textArea, vimForm, and vimShell.
*/
XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
gui_x11_visibility_cb, (XtPointer)0);
XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
(XtPointer)0);
XtAddEventHandler(vimForm, StructureNotifyMask, FALSE,
gui_x11_resize_window_cb, (XtPointer)0);
XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
(XtPointer)0);
XtAddEventHandler(vimForm, KeyPressMask, FALSE, gui_x11_key_hit_cb,
(XtPointer)0);
XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
ButtonMotionMask, FALSE, gui_x11_mouse_cb, (XtPointer)0);
parentTrans = XtParseTranslationTable("<EnterWindow>: highlight()\n<LeaveWindow>:\n<BtnUp>: notify() unhighlight() MenuPopdown()\n<BtnMotion>: highlight() menu-pullright()");
menuTrans = XtParseTranslationTable("<EnterWindow>: highlight()\n<LeaveWindow>: unhighlight() MenuPopdown()\n<BtnUp>: notify() unhighlight() MenuPopdown()\n<BtnMotion>: highlight() menu-pullright()");
supermenuTrans = XtParseTranslationTable("<EnterWindow>: highlight() menu-pullleft()\n<LeaveWindow>:\n<BtnUp>: notify() unhighlight() MenuPopdown()\n<BtnMotion>:");
XtAppAddActions(XtWidgetToApplicationContext(vimForm), pullAction, 2);
pullerBitmap = XCreateBitmapFromData(gui.dpy, DefaultRootWindow(gui.dpy),
(char *)puller_bits, puller_width, puller_height);
}
void
gui_mch_set_text_area_pos(x, y, w, h)
int x;
int y;
int w;
int h;
{
XtUnmanageChild(textArea);
XtVaSetValues(textArea,
XtNhorizDistance, x,
XtNvertDistance, y,
XtNwidth, w,
XtNheight, h,
NULL);
XtManageChild(textArea);
}
/*
* Menu stuff.
*/
void
gui_mch_enable_menu(flag)
int flag;
{
if (flag)
XtManageChild(menuBar);
else
XtUnmanageChild(menuBar);
}
void
gui_mch_set_menu_pos(x, y, w, h)
int x;
int y;
int w;
int h;
{
Dimension border;
XtUnmanageChild(menuBar);
XtVaGetValues(menuBar,
XtNborderWidth, &border,
NULL);
XtVaSetValues(menuBar,
XtNhorizDistance, x,
XtNvertDistance, y,
XtNwidth, w - 2 * border,
XtNheight, h - 2 * border,
NULL);
XtManageChild(menuBar);
}
void
gui_mch_add_menu(menu, parent)
GuiMenu *menu;
GuiMenu *parent;
{
char_u *pullright_name;
Dimension height, space, border;
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);
/*
* When we add a top-level item to the menu bar, we can figure out how
* high the menu bar should be.
*/
XtVaGetValues(menuBar,
XtNvSpace, &space,
XtNborderWidth, &border,
NULL);
XtVaGetValues(menu->id,
XtNheight, &height,
NULL);
gui.menu_height = height + 2 * (space + border);
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 = vim_strnsave(menu->name,
STRLEN(menu->name) + strlen("-pullright"));
strcat((char *)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;
{
Widget parent;
if (menu->submenu_id != (Widget)0)
{
XtDestroyWidget(menu->submenu_id);
menu->submenu_id = (Widget)0;
}
if (menu->id != (Widget)0)
{
/*
* This is a hack to stop the Athena simpleMenuWidget from getting a
* BadValue error when a menu's last child is destroyed. We check to
* see if this is the last child and if so, don't delete it. The parent
* will be deleted soon anyway, and it will delete it's children like
* all good widgets do.
*/
parent = XtParent(menu->id);
if (parent != menuBar)
{
int num_children;
XtVaGetValues(parent, XtNnumChildren, &num_children, NULL);
if (num_children > 1)
XtDestroyWidget(menu->id);
}
else
XtDestroyWidget(menu->id);
menu->id = (Widget)0;
}
}
/*
* 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_set_scrollbar_thumb(sb, val, size, max)
GuiScrollbar *sb;
int val;
int size;
int max;
{
float v, s;
/*
* Athena scrollbar must go from 0.0 to 1.0.
*/
if (max == 0)
{
/* So you can't scroll it at all (normally it scrolls past end) */
vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
}
else
{
v = (float)val / (float)(max + 1);
s = (float)size / (float)(max + 1);
vim_XawScrollbarSetThumb(sb->id, v, s, 1.0);
}
}
void
gui_mch_set_scrollbar_pos(sb, x, y, w, h)
GuiScrollbar *sb;
int x;
int y;
int w;
int h;
{
XtUnmanageChild(sb->id);
XtVaSetValues(sb->id,
XtNhorizDistance, x,
XtNvertDistance, y,
XtNwidth, w,
XtNheight, h,
NULL);
XtManageChild(sb->id);
}
void
gui_mch_create_scrollbar(sb, orient)
GuiScrollbar *sb;
int orient; /* SBAR_VERT or SBAR_HORIZ */
{
sb->id = XtVaCreateWidget("scrollBar",
vim_scrollbarWidgetClass, vimForm,
XtNresizable, True,
XtNtop, XawChainTop,
XtNbottom, XawChainTop,
XtNleft, XawChainLeft,
XtNright, XawChainLeft,
XtNborderWidth, 0,
XtNorientation, (orient == SBAR_VERT) ? XtorientVertical
: XtorientHorizontal,
XtNforeground, gui.scroll_fg_pixel,
XtNbackground, gui.scroll_bg_pixel,
NULL);
XtAddCallback(sb->id, XtNjumpProc,
gui_athena_scroll_cb_jump, (XtPointer)sb->ident);
XtAddCallback(sb->id, XtNscrollProc,
gui_athena_scroll_cb_scroll, (XtPointer)sb->ident);
vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
}
void
gui_mch_destroy_scrollbar(sb)
GuiScrollbar *sb;
{
XtDestroyWidget(sb->id);
}
/*
* Miscellaneous stuff:
*/
Window
gui_x11_get_wid()
{
return( XtWindow(textArea) );
}
static void
gui_athena_pullright_action(w, event, args, nargs)
Widget w;
XEvent *event;
String *args;
Cardinal *nargs;
{
Dimension width, height;
Widget popup;
if (event->type != MotionNotify)
return;
XtVaGetValues(w,
XtNwidth, &width,
XtNheight, &height,
NULL);
if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height)
return;
/* We do the pull-off when the pointer is in the rightmost 1/4th */
if (event->xmotion.x < (int)(width * 3) / 4)
return;
popup = get_popup_entry(w);
if (popup == (Widget)NULL)
return;
/* Don't Popdown the previous submenu now */
XtOverrideTranslations(w, supermenuTrans);
XtVaSetValues(popup,
XtNx, event->xmotion.x_root,
XtNy, event->xmotion.y_root - 7,
NULL);
XtOverrideTranslations(popup, menuTrans);
XtPopup(popup, XtGrabNonexclusive);
}
/*
* Called when a submenu with another submenu gets focus again.
*/
static void
gui_athena_pullleft_action(w, event, args, nargs)
Widget w;
XEvent *event;
String *args;
Cardinal *nargs;
{
Widget popup;
Widget parent;
if (event->type != EnterNotify)
return;
/* Do Popdown the submenu now */
popup = get_popup_entry(w);
if (popup != (Widget)NULL)
XtPopdown(popup);
/* If this is the toplevel menu item, set parentTrans */
if ((parent = XtParent(w)) != (Widget)NULL && XtParent(parent) == menuBar)
XtOverrideTranslations(w, parentTrans);
else
XtOverrideTranslations(w, menuTrans);
}
static Widget
get_popup_entry(w)
Widget w;
{
Widget menuw;
char_u *pullright_name;
Widget popup;
/* Get the active entry for the current menu */
if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)NULL)
return NULL;
pullright_name = vim_strnsave((char_u *)XtName(menuw),
strlen(XtName(menuw)) + strlen("-pullright"));
strcat((char *)pullright_name, "-pullright");
popup = XtNameToWidget(w, pullright_name);
vim_free(pullright_name);
return popup;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.