Annotation of src/usr.bin/vim/gui_athena.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2: /* vi:set ts=4 sw=4:
! 3: *
! 4: * VIM - Vi IMproved by Bram Moolenaar
! 5: * GUI/Motif support by Robert Webb
! 6: * Athena port by Bill Foster
! 7: *
! 8: * Do ":help uganda" in Vim to read copying and usage conditions.
! 9: * Do ":help credits" in Vim to see a list of people who contributed.
! 10: */
! 11:
! 12: #include <X11/StringDefs.h>
! 13: #include <X11/Intrinsic.h>
! 14: #include <X11/Xaw/Paned.h>
! 15: #include <X11/Xaw/Form.h>
! 16: #include <X11/Xaw/SimpleMenu.h>
! 17: #include <X11/Xaw/MenuButton.h>
! 18: #include <X11/Xaw/SmeBSB.h>
! 19: #include <X11/Xaw/Box.h>
! 20:
! 21: #include "vim.h"
! 22: #include "globals.h"
! 23: #include "proto.h"
! 24: #include "option.h"
! 25: #include "ops.h"
! 26: #include "gui_at_sb.h"
! 27:
! 28: #define puller_width 19
! 29: #define puller_height 19
! 30:
! 31: static char puller_bits[] =
! 32: {
! 33: 0x00,0x00,0xf8,0x00,0x00,0xf8,0xf8,0x7f,0xf8,0x04,0x80,0xf8,0x04,0x80,0xf9,
! 34: 0x84,0x81,0xf9,0x84,0x83,0xf9,0x84,0x87,0xf9,0x84,0x8f,0xf9,0x84,0x8f,0xf9,
! 35: 0x84,0x87,0xf9,0x84,0x83,0xf9,0x84,0x81,0xf9,0x04,0x80,0xf9,0x04,0x80,0xf9,
! 36: 0xf8,0xff,0xf9,0xf0,0x7f,0xf8,0x00,0x00,0xf8,0x00,0x00,0xf8
! 37: };
! 38:
! 39: extern Widget vimShell;
! 40:
! 41: static Widget vimPanes;
! 42: static Widget vimForm = (Widget)NULL;
! 43: static Widget textArea;
! 44: static Widget scrollbarBox[3]; /* Left, right & bottom scrollbar boxes */
! 45: static Widget bottomScrollbar; /* Bottom scrollbar */
! 46: static Widget leftBottomScrollFiller; /* Left filler for bottom scrollbar */
! 47: static Widget rightBottomScrollFiller; /* Right filler for bottom scrollbar */
! 48: static Widget leftScrollbarFiller; /* Filler for left scrollbar */
! 49: static Widget rightScrollbarFiller; /* Filler for right scrollbar */
! 50: static Widget menuBar;
! 51:
! 52: static void gui_athena_scroll_cb_jump __ARGS((Widget, XtPointer, XtPointer));
! 53: static void gui_athena_scroll_cb_scroll __ARGS((Widget, XtPointer, XtPointer));
! 54: static void gui_athena_reorder_menus __ARGS((void));
! 55: static void gui_athena_pullright_action __ARGS((Widget, XEvent *, String *,
! 56: Cardinal *));
! 57:
! 58: static XtActionsRec pullAction = { "menu-pullright",
! 59: (XtActionProc)gui_athena_pullright_action };
! 60: static XtTranslations parentTrans, menuTrans;
! 61: static Pixmap pullerBitmap;
! 62:
! 63: /*
! 64: * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
! 65: * left or middle mouse button.
! 66: */
! 67: static void
! 68: gui_athena_scroll_cb_jump(w, client_data, call_data)
! 69: Widget w;
! 70: XtPointer client_data, call_data;
! 71: {
! 72: char_u bytes[4 + sizeof(long_u)];
! 73: WIN *wp;
! 74: GuiScrollbar *sb;
! 75: int sb_num;
! 76: int i;
! 77: int byte_count;
! 78: long_u value;
! 79:
! 80: gui.dragged_sb = SB_NONE;
! 81: for (i = 0; i <= SB_BOTTOM; i++)
! 82: if (XtParent(w) == scrollbarBox[i])
! 83: {
! 84: gui.dragged_sb = i;
! 85: break;
! 86: }
! 87:
! 88: switch (gui.dragged_sb)
! 89: {
! 90: case SB_LEFT:
! 91: case SB_RIGHT:
! 92: gui.dragged_wp = (WIN *)client_data;
! 93: sb_num = 0;
! 94: wp = firstwin;
! 95: for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
! 96: sb_num++;
! 97:
! 98: if (gui.dragged_wp == NULL)
! 99: return;
! 100:
! 101: sb = &wp->w_scrollbar;
! 102:
! 103: value = *((float *)call_data) * (float)sb->max + 0.5;
! 104: ++value; /* range is 1 to line_count */
! 105: sb->value = value;
! 106:
! 107: bytes[0] = CSI;
! 108: bytes[1] = KS_SCROLLBAR;
! 109: bytes[2] = K_FILLER;
! 110: bytes[3] = (char_u)sb_num;
! 111: byte_count = 4;
! 112: break;
! 113:
! 114: case SB_BOTTOM:
! 115: /* why not use sb->max? */
! 116: value = *((float *)call_data) *
! 117: (float)(gui_get_max_horiz_scroll()) + 0.5;
! 118: bytes[0] = CSI;
! 119: bytes[1] = KS_HORIZ_SCROLLBAR;
! 120: bytes[2] = K_FILLER;
! 121: byte_count = 3;
! 122: break;
! 123:
! 124: case SB_NONE:
! 125: default:
! 126: return;
! 127: }
! 128:
! 129: add_long_to_buf(value, bytes + byte_count);
! 130: add_to_input_buf(bytes, byte_count + sizeof(long_u));
! 131: }
! 132:
! 133: /*
! 134: * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
! 135: * right mouse buttons.
! 136: */
! 137: static void
! 138: gui_athena_scroll_cb_scroll(w, client_data, call_data)
! 139: Widget w;
! 140: XtPointer client_data, call_data;
! 141: {
! 142: char_u bytes[4 + sizeof(long_u)];
! 143: WIN *wp;
! 144: GuiScrollbar *sb;
! 145: int sb_num;
! 146: int i;
! 147: int byte_count;
! 148: long value;
! 149: int data = (int)call_data;
! 150:
! 151: for (i = 0; i <= SB_BOTTOM; i++)
! 152: if (XtParent(w) == scrollbarBox[i])
! 153: {
! 154: gui.dragged_sb = i;
! 155: break;
! 156: }
! 157:
! 158: switch (gui.dragged_sb)
! 159: {
! 160: case SB_LEFT:
! 161: case SB_RIGHT:
! 162: gui.dragged_wp = (WIN *)client_data;
! 163: sb_num = 0;
! 164: wp = firstwin;
! 165: for ( ; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
! 166: sb_num++;
! 167:
! 168: if (gui.dragged_wp == NULL)
! 169: return;
! 170:
! 171: sb = &wp->w_scrollbar;
! 172:
! 173: if (sb->size > 5)
! 174: i = sb->size - 2; /* use two lines of context */
! 175: else
! 176: i = sb->size;
! 177: switch (data)
! 178: {
! 179: case ONE_LINE_DATA: data = 1; break;
! 180: case -ONE_LINE_DATA: data = -1; break;
! 181: case ONE_PAGE_DATA: data = i; break;
! 182: case -ONE_PAGE_DATA: data = -i; break;
! 183: case END_PAGE_DATA: data = sb->max; break;
! 184: case -END_PAGE_DATA: data = -sb->max; break;
! 185: default: data = 0; break;
! 186: }
! 187: value = sb->value + data;
! 188: if (value > sb->max)
! 189: value = sb->max;
! 190: else if (value < 1) /* range is 1 to line_count */
! 191: value = 1;
! 192:
! 193: bytes[0] = CSI;
! 194: bytes[1] = KS_SCROLLBAR;
! 195: bytes[2] = K_FILLER;
! 196: bytes[3] = (char_u)sb_num;
! 197: byte_count = 4;
! 198: break;
! 199:
! 200: case SB_BOTTOM:
! 201: if (data < -1)
! 202: data = -(Columns - 5);
! 203: else if (data > 1)
! 204: data = (Columns - 5);
! 205: value = curwin->w_leftcol + data;
! 206: if (value < 0) /* range is 0 to max_col */
! 207: value = 0;
! 208: else
! 209: {
! 210: int max;
! 211: /* why not use sb->max here? */
! 212: max = gui_get_max_horiz_scroll();
! 213: if (value >= max)
! 214: value = max;
! 215: }
! 216:
! 217: bytes[0] = CSI;
! 218: bytes[1] = KS_HORIZ_SCROLLBAR;
! 219: bytes[2] = K_FILLER;
! 220: byte_count = 3;
! 221: break;
! 222:
! 223: case SB_NONE:
! 224: default:
! 225: return;
! 226: }
! 227:
! 228: /*
! 229: * This type of scrolling doesn't move the thumb automatically so we need
! 230: * make sure the scrollbar still gets updated.
! 231: */
! 232: gui.dragged_sb = SB_NONE;
! 233:
! 234: add_long_to_buf((long_u)value, bytes + byte_count);
! 235: add_to_input_buf(bytes, byte_count + sizeof(long_u));
! 236: }
! 237:
! 238: /*
! 239: * Create all the Athena widgets necessary.
! 240: */
! 241: void
! 242: gui_mch_create_widgets()
! 243: {
! 244: Dimension base_width, base_height;
! 245:
! 246: /*
! 247: * We don't have any borders handled internally by the textArea to worry
! 248: * about so only skip over the configured border width.
! 249: */
! 250: gui.border_offset = gui.border_width;
! 251:
! 252: base_width = 2 * gui.border_offset;
! 253: base_height = 2 * gui.border_offset;
! 254:
! 255: XtInitializeWidgetClass(panedWidgetClass);
! 256: XtInitializeWidgetClass(simpleMenuWidgetClass);
! 257: XtInitializeWidgetClass(vim_scrollbarWidgetClass);
! 258: XtInitializeWidgetClass(labelWidgetClass);
! 259:
! 260: /* Panes for menu bar, middle stuff, and bottom scrollbar box */
! 261: vimPanes = XtVaCreateManagedWidget("vimPanes",
! 262: panedWidgetClass, vimShell,
! 263: XtNorientation, XtorientVertical,
! 264: NULL);
! 265:
! 266: /* The top menu bar */
! 267: menuBar = XtVaCreateManagedWidget("menuBar",
! 268: boxWidgetClass, vimPanes,
! 269: XtNmin, gui.menu_height,
! 270: XtNborderWidth, 1,
! 271: XtNallowResize, True,
! 272: XtNresizeToPreferred, True,
! 273: XtNskipAdjust, True,
! 274: XtNshowGrip, False,
! 275: XtNforeground, gui.menu_fg_pixel,
! 276: XtNbackground, gui.menu_bg_pixel,
! 277: XtNborderColor, gui.menu_fg_pixel,
! 278: NULL);
! 279:
! 280: /*
! 281: * Panes for the middle stuff (left scrollbar box, text area, and right
! 282: * scrollbar box.
! 283: */
! 284: vimForm = XtVaCreateManagedWidget("vimForm",
! 285: panedWidgetClass, vimPanes,
! 286: XtNallowResize, True,
! 287: XtNorientation, XtorientHorizontal,
! 288: XtNborderWidth, 0,
! 289: XtNdefaultDistance, 0,
! 290: XtNshowGrip, False,
! 291: NULL);
! 292:
! 293: /* Panes for the left window scrollbars. */
! 294: scrollbarBox[SB_LEFT] = XtVaCreateWidget("scrollBarBox",
! 295: panedWidgetClass, vimForm,
! 296: XtNpreferredPaneSize, gui.scrollbar_width,
! 297: XtNallowResize, True,
! 298: XtNskipAdjust, True,
! 299: XtNborderWidth, 1,
! 300: XtNshowGrip, False,
! 301: XtNforeground, gui.scroll_fg_pixel,
! 302: XtNbackground, gui.scroll_fg_pixel,
! 303: XtNborderColor, gui.scroll_fg_pixel,
! 304: NULL);
! 305:
! 306: /* The text area. */
! 307: textArea = XtVaCreateManagedWidget("textArea",
! 308: coreWidgetClass, vimForm,
! 309: XtNallowResize, True,
! 310: XtNshowGrip, False,
! 311: XtNbackground, gui.back_pixel,
! 312: XtNborderWidth, 0,
! 313: XtNheight, Rows * gui.char_height + base_height,
! 314: XtNwidth, Columns * gui.char_width + base_width,
! 315: NULL);
! 316:
! 317: /* Panes for the right window scrollbars. */
! 318: scrollbarBox[SB_RIGHT] = XtVaCreateWidget("scrollBarBox",
! 319: panedWidgetClass, vimForm,
! 320: XtNpreferredPaneSize, gui.scrollbar_width,
! 321: XtNallowResize, True,
! 322: XtNskipAdjust, True,
! 323: XtNborderWidth, 1,
! 324: XtNresizeToPreferred, True,
! 325: XtNshowGrip, False,
! 326: XtNforeground, gui.scroll_fg_pixel,
! 327: XtNbackground, gui.scroll_fg_pixel,
! 328: XtNborderColor, gui.scroll_fg_pixel,
! 329: NULL);
! 330:
! 331: /* Panes for the bottom scrollbar and fillers on each side. */
! 332: scrollbarBox[SB_BOTTOM] = XtVaCreateWidget("scrollBarBox",
! 333: panedWidgetClass, vimPanes,
! 334: XtNpreferredPaneSize, gui.scrollbar_width,
! 335: XtNallowResize, True,
! 336: XtNskipAdjust, True,
! 337: XtNborderWidth, 1,
! 338: XtNresizeToPreferred, True,
! 339: XtNshowGrip, False,
! 340: XtNforeground, gui.scroll_fg_pixel,
! 341: XtNbackground, gui.scroll_fg_pixel,
! 342: XtNborderColor, gui.scroll_fg_pixel,
! 343: XtNorientation, XtorientHorizontal,
! 344: NULL);
! 345:
! 346: /* A filler for the gap on the left side of the bottom scrollbar. */
! 347: leftBottomScrollFiller = XtVaCreateManagedWidget("",
! 348: labelWidgetClass, scrollbarBox[SB_BOTTOM],
! 349: XtNshowGrip, False,
! 350: XtNresize, False,
! 351: XtNborderWidth, 4,
! 352: XtNmin, gui.scrollbar_width + 1,
! 353: XtNmax, gui.scrollbar_width + 1,
! 354: XtNforeground, gui.scroll_fg_pixel,
! 355: XtNbackground, gui.scroll_fg_pixel,
! 356: XtNborderColor, gui.scroll_fg_pixel,
! 357: NULL);
! 358:
! 359: /* The bottom scrollbar. */
! 360: bottomScrollbar = XtVaCreateManagedWidget("bottomScrollBar",
! 361: vim_scrollbarWidgetClass, scrollbarBox[SB_BOTTOM],
! 362: XtNresizeToPreferred, True,
! 363: XtNallowResize, True,
! 364: XtNskipAdjust, True,
! 365: XtNshowGrip, False,
! 366: XtNorientation, XtorientHorizontal,
! 367: XtNforeground, gui.scroll_fg_pixel,
! 368: XtNbackground, gui.scroll_bg_pixel,
! 369: NULL);
! 370:
! 371: XtAddCallback(bottomScrollbar, XtNjumpProc,
! 372: gui_athena_scroll_cb_jump, (XtPointer)NULL);
! 373: XtAddCallback(bottomScrollbar, XtNscrollProc,
! 374: gui_athena_scroll_cb_scroll, (XtPointer)NULL);
! 375:
! 376: vim_XawScrollbarSetThumb(bottomScrollbar, 0., 1., 0.);
! 377:
! 378: /* A filler for the gap on the right side of the bottom scrollbar. */
! 379: rightBottomScrollFiller = XtVaCreateManagedWidget("",
! 380: labelWidgetClass, scrollbarBox[SB_BOTTOM],
! 381: XtNshowGrip, False,
! 382: XtNresize, False,
! 383: XtNborderWidth, 4,
! 384: XtNmin, gui.scrollbar_width + 1,
! 385: XtNmax, gui.scrollbar_width + 1,
! 386: XtNforeground, gui.scroll_fg_pixel,
! 387: XtNbackground, gui.scroll_fg_pixel,
! 388: NULL);
! 389:
! 390: /* A filler for the gap on the bottom of the left scrollbar. */
! 391: leftScrollbarFiller = XtVaCreateManagedWidget("",
! 392: labelWidgetClass, scrollbarBox[SB_LEFT],
! 393: XtNshowGrip, False,
! 394: XtNresize, False,
! 395: XtNborderWidth, 4,
! 396: XtNmin, gui.scrollbar_width + 1,
! 397: XtNmax, gui.scrollbar_width + 1,
! 398: XtNforeground, gui.scroll_fg_pixel,
! 399: XtNbackground, gui.scroll_fg_pixel,
! 400: NULL);
! 401:
! 402: /* A filler for the gap on the bottom of the right scrollbar. */
! 403: rightScrollbarFiller = XtVaCreateManagedWidget("",
! 404: labelWidgetClass, scrollbarBox[SB_RIGHT],
! 405: XtNshowGrip, False,
! 406: XtNresize, False,
! 407: XtNborderWidth, 4,
! 408: XtNmin, gui.scrollbar_width + 1,
! 409: XtNmax, gui.scrollbar_width + 1,
! 410: XtNforeground, gui.scroll_fg_pixel,
! 411: XtNbackground, gui.scroll_fg_pixel,
! 412: NULL);
! 413:
! 414: gui.num_scrollbars = 0;
! 415:
! 416: /*
! 417: * Text area callbacks
! 418: */
! 419: XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
! 420: gui_x11_visibility_cb, (XtPointer)0);
! 421:
! 422: XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
! 423: (XtPointer)0);
! 424:
! 425: XtAddEventHandler(textArea, StructureNotifyMask, FALSE,
! 426: gui_x11_resize_window_cb, (XtPointer)0);
! 427:
! 428: XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
! 429: (XtPointer)0);
! 430:
! 431: XtAddEventHandler(vimPanes, KeyPressMask, FALSE, gui_x11_key_hit_cb,
! 432: (XtPointer)0);
! 433:
! 434: XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
! 435: ButtonMotionMask, FALSE, gui_x11_mouse_cb, (XtPointer)0);
! 436:
! 437: parentTrans = XtParseTranslationTable("<BtnMotion>: highlight() menu-pullright()");
! 438: menuTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight() MenuPopdown()\n<BtnUp>: notify() unhighlight() MenuPopdown()\n<BtnMotion>: highlight()");
! 439:
! 440: XtAppAddActions(XtWidgetToApplicationContext(vimForm), &pullAction, 1);
! 441:
! 442: pullerBitmap = XCreateBitmapFromData(gui.dpy, DefaultRootWindow(gui.dpy),
! 443: (char *)puller_bits, puller_width, puller_height);
! 444: }
! 445:
! 446: int
! 447: gui_mch_get_winsize()
! 448: {
! 449: Dimension base_width, base_height;
! 450: Dimension total_width, total_height;
! 451: Dimension left_width = 0, right_width = 0;
! 452: Dimension bottom_height = 0, menu_height = 0;
! 453:
! 454: base_height = 2 * gui.border_offset;
! 455: base_width = 2 * gui.border_offset;
! 456:
! 457: if (gui.which_scrollbars[SB_LEFT])
! 458: XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);
! 459:
! 460: if (gui.which_scrollbars[SB_RIGHT])
! 461: XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);
! 462:
! 463: if (gui.which_scrollbars[SB_BOTTOM])
! 464: XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);
! 465:
! 466: if (XtIsManaged(menuBar))
! 467: XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);
! 468:
! 469: base_width += left_width + right_width;
! 470: base_height += menu_height + bottom_height;
! 471:
! 472: XtVaGetValues(vimShell,
! 473: XtNheight, &total_height,
! 474: XtNwidth, &total_width,
! 475: NULL);
! 476:
! 477: gui.num_rows = (total_height - base_height) / gui.char_height;
! 478: gui.num_cols = (total_width - base_width) / gui.char_width;
! 479:
! 480: Rows = gui.num_rows;
! 481: Columns = gui.num_cols;
! 482: gui_reset_scroll_region();
! 483:
! 484: return OK;
! 485: }
! 486:
! 487: void
! 488: gui_mch_set_winsize()
! 489: {
! 490: Dimension left_width = 0, right_width = 0;
! 491: Dimension bottom_height = 0, menu_height = 0;
! 492: Dimension base_width, base_height;
! 493:
! 494: base_width = 2 * gui.border_offset;
! 495: base_height = 2 * gui.border_offset;
! 496:
! 497: if (gui.which_scrollbars[SB_LEFT])
! 498: XtVaGetValues(scrollbarBox[SB_LEFT], XtNwidth, &left_width, NULL);
! 499:
! 500: if (gui.which_scrollbars[SB_RIGHT])
! 501: XtVaGetValues(scrollbarBox[SB_RIGHT], XtNwidth, &right_width, NULL);
! 502:
! 503: if (gui.which_scrollbars[SB_BOTTOM])
! 504: XtVaGetValues(scrollbarBox[SB_BOTTOM], XtNheight, &bottom_height, NULL);
! 505:
! 506: if (XtIsManaged(menuBar))
! 507: XtVaGetValues(menuBar, XtNheight, &menu_height, NULL);
! 508:
! 509: base_width += left_width + right_width;
! 510: base_height += menu_height + bottom_height;
! 511:
! 512: XtVaSetValues(vimShell,
! 513: XtNwidthInc, gui.char_width,
! 514: XtNheightInc, gui.char_height,
! 515: XtNbaseWidth, base_width,
! 516: XtNbaseHeight, base_height,
! 517: XtNminWidth, base_width + MIN_COLUMNS * gui.char_width,
! 518: XtNminHeight, base_height + MIN_ROWS * gui.char_height,
! 519: XtNwidth, base_width + Columns * gui.char_width,
! 520: XtNheight, base_height + Rows * gui.char_height,
! 521: NULL);
! 522: }
! 523:
! 524: /*
! 525: * Menu stuff.
! 526: */
! 527:
! 528: void
! 529: gui_mch_add_menu(menu, parent)
! 530: GuiMenu *menu;
! 531: GuiMenu *parent;
! 532: {
! 533: char_u *pullright_name;
! 534:
! 535: if (parent == NULL)
! 536: {
! 537: menu->id = XtVaCreateManagedWidget(menu->name,
! 538: menuButtonWidgetClass, menuBar,
! 539: XtNmenuName, menu->name,
! 540: XtNforeground, gui.menu_fg_pixel,
! 541: XtNbackground, gui.menu_bg_pixel,
! 542: NULL);
! 543:
! 544: menu->submenu_id = XtVaCreatePopupShell(menu->name,
! 545: simpleMenuWidgetClass, menu->id,
! 546: XtNforeground, gui.menu_fg_pixel,
! 547: XtNbackground, gui.menu_bg_pixel,
! 548: NULL);
! 549:
! 550: gui_athena_reorder_menus();
! 551: }
! 552: else
! 553: {
! 554: menu->id = XtVaCreateManagedWidget(menu->name,
! 555: smeBSBObjectClass, parent->submenu_id,
! 556: XtNforeground, gui.menu_fg_pixel,
! 557: XtNbackground, gui.menu_bg_pixel,
! 558: XtNrightMargin, puller_width,
! 559: XtNrightBitmap, pullerBitmap,
! 560:
! 561: NULL);
! 562: XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
! 563: (XtPointer)menu);
! 564:
! 565: pullright_name = strnsave(menu->name, strlen(menu->name) +
! 566: strlen("-pullright"));
! 567: strcat(pullright_name, "-pullright");
! 568: menu->submenu_id = XtVaCreatePopupShell(pullright_name,
! 569: simpleMenuWidgetClass, parent->submenu_id,
! 570: XtNforeground, gui.menu_fg_pixel,
! 571: XtNbackground, gui.menu_bg_pixel,
! 572: XtNtranslations, menuTrans,
! 573: NULL);
! 574: vim_free(pullright_name);
! 575:
! 576: XtOverrideTranslations(parent->submenu_id, parentTrans);
! 577: }
! 578: }
! 579:
! 580: void
! 581: gui_mch_add_menu_item(menu, parent)
! 582: GuiMenu *menu;
! 583: GuiMenu *parent;
! 584: {
! 585: menu->submenu_id = (Widget)0;
! 586: menu->id = XtVaCreateManagedWidget(menu->name,
! 587: smeBSBObjectClass, parent->submenu_id,
! 588: XtNforeground, gui.menu_fg_pixel,
! 589: XtNbackground, gui.menu_bg_pixel,
! 590: NULL);
! 591: XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
! 592: (XtPointer)menu);
! 593: }
! 594:
! 595: /*
! 596: * Destroy the machine specific menu widget.
! 597: */
! 598: void
! 599: gui_mch_destroy_menu(menu)
! 600: GuiMenu *menu;
! 601: {
! 602: if (menu->id != (Widget)NULL)
! 603: {
! 604: /*
! 605: * This is a hack for the Athena simpleMenuWidget to keep it from
! 606: * getting a BadValue error when it's last child is destroyed. We
! 607: * check to see if this is the last child and if so, go ahead and
! 608: * delete the parent ahead of time. The parent will delete it's
! 609: * children like all good widgets do.
! 610: */
! 611: if (XtParent(menu->id) != menuBar)
! 612: {
! 613: int num_children;
! 614:
! 615: XtVaGetValues(XtParent(menu->id),
! 616: XtNnumChildren, &num_children, NULL);
! 617: if (num_children <= 1)
! 618: XtDestroyWidget(XtParent(menu->id));
! 619: else
! 620: XtDestroyWidget(menu->id);
! 621: }
! 622: else
! 623: XtDestroyWidget(menu->id);
! 624: menu->id = (Widget)NULL;
! 625: }
! 626: }
! 627:
! 628: /*
! 629: * Reorder the menus so "Help" is the rightmost item on the menu.
! 630: */
! 631: static void
! 632: gui_athena_reorder_menus()
! 633: {
! 634: Widget *children;
! 635: Widget help_widget = (Widget)NULL;
! 636: int num_children;
! 637: int i;
! 638:
! 639: XtVaGetValues(menuBar,
! 640: XtNchildren, &children,
! 641: XtNnumChildren, &num_children,
! 642: NULL);
! 643:
! 644: XtUnmanageChildren(children, num_children);
! 645:
! 646: for (i = 0; i < num_children - 1; i++)
! 647: if (help_widget == (Widget)NULL)
! 648: {
! 649: if (strcmp((char *)XtName(children[i]), "Help") == 0)
! 650: {
! 651: help_widget = children[i];
! 652: children[i] = children[i + 1];
! 653: }
! 654: }
! 655: else
! 656: children[i] = children[i + 1];
! 657:
! 658: if (help_widget != (Widget)NULL)
! 659: children[num_children - 1] = help_widget;
! 660:
! 661: XtManageChildren(children, num_children);
! 662: }
! 663:
! 664:
! 665: /*
! 666: * Scrollbar stuff:
! 667: */
! 668:
! 669: void
! 670: gui_mch_create_which_components()
! 671: {
! 672: static int prev_which_scrollbars[3] = {-1, -1, -1};
! 673: static int prev_menu_is_active = -1;
! 674:
! 675: int i;
! 676: WIN *wp;
! 677:
! 678: /*
! 679: * When removing the left/right scrollbar and creating the right/left
! 680: * scrollbar, we have to force a redraw (the size of the text area doesn't
! 681: * change).
! 682: */
! 683: if (prev_which_scrollbars[SB_LEFT] != gui.which_scrollbars[SB_LEFT] &&
! 684: prev_which_scrollbars[SB_RIGHT] != gui.which_scrollbars[SB_RIGHT])
! 685: must_redraw = CLEAR;
! 686:
! 687: gui_x11_use_resize_callback(textArea, FALSE);
! 688:
! 689: for (i = 0; i < 3; i++)
! 690: {
! 691: if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
! 692: {
! 693: if (gui.which_scrollbars[i])
! 694: {
! 695: switch (i)
! 696: {
! 697: /* When adding the left one, we need to reorder them all */
! 698: case SB_LEFT:
! 699: XtUnmanageChild(textArea);
! 700: if (gui.which_scrollbars[SB_RIGHT])
! 701: XtUnmanageChild(scrollbarBox[SB_RIGHT]);
! 702: XtManageChild(scrollbarBox[SB_LEFT]);
! 703: XtManageChild(textArea);
! 704: if (gui.which_scrollbars[SB_RIGHT])
! 705: XtManageChild(scrollbarBox[SB_RIGHT]);
! 706:
! 707: /*
! 708: * When adding at the left and we have a bottom
! 709: * scrollbar, we need to reorder these too.
! 710: */
! 711: if (gui.which_scrollbars[SB_BOTTOM])
! 712: {
! 713: XtUnmanageChild(bottomScrollbar);
! 714: if (gui.which_scrollbars[SB_RIGHT])
! 715: XtUnmanageChild(rightBottomScrollFiller);
! 716:
! 717: XtManageChild(leftBottomScrollFiller);
! 718: XtManageChild(bottomScrollbar);
! 719: if (gui.which_scrollbars[SB_RIGHT])
! 720: XtManageChild(rightBottomScrollFiller);
! 721: }
! 722: break;
! 723:
! 724: case SB_RIGHT:
! 725: XtManageChild(rightBottomScrollFiller);
! 726: XtManageChild(scrollbarBox[i]);
! 727: break;
! 728:
! 729: case SB_BOTTOM:
! 730: /* Unmanage the bottom scrollbar and fillers */
! 731: XtUnmanageChild(leftBottomScrollFiller);
! 732: XtUnmanageChild(bottomScrollbar);
! 733: XtUnmanageChild(rightBottomScrollFiller);
! 734:
! 735: /*
! 736: * Now manage the bottom scrollbar and fillers that
! 737: * are supposed to be there.
! 738: */
! 739: if (gui.which_scrollbars[SB_LEFT])
! 740: XtManageChild(leftBottomScrollFiller);
! 741: XtManageChild(bottomScrollbar);
! 742: if (gui.which_scrollbars[SB_RIGHT])
! 743: XtManageChild(rightBottomScrollFiller);
! 744:
! 745: XtManageChild(scrollbarBox[i]);
! 746: break;
! 747: }
! 748: }
! 749: else
! 750: {
! 751: switch (i)
! 752: {
! 753: case SB_LEFT:
! 754: XtUnmanageChild(leftBottomScrollFiller);
! 755: break;
! 756:
! 757: case SB_RIGHT:
! 758: XtUnmanageChild(rightBottomScrollFiller);
! 759: break;
! 760: }
! 761: XtUnmanageChild(scrollbarBox[i]);
! 762: }
! 763: }
! 764: if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
! 765: {
! 766: if (i == SB_LEFT || i == SB_RIGHT)
! 767: {
! 768: if (gui.which_scrollbars[i])
! 769: {
! 770: /* Scrollbar box has just appeared */
! 771: gui.new_sb[i] = TRUE;
! 772: }
! 773: else if (prev_which_scrollbars[i] == TRUE)
! 774: {
! 775: /* Scrollbar box has just been deleted */
! 776: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 777: XtDestroyWidget(wp->w_scrollbar.id[i]);
! 778: }
! 779: }
! 780: }
! 781: prev_which_scrollbars[i] = gui.which_scrollbars[i];
! 782: }
! 783:
! 784: if (gui.menu_is_active != prev_menu_is_active)
! 785: {
! 786: if (gui.menu_is_active)
! 787: {
! 788: XtUnmanageChild(menuBar);
! 789: XtUnmanageChild(vimForm);
! 790: if (gui.which_scrollbars[SB_BOTTOM])
! 791: XtUnmanageChild(scrollbarBox[SB_BOTTOM]);
! 792:
! 793: XtManageChild(menuBar);
! 794: XtManageChild(vimForm);
! 795: if (gui.which_scrollbars[SB_BOTTOM])
! 796: XtManageChild(scrollbarBox[SB_BOTTOM]);
! 797: }
! 798: else
! 799: XtUnmanageChild(menuBar);
! 800: prev_menu_is_active = gui.menu_is_active;
! 801: }
! 802:
! 803: gui_x11_use_resize_callback(textArea, TRUE);
! 804: if (vimForm != (Widget)NULL && XtIsRealized(vimForm))
! 805: gui_mch_set_winsize();
! 806: }
! 807:
! 808:
! 809: /*
! 810: * Vertical scrollbar stuff:
! 811: */
! 812: void
! 813: gui_mch_update_scrollbars(worst_update, which_sb)
! 814: int worst_update;
! 815: int which_sb; /* SB_LEFT or SB_RIGHT */
! 816: {
! 817: WIN *wp;
! 818: GuiScrollbar *sb;
! 819: int idx;
! 820: Dimension h; /* Height of scrollbar (in pixels) */
! 821: Dimension y; /* Coord of top of scrollbar (in pixels) */
! 822: int tmp;
! 823: float val = 0., size = 0.;
! 824:
! 825: if (worst_update >= SB_UPDATE_HEIGHT)
! 826: {
! 827: XawPanedSetRefigureMode(scrollbarBox[which_sb], False);
! 828: gui_x11_use_resize_callback(textArea, FALSE);
! 829: }
! 830:
! 831: /*
! 832: * This has to get cleared manually since Athena doesn't tell us when the
! 833: * draggin' stops.
! 834: */
! 835: gui.dragged_sb = SB_NONE;
! 836:
! 837: for (wp = firstwin, idx = 0; wp; wp = wp->w_next, idx++)
! 838: {
! 839: sb = &wp->w_scrollbar;
! 840: if (sb->update[which_sb] >= SB_UPDATE_VALUE)
! 841: {
! 842: val = (float)(sb->value - 1) / (float)sb->max;
! 843: size = (float)sb->size / (float)sb->max;
! 844: }
! 845: if (sb->update[which_sb] == SB_UPDATE_CREATE)
! 846: {
! 847: sb->id[which_sb] = XtVaCreateManagedWidget("scrollBar",
! 848: vim_scrollbarWidgetClass, scrollbarBox[which_sb],
! 849: XtNborderWidth, 1,
! 850: XtNdefaultDistance, 0,
! 851: XtNallowResize, True,
! 852: XtNpreferredPaneSize, True,
! 853: XtNresizeToPreferred, True,
! 854: XtNskipAdjust, True,
! 855: XtNorientation, XtorientVertical,
! 856: XtNshowGrip, False,
! 857: XtNforeground, gui.scroll_fg_pixel,
! 858: XtNbackground, gui.scroll_bg_pixel,
! 859: NULL);
! 860: XtAddCallback(sb->id[which_sb], XtNjumpProc,
! 861: gui_athena_scroll_cb_jump, (XtPointer)wp);
! 862: XtAddCallback(sb->id[which_sb], XtNscrollProc,
! 863: gui_athena_scroll_cb_scroll, (XtPointer)wp);
! 864: }
! 865: if (sb->update[which_sb] >= SB_UPDATE_HEIGHT)
! 866: {
! 867: h = sb->height * gui.char_height
! 868: + sb->status_height * gui.char_height / 2;
! 869: y = wp->w_winpos * gui.char_height + gui.border_offset;
! 870:
! 871: if (wp == firstwin)
! 872: {
! 873: /* Height of top scrollbar includes width of top border */
! 874: h += gui.border_offset;
! 875: }
! 876: else
! 877: {
! 878: /*
! 879: * Height of other scrollbars includes half of status bar above
! 880: */
! 881: tmp = wp->w_prev->w_status_height * (gui.char_height + 1) / 2;
! 882: h += tmp;
! 883: y -= tmp;
! 884: }
! 885:
! 886: XtVaSetValues(sb->id[which_sb],
! 887: XtNheight, h,
! 888: XtNmin, h,
! 889: XtNmax, h,
! 890: XtNy, y,
! 891: NULL);
! 892: vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
! 893: }
! 894: else if (sb->update[which_sb] == SB_UPDATE_VALUE)
! 895: {
! 896: vim_XawScrollbarSetThumb(sb->id[which_sb], val, size, 1.0);
! 897: }
! 898: sb->update[which_sb] = SB_UPDATE_NOTHING;
! 899: }
! 900:
! 901: if (worst_update >= SB_UPDATE_HEIGHT)
! 902: {
! 903: if (worst_update >= SB_UPDATE_CREATE)
! 904: gui_mch_reorder_scrollbars(which_sb);
! 905: XawPanedSetRefigureMode(scrollbarBox[which_sb], True);
! 906: gui_x11_use_resize_callback(textArea, TRUE);
! 907: }
! 908: }
! 909:
! 910: void
! 911: gui_mch_reorder_scrollbars(which_sb)
! 912: int which_sb;
! 913: {
! 914: WIN *wp;
! 915:
! 916: if (which_sb == SB_LEFT)
! 917: XtUnmanageChild(leftScrollbarFiller);
! 918: else
! 919: XtUnmanageChild(rightScrollbarFiller);
! 920:
! 921: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 922: if (wp->w_scrollbar.id[which_sb] != NULL)
! 923: XtUnmanageChild(wp->w_scrollbar.id[which_sb]);
! 924:
! 925: for (wp = firstwin; wp != NULL; wp = wp->w_next)
! 926: if (wp->w_scrollbar.id[which_sb] != NULL)
! 927: XtManageChild(wp->w_scrollbar.id[which_sb]);
! 928:
! 929: if (which_sb == SB_LEFT)
! 930: XtManageChild(leftScrollbarFiller);
! 931: else
! 932: XtManageChild(rightScrollbarFiller);
! 933:
! 934: }
! 935:
! 936: void
! 937: gui_mch_destroy_scrollbar(wp)
! 938: WIN *wp;
! 939: {
! 940: if (gui.which_scrollbars[SB_LEFT])
! 941: XtDestroyWidget(wp->w_scrollbar.id[SB_LEFT]);
! 942: if (gui.which_scrollbars[SB_RIGHT])
! 943: XtDestroyWidget(wp->w_scrollbar.id[SB_RIGHT]);
! 944: gui.num_scrollbars--;
! 945: }
! 946:
! 947:
! 948: /*
! 949: * Horizontal scrollbar stuff:
! 950: */
! 951: void
! 952: gui_mch_update_horiz_scrollbar(value, size, max)
! 953: int value;
! 954: int size;
! 955: int max;
! 956: {
! 957: static int prev_value = -1, prev_size = -1, prev_max = -1;
! 958: float val, shown, maxval;
! 959:
! 960: if (value == prev_value && size == prev_size && max == prev_max)
! 961: return;
! 962:
! 963: prev_value = value;
! 964: prev_size = size;
! 965: prev_max = max;
! 966:
! 967: if (max == 1) /* maximum is one more than maximal value */
! 968: {
! 969: val = 0.0;
! 970: shown = 1.0;
! 971: maxval = 0.0;
! 972: }
! 973: else
! 974: {
! 975: val = (float)value / (float)max;
! 976: shown = (float)size / (float)max;
! 977: maxval = 1.0;
! 978: }
! 979: vim_XawScrollbarSetThumb(bottomScrollbar, val, shown, maxval);
! 980: }
! 981:
! 982: Window
! 983: gui_mch_get_wid()
! 984: {
! 985: return( XtWindow(textArea) );
! 986: }
! 987:
! 988: static void
! 989: gui_athena_pullright_action(w, event, args, nargs)
! 990: Widget w;
! 991: XEvent *event;
! 992: String *args;
! 993: Cardinal *nargs;
! 994: {
! 995: Widget menuw;
! 996: Dimension width, height;
! 997: char_u *pullright_name;
! 998: Widget popup;
! 999:
! 1000: if (event->type != MotionNotify)
! 1001: return;
! 1002:
! 1003: /* Get the active entry for the current menu */
! 1004: if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)NULL)
! 1005: return;
! 1006:
! 1007: XtVaGetValues(w,
! 1008: XtNwidth, &width,
! 1009: XtNheight, &height,
! 1010: NULL);
! 1011:
! 1012: if (event->xmotion.x >= width || event->xmotion.y >= height)
! 1013: return;
! 1014:
! 1015: /* We do the pull-off when the pointer is in the rightmost 1/4th */
! 1016: if (event->xmotion.x < (width * 3) / 4)
! 1017: return;
! 1018:
! 1019: pullright_name = strnsave(XtName(menuw), strlen(XtName(menuw)) +
! 1020: strlen("-pullright"));
! 1021: strcat(pullright_name, "-pullright");
! 1022: popup = XtNameToWidget(w, pullright_name);
! 1023: vim_free(pullright_name);
! 1024:
! 1025: if (popup == (Widget)NULL)
! 1026: return;
! 1027:
! 1028: XtVaSetValues(popup,
! 1029: XtNx, event->xmotion.x_root,
! 1030: XtNy, event->xmotion.y_root - 7,
! 1031: NULL);
! 1032:
! 1033: XtPopup(popup, XtGrabExclusive);
! 1034: }