diff options
Diffstat (limited to 'usr.bin/vim/gui_athena.c')
-rw-r--r-- | usr.bin/vim/gui_athena.c | 1034 |
1 files changed, 1034 insertions, 0 deletions
diff --git a/usr.bin/vim/gui_athena.c b/usr.bin/vim/gui_athena.c new file mode 100644 index 00000000000..75382c2902f --- /dev/null +++ b/usr.bin/vim/gui_athena.c @@ -0,0 +1,1034 @@ +/* $OpenBSD: gui_athena.c,v 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); +} |