1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * GUI/Motif support by Robert Webb 5 * Athena port by Bill Foster 6 * 7 * Do ":help uganda" in Vim to read copying and usage conditions. 8 * Do ":help credits" in Vim to see a list of people who contributed. 9 * See README.txt for an overview of the Vim source code. 10 */ 11 12 #include "vim.h" 13 14 #include <X11/StringDefs.h> 15 #include <X11/Intrinsic.h> 16 #ifdef FEAT_GUI_NEXTAW 17 # include <X11/neXtaw/Form.h> 18 # include <X11/neXtaw/SimpleMenu.h> 19 # include <X11/neXtaw/MenuButton.h> 20 # include <X11/neXtaw/SmeBSB.h> 21 # include <X11/neXtaw/SmeLine.h> 22 # include <X11/neXtaw/Box.h> 23 # include <X11/neXtaw/Dialog.h> 24 # include <X11/neXtaw/Text.h> 25 # include <X11/neXtaw/AsciiText.h> 26 # include <X11/neXtaw/Scrollbar.h> 27 #else 28 # include <X11/Xaw/Form.h> 29 # include <X11/Xaw/SimpleMenu.h> 30 # include <X11/Xaw/MenuButton.h> 31 # include <X11/Xaw/SmeBSB.h> 32 # include <X11/Xaw/SmeLine.h> 33 # include <X11/Xaw/Box.h> 34 # include <X11/Xaw/Dialog.h> 35 # include <X11/Xaw/Text.h> 36 # include <X11/Xaw/AsciiText.h> 37 #endif /* FEAT_GUI_NEXTAW */ 38 39 #ifndef FEAT_GUI_NEXTAW 40 # include "gui_at_sb.h" 41 #endif 42 43 extern Widget vimShell; 44 45 static Widget vimForm = (Widget)0; 46 Widget textArea = (Widget)0; 47 #ifdef FEAT_MENU 48 static Widget menuBar = (Widget)0; 49 static XtIntervalId timer = 0; /* 0 = expired, otherwise active */ 50 51 /* Used to figure out menu ordering */ 52 static vimmenu_T *a_cur_menu = NULL; 53 static Cardinal athena_calculate_ins_pos(Widget); 54 55 static void gui_athena_popup_callback(Widget, XtPointer, XtPointer); 56 static void gui_athena_delayed_arm_action(Widget, XEvent *, String *, 57 Cardinal *); 58 static void gui_athena_popdown_submenus_action(Widget, XEvent *, 59 String *, Cardinal *); 60 static XtActionsRec pullAction[2] = { 61 { "menu-delayedpopup", (XtActionProc)gui_athena_delayed_arm_action}, 62 { "menu-popdownsubmenus", (XtActionProc)gui_athena_popdown_submenus_action} 63 }; 64 #endif 65 66 #ifdef FEAT_TOOLBAR 67 static void gui_mch_reset_focus(void); 68 static Widget toolBar = (Widget)0; 69 #endif 70 71 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU) 72 static void gui_athena_menu_colors(Widget id); 73 #endif 74 static void gui_athena_scroll_colors(Widget id); 75 76 #ifdef FEAT_MENU 77 static XtTranslations popupTrans, parentTrans, menuTrans, supermenuTrans; 78 static Pixmap pullerBitmap = None; 79 static int puller_width = 0; 80 #endif 81 82 /* 83 * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the 84 * left or middle mouse button. 85 */ 86 static void 87 gui_athena_scroll_cb_jump( 88 Widget w UNUSED, 89 XtPointer client_data, 90 XtPointer call_data) 91 { 92 scrollbar_T *sb, *sb_info; 93 long value; 94 95 sb = gui_find_scrollbar((long)client_data); 96 97 if (sb == NULL) 98 return; 99 else if (sb->wp != NULL) /* Left or right scrollbar */ 100 { 101 /* 102 * Careful: need to get scrollbar info out of first (left) scrollbar 103 * for window, but keep real scrollbar too because we must pass it to 104 * gui_drag_scrollbar(). 105 */ 106 sb_info = &sb->wp->w_scrollbars[0]; 107 } 108 else /* Bottom scrollbar */ 109 sb_info = sb; 110 111 value = (long)(*((float *)call_data) * (float)(sb_info->max + 1) + 0.001); 112 if (value > sb_info->max) 113 value = sb_info->max; 114 115 gui_drag_scrollbar(sb, value, TRUE); 116 } 117 118 /* 119 * Scrollbar callback (XtNscrollProc) for paging up or down with the left or 120 * right mouse buttons. 121 */ 122 static void 123 gui_athena_scroll_cb_scroll( 124 Widget w UNUSED, 125 XtPointer client_data, 126 XtPointer call_data) 127 { 128 scrollbar_T *sb, *sb_info; 129 long value; 130 int data = (int)(long)call_data; 131 int page; 132 133 sb = gui_find_scrollbar((long)client_data); 134 135 if (sb == NULL) 136 return; 137 if (sb->wp != NULL) /* Left or right scrollbar */ 138 { 139 /* 140 * Careful: need to get scrollbar info out of first (left) scrollbar 141 * for window, but keep real scrollbar too because we must pass it to 142 * gui_drag_scrollbar(). 143 */ 144 sb_info = &sb->wp->w_scrollbars[0]; 145 146 if (sb_info->size > 5) 147 page = sb_info->size - 2; /* use two lines of context */ 148 else 149 page = sb_info->size; 150 #ifdef FEAT_GUI_NEXTAW 151 if (data < 0) 152 { 153 data = (data - gui.char_height + 1) / gui.char_height; 154 if (data > -sb_info->size) 155 data = -1; 156 else 157 data = -page; 158 } 159 else if (data > 0) 160 { 161 data = (data + gui.char_height - 1) / gui.char_height; 162 if (data < sb_info->size) 163 data = 1; 164 else 165 data = page; 166 } 167 #else 168 switch (data) 169 { 170 case ONE_LINE_DATA: data = 1; break; 171 case -ONE_LINE_DATA: data = -1; break; 172 case ONE_PAGE_DATA: data = page; break; 173 case -ONE_PAGE_DATA: data = -page; break; 174 case END_PAGE_DATA: data = sb_info->max; break; 175 case -END_PAGE_DATA: data = -sb_info->max; break; 176 default: data = 0; break; 177 } 178 #endif 179 } 180 else /* Bottom scrollbar */ 181 { 182 sb_info = sb; 183 #ifdef FEAT_GUI_NEXTAW 184 if (data < 0) 185 { 186 data = (data - gui.char_width + 1) / gui.char_width; 187 if (data > -sb->size) 188 data = -1; 189 } 190 else if (data > 0) 191 { 192 data = (data + gui.char_width - 1) / gui.char_width; 193 if (data < sb->size) 194 data = 1; 195 } 196 #endif 197 if (data < -1) /* page-width left */ 198 { 199 if (sb->size > 8) 200 data = -(sb->size - 5); 201 else 202 data = -sb->size; 203 } 204 else if (data > 1) /* page-width right */ 205 { 206 if (sb->size > 8) 207 data = (sb->size - 5); 208 else 209 data = sb->size; 210 } 211 } 212 213 value = sb_info->value + data; 214 if (value > sb_info->max) 215 value = sb_info->max; 216 else if (value < 0) 217 value = 0; 218 219 /* Update the bottom scrollbar an extra time (why is this needed?? */ 220 if (sb->wp == NULL) /* Bottom scrollbar */ 221 gui_mch_set_scrollbar_thumb(sb, value, sb->size, sb->max); 222 223 gui_drag_scrollbar(sb, value, FALSE); 224 } 225 226 /* 227 * Create all the Athena widgets necessary. 228 */ 229 void 230 gui_x11_create_widgets(void) 231 { 232 /* 233 * We don't have any borders handled internally by the textArea to worry 234 * about so only skip over the configured border width. 235 */ 236 gui.border_offset = gui.border_width; 237 238 /* The form containing all the other widgets */ 239 vimForm = XtVaCreateManagedWidget("vimForm", 240 formWidgetClass, vimShell, 241 XtNborderWidth, 0, 242 NULL); 243 gui_athena_scroll_colors(vimForm); 244 245 #ifdef FEAT_MENU 246 /* The top menu bar */ 247 menuBar = XtVaCreateManagedWidget("menuBar", 248 boxWidgetClass, vimForm, 249 XtNresizable, True, 250 XtNtop, XtChainTop, 251 XtNbottom, XtChainTop, 252 XtNleft, XtChainLeft, 253 XtNright, XtChainRight, 254 XtNinsertPosition, athena_calculate_ins_pos, 255 NULL); 256 gui_athena_menu_colors(menuBar); 257 if (gui.menu_fg_pixel != INVALCOLOR) 258 XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL); 259 #endif 260 261 #ifdef FEAT_TOOLBAR 262 /* Don't create it Managed, it will be managed when creating the first 263 * item. Otherwise an empty toolbar shows up. */ 264 toolBar = XtVaCreateWidget("toolBar", 265 boxWidgetClass, vimForm, 266 XtNresizable, True, 267 XtNtop, XtChainTop, 268 XtNbottom, XtChainTop, 269 XtNleft, XtChainLeft, 270 XtNright, XtChainRight, 271 XtNorientation, XtorientHorizontal, 272 XtNhSpace, 1, 273 XtNvSpace, 3, 274 XtNinsertPosition, athena_calculate_ins_pos, 275 NULL); 276 gui_athena_menu_colors(toolBar); 277 #endif 278 279 /* The text area. */ 280 textArea = XtVaCreateManagedWidget("textArea", 281 coreWidgetClass, vimForm, 282 XtNresizable, True, 283 XtNtop, XtChainTop, 284 XtNbottom, XtChainTop, 285 XtNleft, XtChainLeft, 286 XtNright, XtChainLeft, 287 XtNbackground, gui.back_pixel, 288 XtNborderWidth, 0, 289 NULL); 290 291 /* 292 * Install the callbacks. 293 */ 294 gui_x11_callbacks(textArea, vimForm); 295 296 #ifdef FEAT_MENU 297 popupTrans = XtParseTranslationTable( 298 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n" 299 "<LeaveWindow>: unhighlight()\n" 300 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n" 301 "<Motion>: highlight() menu-delayedpopup()"); 302 parentTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight()"); 303 menuTrans = XtParseTranslationTable( 304 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n" 305 "<LeaveWindow>: menu-popdownsubmenus() XtMenuPopdown() unhighlight()\n" 306 "<BtnUp>: notify() unhighlight()\n" 307 "<BtnMotion>: highlight() menu-delayedpopup()"); 308 supermenuTrans = XtParseTranslationTable( 309 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n" 310 "<LeaveWindow>: unhighlight()\n" 311 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n" 312 "<BtnMotion>: highlight() menu-delayedpopup()"); 313 314 XtAppAddActions(XtWidgetToApplicationContext(vimForm), pullAction, 315 XtNumber(pullAction)); 316 #endif 317 318 /* Pretend we don't have input focus, we will get an event if we do. */ 319 gui.in_focus = FALSE; 320 } 321 322 #ifdef FEAT_MENU 323 /* 324 * Calculates the Pixmap based on the size of the current menu font. 325 */ 326 static Pixmap 327 gui_athena_create_pullright_pixmap(Widget w) 328 { 329 Pixmap retval; 330 #ifdef FONTSET_ALWAYS 331 XFontSet font = None; 332 #else 333 XFontStruct *font = NULL; 334 #endif 335 336 #ifdef FONTSET_ALWAYS 337 if (gui.menu_fontset == NOFONTSET) 338 #else 339 if (gui.menu_font == NOFONT) 340 #endif 341 { 342 XrmValue from, to; 343 WidgetList children; 344 Cardinal num_children; 345 346 #ifdef FONTSET_ALWAYS 347 from.size = strlen(from.addr = XtDefaultFontSet); 348 to.addr = (XtPointer)&font; 349 to.size = sizeof(XFontSet); 350 #else 351 from.size = strlen(from.addr = XtDefaultFont); 352 to.addr = (XtPointer)&font; 353 to.size = sizeof(XFontStruct *); 354 #endif 355 /* Assumption: The menuBar children will use the same font as the 356 * pulldown menu items AND they will all be of type 357 * XtNfont. 358 */ 359 XtVaGetValues(menuBar, XtNchildren, &children, 360 XtNnumChildren, &num_children, 361 NULL); 362 if (XtConvertAndStore(w ? w : 363 (num_children > 0) ? children[0] : menuBar, 364 XtRString, &from, 365 #ifdef FONTSET_ALWAYS 366 XtRFontSet, &to 367 #else 368 XtRFontStruct, &to 369 #endif 370 ) == False) 371 return None; 372 /* "font" should now contain data */ 373 } 374 else 375 #ifdef FONTSET_ALWAYS 376 font = (XFontSet)gui.menu_fontset; 377 #else 378 font = (XFontStruct *)gui.menu_font; 379 #endif 380 381 { 382 int width, height; 383 GC draw_gc, undraw_gc; 384 XGCValues gc_values; 385 XPoint points[3]; 386 387 #ifdef FONTSET_ALWAYS 388 height = fontset_height2(font); 389 #else 390 height = font->max_bounds.ascent + font->max_bounds.descent; 391 #endif 392 width = height - 2; 393 puller_width = width + 4; 394 retval = XCreatePixmap(gui.dpy,DefaultRootWindow(gui.dpy),width, 395 height, 1); 396 gc_values.foreground = 1; 397 gc_values.background = 0; 398 draw_gc = XCreateGC(gui.dpy, retval, 399 GCForeground | GCBackground, 400 &gc_values); 401 gc_values.foreground = 0; 402 gc_values.background = 1; 403 undraw_gc = XCreateGC(gui.dpy, retval, 404 GCForeground | GCBackground, 405 &gc_values); 406 points[0].x = 0; 407 points[0].y = 0; 408 points[1].x = width - 1; 409 points[1].y = (height - 1) / 2; 410 points[2].x = 0; 411 points[2].y = height - 1; 412 XFillRectangle(gui.dpy, retval, undraw_gc, 0, 0, height, height); 413 XFillPolygon(gui.dpy, retval, draw_gc, points, XtNumber(points), 414 Convex, CoordModeOrigin); 415 XFreeGC(gui.dpy, draw_gc); 416 XFreeGC(gui.dpy, undraw_gc); 417 } 418 return retval; 419 } 420 #endif 421 422 /* 423 * Called when the GUI is not going to start after all. 424 */ 425 void 426 gui_x11_destroy_widgets(void) 427 { 428 textArea = NULL; 429 #ifdef FEAT_MENU 430 menuBar = NULL; 431 #endif 432 #ifdef FEAT_TOOLBAR 433 toolBar = NULL; 434 #endif 435 } 436 437 #if defined(FEAT_TOOLBAR) || defined(PROTO) 438 # include "gui_x11_pm.h" 439 # ifdef HAVE_X11_XPM_H 440 # include <X11/xpm.h> 441 # endif 442 443 static void createXpmImages(char_u *path, char **xpm, Pixmap *sen); 444 445 /* 446 * Allocated a pixmap for toolbar menu "menu". 447 * Return in "sen". 448 */ 449 static void 450 get_toolbar_pixmap(vimmenu_T *menu, Pixmap *sen) 451 { 452 char_u buf[MAXPATHL]; /* buffer storing expanded pathname */ 453 char **xpm = NULL; /* xpm array */ 454 455 buf[0] = NUL; /* start with NULL path */ 456 457 if (menu->iconfile != NULL) 458 { 459 /* Use the "icon=" argument. */ 460 gui_find_iconfile(menu->iconfile, buf, "xpm"); 461 createXpmImages(buf, NULL, sen); 462 463 /* If it failed, try using the menu name. */ 464 if (*sen == (Pixmap)0 && gui_find_bitmap(menu->name, buf, "xpm") == OK) 465 createXpmImages(buf, NULL, sen); 466 if (*sen != (Pixmap)0) 467 return; 468 } 469 470 if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL) 471 { 472 if (menu->iconidx >= 0 && menu->iconidx 473 < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0]))) 474 xpm = built_in_pixmaps[menu->iconidx]; 475 else 476 xpm = tb_blank_xpm; 477 } 478 479 if (xpm != NULL || buf[0] != NUL) 480 createXpmImages(buf, xpm, sen); 481 } 482 483 /* 484 * Read an Xpm file, doing color substitutions for the foreground and 485 * background colors. If there is an error reading a color xpm file, 486 * drop back and read the monochrome file. If successful, create the 487 * insensitive Pixmap too. 488 */ 489 static void 490 createXpmImages(char_u *path, char **xpm, Pixmap *sen) 491 { 492 Window rootWindow; 493 XpmAttributes attrs; 494 XpmColorSymbol color[5] = 495 { 496 {"none", "none", 0}, 497 {"iconColor1", NULL, 0}, 498 {"bottomShadowColor", NULL, 0}, 499 {"topShadowColor", NULL, 0}, 500 {"selectColor", NULL, 0} 501 }; 502 int screenNum; 503 int status; 504 Pixmap mask; 505 Pixmap map; 506 507 gui_mch_get_toolbar_colors( 508 &color[BACKGROUND].pixel, 509 &color[FOREGROUND].pixel, 510 &color[BOTTOM_SHADOW].pixel, 511 &color[TOP_SHADOW].pixel, 512 &color[HIGHLIGHT].pixel); 513 514 /* Setup the color substitution table */ 515 attrs.valuemask = XpmColorSymbols; 516 attrs.colorsymbols = color; 517 attrs.numsymbols = 5; 518 519 screenNum = DefaultScreen(gui.dpy); 520 rootWindow = RootWindow(gui.dpy, screenNum); 521 522 /* Create the "sensitive" pixmap */ 523 if (xpm != NULL) 524 status = XpmCreatePixmapFromData(gui.dpy, rootWindow, xpm, 525 &map, &mask, &attrs); 526 else 527 status = XpmReadFileToPixmap(gui.dpy, rootWindow, (char *)path, 528 &map, &mask, &attrs); 529 if (status == XpmSuccess && map != 0) 530 { 531 XGCValues gcvalues; 532 GC back_gc; 533 GC mask_gc; 534 535 /* Need to create new Pixmaps with the mask applied. */ 536 gcvalues.foreground = color[BACKGROUND].pixel; 537 back_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues); 538 mask_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues); 539 XSetClipMask(gui.dpy, mask_gc, mask); 540 541 /* Create the "sensitive" pixmap. */ 542 *sen = XCreatePixmap(gui.dpy, rootWindow, 543 attrs.width, attrs.height, 544 DefaultDepth(gui.dpy, screenNum)); 545 XFillRectangle(gui.dpy, *sen, back_gc, 0, 0, 546 attrs.width, attrs.height); 547 XCopyArea(gui.dpy, map, *sen, mask_gc, 0, 0, 548 attrs.width, attrs.height, 0, 0); 549 550 XFreeGC(gui.dpy, back_gc); 551 XFreeGC(gui.dpy, mask_gc); 552 XFreePixmap(gui.dpy, map); 553 } 554 else 555 *sen = 0; 556 557 XpmFreeAttributes(&attrs); 558 } 559 560 void 561 gui_mch_set_toolbar_pos( 562 int x, 563 int y, 564 int w, 565 int h) 566 { 567 Dimension border; 568 int height; 569 570 if (!XtIsManaged(toolBar)) /* nothing to do */ 571 return; 572 XtUnmanageChild(toolBar); 573 XtVaGetValues(toolBar, 574 XtNborderWidth, &border, 575 NULL); 576 height = h - 2 * border; 577 if (height < 0) 578 height = 1; 579 XtVaSetValues(toolBar, 580 XtNhorizDistance, x, 581 XtNvertDistance, y, 582 XtNwidth, w - 2 * border, 583 XtNheight, height, 584 NULL); 585 XtManageChild(toolBar); 586 } 587 #endif 588 589 void 590 gui_mch_set_text_area_pos( 591 int x, 592 int y, 593 int w, 594 int h) 595 { 596 XtUnmanageChild(textArea); 597 XtVaSetValues(textArea, 598 XtNhorizDistance, x, 599 XtNvertDistance, y, 600 XtNwidth, w, 601 XtNheight, h, 602 NULL); 603 XtManageChild(textArea); 604 #ifdef FEAT_TOOLBAR 605 /* Give keyboard focus to the textArea instead of the toolbar. */ 606 gui_mch_reset_focus(); 607 #endif 608 } 609 610 #ifdef FEAT_TOOLBAR 611 /* 612 * A toolbar button has been pushed; now reset the input focus 613 * such that the user can type page up/down etc. and have the 614 * input go to the editor window, not the button 615 */ 616 static void 617 gui_mch_reset_focus(void) 618 { 619 XtSetKeyboardFocus(vimForm, textArea); 620 } 621 #endif 622 623 624 void 625 gui_x11_set_back_color(void) 626 { 627 if (textArea != NULL) 628 XtVaSetValues(textArea, 629 XtNbackground, gui.back_pixel, 630 NULL); 631 } 632 633 #if defined(FEAT_MENU) || defined(PROTO) 634 /* 635 * Menu stuff. 636 */ 637 638 static char_u *make_pull_name(char_u * name); 639 static Widget get_popup_entry(Widget w); 640 static Widget submenu_widget(Widget); 641 static Boolean has_submenu(Widget); 642 static void gui_mch_submenu_change(vimmenu_T *mp, int colors); 643 static void gui_athena_menu_font(Widget id); 644 645 void 646 gui_mch_enable_menu(int flag) 647 { 648 if (flag) 649 { 650 XtManageChild(menuBar); 651 # ifdef FEAT_TOOLBAR 652 if (XtIsManaged(toolBar)) 653 { 654 XtVaSetValues(toolBar, 655 XtNvertDistance, gui.menu_height, 656 NULL); 657 XtVaSetValues(textArea, 658 XtNvertDistance, gui.menu_height + gui.toolbar_height, 659 NULL); 660 } 661 # endif 662 } 663 else 664 { 665 XtUnmanageChild(menuBar); 666 # ifdef FEAT_TOOLBAR 667 if (XtIsManaged(toolBar)) 668 { 669 XtVaSetValues(toolBar, 670 XtNvertDistance, 0, 671 NULL); 672 } 673 # endif 674 } 675 } 676 677 void 678 gui_mch_set_menu_pos( 679 int x, 680 int y, 681 int w, 682 int h) 683 { 684 Dimension border; 685 int height; 686 687 XtUnmanageChild(menuBar); 688 XtVaGetValues(menuBar, XtNborderWidth, &border, NULL); 689 /* avoid trouble when there are no menu items, and h is 1 */ 690 height = h - 2 * border; 691 if (height < 0) 692 height = 1; 693 XtVaSetValues(menuBar, 694 XtNhorizDistance, x, 695 XtNvertDistance, y, 696 XtNwidth, w - 2 * border, 697 XtNheight, height, 698 NULL); 699 XtManageChild(menuBar); 700 } 701 702 /* 703 * Used to calculate the insertion position of a widget with respect to its 704 * neighbors. 705 * 706 * Valid range of return values is: 0 (beginning of children) to 707 * numChildren (end of children). 708 */ 709 static Cardinal 710 athena_calculate_ins_pos(Widget widget) 711 { 712 /* Assume that if the parent of the vimmenu_T is NULL, then we can get 713 * to this menu by traversing "next", starting at "root_menu". 714 * 715 * This holds true for popup menus, toolbar, and toplevel menu items. 716 */ 717 718 /* Popup menus: "id" is NULL. Only submenu_id is valid */ 719 720 /* Menus that are not toplevel: "parent" will be non-NULL, "id" & 721 * "submenu_id" will be non-NULL. 722 */ 723 724 /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */ 725 726 WidgetList children; 727 Cardinal num_children = 0; 728 int retval; 729 Arg args[2]; 730 int n = 0; 731 int i; 732 733 XtSetArg(args[n], XtNchildren, &children); n++; 734 XtSetArg(args[n], XtNnumChildren, &num_children); n++; 735 XtGetValues(XtParent(widget), args, n); 736 737 retval = num_children; 738 for (i = 0; i < (int)num_children; ++i) 739 { 740 Widget current = children[i]; 741 vimmenu_T *menu = NULL; 742 743 for (menu = (a_cur_menu->parent == NULL) 744 ? root_menu : a_cur_menu->parent->children; 745 menu != NULL; 746 menu = menu->next) 747 if (current == menu->id 748 && a_cur_menu->priority < menu->priority 749 && i < retval) 750 retval = i; 751 } 752 return retval; 753 } 754 755 void 756 gui_mch_add_menu(vimmenu_T *menu, int idx UNUSED) 757 { 758 char_u *pullright_name; 759 Dimension height, space, border; 760 vimmenu_T *parent = menu->parent; 761 762 a_cur_menu = menu; 763 if (parent == NULL) 764 { 765 if (menu_is_popup(menu->dname)) 766 { 767 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname, 768 simpleMenuWidgetClass, vimShell, 769 XtNinsertPosition, athena_calculate_ins_pos, 770 XtNtranslations, popupTrans, 771 NULL); 772 gui_athena_menu_colors(menu->submenu_id); 773 } 774 else if (menu_is_menubar(menu->dname)) 775 { 776 menu->id = XtVaCreateManagedWidget((char *)menu->dname, 777 menuButtonWidgetClass, menuBar, 778 XtNmenuName, menu->dname, 779 #ifdef FONTSET_ALWAYS 780 XtNinternational, True, 781 #endif 782 NULL); 783 if (menu->id == (Widget)0) 784 return; 785 gui_athena_menu_colors(menu->id); 786 gui_athena_menu_font(menu->id); 787 788 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname, 789 simpleMenuWidgetClass, menu->id, 790 XtNinsertPosition, athena_calculate_ins_pos, 791 XtNtranslations, supermenuTrans, 792 NULL); 793 gui_athena_menu_colors(menu->submenu_id); 794 gui_athena_menu_font(menu->submenu_id); 795 796 /* Don't update the menu height when it was set at a fixed value */ 797 if (!gui.menu_height_fixed) 798 { 799 /* 800 * When we add a top-level item to the menu bar, we can figure 801 * out how high the menu bar should be. 802 */ 803 XtVaGetValues(menuBar, 804 XtNvSpace, &space, 805 XtNborderWidth, &border, 806 NULL); 807 XtVaGetValues(menu->id, 808 XtNheight, &height, 809 NULL); 810 gui.menu_height = height + 2 * (space + border); 811 } 812 } 813 } 814 else if (parent->submenu_id != (Widget)0) 815 { 816 menu->id = XtVaCreateManagedWidget((char *)menu->dname, 817 smeBSBObjectClass, parent->submenu_id, 818 XtNlabel, menu->dname, 819 #ifdef FONTSET_ALWAYS 820 XtNinternational, True, 821 #endif 822 NULL); 823 if (menu->id == (Widget)0) 824 return; 825 if (pullerBitmap == None) 826 pullerBitmap = gui_athena_create_pullright_pixmap(menu->id); 827 828 XtVaSetValues(menu->id, XtNrightBitmap, pullerBitmap, 829 NULL); 830 /* If there are other menu items that are not pulldown menus, 831 * we need to adjust the right margins of those, too. 832 */ 833 { 834 WidgetList children; 835 Cardinal num_children; 836 int i; 837 838 XtVaGetValues(parent->submenu_id, XtNchildren, &children, 839 XtNnumChildren, &num_children, 840 NULL); 841 for (i = 0; i < (int)num_children; ++i) 842 { 843 XtVaSetValues(children[i], 844 XtNrightMargin, puller_width, 845 NULL); 846 } 847 } 848 gui_athena_menu_colors(menu->id); 849 gui_athena_menu_font(menu->id); 850 851 pullright_name = make_pull_name(menu->dname); 852 menu->submenu_id = XtVaCreatePopupShell((char *)pullright_name, 853 simpleMenuWidgetClass, parent->submenu_id, 854 XtNtranslations, menuTrans, 855 NULL); 856 gui_athena_menu_colors(menu->submenu_id); 857 gui_athena_menu_font(menu->submenu_id); 858 vim_free(pullright_name); 859 XtAddCallback(menu->submenu_id, XtNpopupCallback, 860 gui_athena_popup_callback, (XtPointer)menu); 861 862 if (parent->parent != NULL) 863 XtOverrideTranslations(parent->submenu_id, parentTrans); 864 } 865 a_cur_menu = NULL; 866 } 867 868 /* Used to determine whether a SimpleMenu has pulldown entries. 869 * 870 * "id" is the parent of the menu items. 871 * Ignore widget "ignore" in the pane. 872 */ 873 static Boolean 874 gui_athena_menu_has_submenus(Widget id, Widget ignore) 875 { 876 WidgetList children; 877 Cardinal num_children; 878 int i; 879 880 XtVaGetValues(id, XtNchildren, &children, 881 XtNnumChildren, &num_children, 882 NULL); 883 for (i = 0; i < (int)num_children; ++i) 884 { 885 if (children[i] == ignore) 886 continue; 887 if (has_submenu(children[i])) 888 return True; 889 } 890 return False; 891 } 892 893 static void 894 gui_athena_menu_font(Widget id) 895 { 896 #ifdef FONTSET_ALWAYS 897 if (gui.menu_fontset != NOFONTSET) 898 { 899 if (XtIsManaged(id)) 900 { 901 XtUnmanageChild(id); 902 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL); 903 /* We should force the widget to recalculate its 904 * geometry now. */ 905 XtManageChild(id); 906 } 907 else 908 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL); 909 if (has_submenu(id)) 910 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL); 911 } 912 #else 913 int managed = FALSE; 914 915 if (gui.menu_font != NOFONT) 916 { 917 if (XtIsManaged(id)) 918 { 919 XtUnmanageChild(id); 920 managed = TRUE; 921 } 922 923 # ifdef FEAT_XFONTSET 924 if (gui.fontset != NOFONTSET) 925 XtVaSetValues(id, XtNfontSet, gui.menu_font, NULL); 926 else 927 # endif 928 XtVaSetValues(id, XtNfont, gui.menu_font, NULL); 929 if (has_submenu(id)) 930 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL); 931 932 /* Force the widget to recalculate its geometry now. */ 933 if (managed) 934 XtManageChild(id); 935 } 936 #endif 937 } 938 939 940 void 941 gui_mch_new_menu_font(void) 942 { 943 Pixmap oldpuller = None; 944 945 if (menuBar == (Widget)0) 946 return; 947 948 if (pullerBitmap != None) 949 { 950 oldpuller = pullerBitmap; 951 pullerBitmap = gui_athena_create_pullright_pixmap(NULL); 952 } 953 gui_mch_submenu_change(root_menu, FALSE); 954 955 { 956 /* Iterate through the menubar menu items and get the height of 957 * each one. The menu bar height is set to the maximum of all 958 * the heights. 959 */ 960 vimmenu_T *mp; 961 int max_height = 9999; 962 963 for (mp = root_menu; mp != NULL; mp = mp->next) 964 { 965 if (menu_is_menubar(mp->dname)) 966 { 967 Dimension height; 968 969 XtVaGetValues(mp->id, 970 XtNheight, &height, 971 NULL); 972 if (height < max_height) 973 max_height = height; 974 } 975 } 976 if (max_height != 9999) 977 { 978 /* Don't update the menu height when it was set at a fixed value */ 979 if (!gui.menu_height_fixed) 980 { 981 Dimension space, border; 982 983 XtVaGetValues(menuBar, 984 XtNvSpace, &space, 985 XtNborderWidth, &border, 986 NULL); 987 gui.menu_height = max_height + 2 * (space + border); 988 } 989 } 990 } 991 /* Now, to simulate the window being resized. Only, this 992 * will resize the window to its current state. 993 * 994 * There has to be a better way, but I do not see one at this time. 995 * (David Harrison) 996 */ 997 { 998 Position w, h; 999 1000 XtVaGetValues(vimShell, 1001 XtNwidth, &w, 1002 XtNheight, &h, 1003 NULL); 1004 gui_resize_shell(w, h 1005 #ifdef FEAT_XIM 1006 - xim_get_status_area_height() 1007 #endif 1008 ); 1009 } 1010 gui_set_shellsize(FALSE, TRUE, RESIZE_VERT); 1011 ui_new_shellsize(); 1012 if (oldpuller != None) 1013 XFreePixmap(gui.dpy, oldpuller); 1014 } 1015 1016 #if defined(FEAT_BEVAL_GUI) || defined(PROTO) 1017 void 1018 gui_mch_new_tooltip_font(void) 1019 { 1020 # ifdef FEAT_TOOLBAR 1021 vimmenu_T *menu; 1022 1023 if (toolBar == (Widget)0) 1024 return; 1025 1026 menu = gui_find_menu((char_u *)"ToolBar"); 1027 if (menu != NULL) 1028 gui_mch_submenu_change(menu, FALSE); 1029 # endif 1030 } 1031 1032 void 1033 gui_mch_new_tooltip_colors(void) 1034 { 1035 # ifdef FEAT_TOOLBAR 1036 vimmenu_T *menu; 1037 1038 if (toolBar == (Widget)0) 1039 return; 1040 1041 menu = gui_find_menu((char_u *)"ToolBar"); 1042 if (menu != NULL) 1043 gui_mch_submenu_change(menu, TRUE); 1044 # endif 1045 } 1046 #endif 1047 1048 static void 1049 gui_mch_submenu_change( 1050 vimmenu_T *menu, 1051 int colors) /* TRUE for colors, FALSE for font */ 1052 { 1053 vimmenu_T *mp; 1054 1055 for (mp = menu; mp != NULL; mp = mp->next) 1056 { 1057 if (mp->id != (Widget)0) 1058 { 1059 if (colors) 1060 { 1061 gui_athena_menu_colors(mp->id); 1062 #ifdef FEAT_TOOLBAR 1063 /* For a toolbar item: Free the pixmap and allocate a new one, 1064 * so that the background color is right. */ 1065 if (mp->image != (Pixmap)0) 1066 { 1067 XFreePixmap(gui.dpy, mp->image); 1068 get_toolbar_pixmap(mp, &mp->image); 1069 if (mp->image != (Pixmap)0) 1070 XtVaSetValues(mp->id, XtNbitmap, mp->image, NULL); 1071 } 1072 1073 # ifdef FEAT_BEVAL_GUI 1074 /* If we have a tooltip, then we need to change its colors */ 1075 if (mp->tip != NULL) 1076 { 1077 Arg args[2]; 1078 1079 args[0].name = XtNbackground; 1080 args[0].value = gui.tooltip_bg_pixel; 1081 args[1].name = XtNforeground; 1082 args[1].value = gui.tooltip_fg_pixel; 1083 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); 1084 } 1085 # endif 1086 #endif 1087 } 1088 else 1089 { 1090 gui_athena_menu_font(mp->id); 1091 #ifdef FEAT_BEVAL_GUI 1092 /* If we have a tooltip, then we need to change its font */ 1093 /* Assume XtNinternational == True (in createBalloonEvalWindow) 1094 */ 1095 if (mp->tip != NULL) 1096 { 1097 Arg args[1]; 1098 1099 args[0].name = XtNfontSet; 1100 args[0].value = (XtArgVal)gui.tooltip_fontset; 1101 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); 1102 } 1103 #endif 1104 } 1105 } 1106 1107 if (mp->children != NULL) 1108 { 1109 /* Set the colors/font for the tear off widget */ 1110 if (mp->submenu_id != (Widget)0) 1111 { 1112 if (colors) 1113 gui_athena_menu_colors(mp->submenu_id); 1114 else 1115 gui_athena_menu_font(mp->submenu_id); 1116 } 1117 /* Set the colors for the children */ 1118 gui_mch_submenu_change(mp->children, colors); 1119 } 1120 } 1121 } 1122 1123 /* 1124 * Make a submenu name into a pullright name. 1125 * Replace '.' by '_', can't include '.' in the submenu name. 1126 */ 1127 static char_u * 1128 make_pull_name(char_u * name) 1129 { 1130 char_u *pname; 1131 char_u *p; 1132 1133 pname = vim_strnsave(name, STRLEN(name) + strlen("-pullright")); 1134 if (pname != NULL) 1135 { 1136 strcat((char *)pname, "-pullright"); 1137 while ((p = vim_strchr(pname, '.')) != NULL) 1138 *p = '_'; 1139 } 1140 return pname; 1141 } 1142 1143 void 1144 gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED) 1145 { 1146 vimmenu_T *parent = menu->parent; 1147 1148 a_cur_menu = menu; 1149 # ifdef FEAT_TOOLBAR 1150 if (menu_is_toolbar(parent->name)) 1151 { 1152 WidgetClass type; 1153 int n; 1154 Arg args[21]; 1155 1156 n = 0; 1157 if (menu_is_separator(menu->name)) 1158 { 1159 XtSetArg(args[n], XtNlabel, ""); n++; 1160 XtSetArg(args[n], XtNborderWidth, 0); n++; 1161 } 1162 else 1163 { 1164 get_toolbar_pixmap(menu, &menu->image); 1165 XtSetArg(args[n], XtNlabel, menu->dname); n++; 1166 XtSetArg(args[n], XtNinternalHeight, 1); n++; 1167 XtSetArg(args[n], XtNinternalWidth, 1); n++; 1168 XtSetArg(args[n], XtNborderWidth, 1); n++; 1169 if (menu->image != 0) 1170 XtSetArg(args[n], XtNbitmap, menu->image); n++; 1171 } 1172 XtSetArg(args[n], XtNhighlightThickness, 0); n++; 1173 type = commandWidgetClass; 1174 /* TODO: figure out the position in the toolbar? 1175 * This currently works fine for the default toolbar, but 1176 * what if we add/remove items during later runtime? 1177 */ 1178 1179 /* NOTE: "idx" isn't used here. The position is calculated by 1180 * athena_calculate_ins_pos(). The position it calculates 1181 * should be equal to "idx". 1182 */ 1183 /* TODO: Could we just store "idx" and use that as the child 1184 * placement? 1185 */ 1186 1187 if (menu->id == NULL) 1188 { 1189 menu->id = XtCreateManagedWidget((char *)menu->dname, 1190 type, toolBar, args, n); 1191 XtAddCallback(menu->id, 1192 XtNcallback, gui_x11_menu_cb, menu); 1193 } 1194 else 1195 XtSetValues(menu->id, args, n); 1196 gui_athena_menu_colors(menu->id); 1197 1198 #ifdef FEAT_BEVAL_GUI 1199 gui_mch_menu_set_tip(menu); 1200 #endif 1201 1202 menu->parent = parent; 1203 menu->submenu_id = NULL; 1204 if (!XtIsManaged(toolBar) 1205 && vim_strchr(p_go, GO_TOOLBAR) != NULL) 1206 gui_mch_show_toolbar(TRUE); 1207 gui.toolbar_height = gui_mch_compute_toolbar_height(); 1208 return; 1209 } /* toolbar menu item */ 1210 # endif 1211 1212 /* Add menu separator */ 1213 if (menu_is_separator(menu->name)) 1214 { 1215 menu->submenu_id = (Widget)0; 1216 menu->id = XtVaCreateManagedWidget((char *)menu->dname, 1217 smeLineObjectClass, parent->submenu_id, 1218 NULL); 1219 if (menu->id == (Widget)0) 1220 return; 1221 gui_athena_menu_colors(menu->id); 1222 } 1223 else 1224 { 1225 if (parent != NULL && parent->submenu_id != (Widget)0) 1226 { 1227 menu->submenu_id = (Widget)0; 1228 menu->id = XtVaCreateManagedWidget((char *)menu->dname, 1229 smeBSBObjectClass, parent->submenu_id, 1230 XtNlabel, menu->dname, 1231 #ifdef FONTSET_ALWAYS 1232 XtNinternational, True, 1233 #endif 1234 NULL); 1235 if (menu->id == (Widget)0) 1236 return; 1237 1238 /* If there are other "pulldown" items in this pane, then adjust 1239 * the right margin to accommodate the arrow pixmap, otherwise 1240 * the right margin will be the same as the left margin. 1241 */ 1242 { 1243 Dimension left_margin; 1244 1245 XtVaGetValues(menu->id, XtNleftMargin, &left_margin, NULL); 1246 XtVaSetValues(menu->id, XtNrightMargin, 1247 gui_athena_menu_has_submenus(parent->submenu_id, NULL) ? 1248 puller_width : 1249 left_margin, 1250 NULL); 1251 } 1252 1253 gui_athena_menu_colors(menu->id); 1254 gui_athena_menu_font(menu->id); 1255 XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb, 1256 (XtPointer)menu); 1257 } 1258 } 1259 a_cur_menu = NULL; 1260 } 1261 1262 #if defined(FEAT_TOOLBAR) || defined(PROTO) 1263 void 1264 gui_mch_show_toolbar(int showit) 1265 { 1266 Cardinal numChildren; /* how many children toolBar has */ 1267 1268 if (toolBar == (Widget)0) 1269 return; 1270 XtVaGetValues(toolBar, XtNnumChildren, &numChildren, NULL); 1271 if (showit && numChildren > 0) 1272 { 1273 /* Assume that we want to show the toolbar if p_toolbar contains valid 1274 * option settings, therefore p_toolbar must not be NULL. 1275 */ 1276 WidgetList children; 1277 1278 XtVaGetValues(toolBar, XtNchildren, &children, NULL); 1279 { 1280 void (*action)(BalloonEval *); 1281 int text = 0; 1282 1283 if (strstr((const char *)p_toolbar, "tooltips")) 1284 action = &gui_mch_enable_beval_area; 1285 else 1286 action = &gui_mch_disable_beval_area; 1287 if (strstr((const char *)p_toolbar, "text")) 1288 text = 1; 1289 else if (strstr((const char *)p_toolbar, "icons")) 1290 text = -1; 1291 if (text != 0) 1292 { 1293 vimmenu_T *toolbar; 1294 vimmenu_T *cur; 1295 1296 for (toolbar = root_menu; toolbar; toolbar = toolbar->next) 1297 if (menu_is_toolbar(toolbar->dname)) 1298 break; 1299 /* Assumption: toolbar is NULL if there is no toolbar, 1300 * otherwise it contains the toolbar menu structure. 1301 * 1302 * Assumption: "numChildren" == the number of items in the list 1303 * of items beginning with toolbar->children. 1304 */ 1305 if (toolbar) 1306 { 1307 for (cur = toolbar->children; cur; cur = cur->next) 1308 { 1309 Arg args[2]; 1310 int n = 0; 1311 1312 /* Enable/Disable tooltip (OK to enable while currently 1313 * enabled) 1314 */ 1315 if (cur->tip != NULL) 1316 (*action)(cur->tip); 1317 if (text == 1) 1318 { 1319 XtSetArg(args[n], XtNbitmap, None); 1320 n++; 1321 XtSetArg(args[n], XtNlabel, 1322 menu_is_separator(cur->name) ? "" : 1323 (char *)cur->dname); 1324 n++; 1325 } 1326 else 1327 { 1328 XtSetArg(args[n], XtNbitmap, cur->image); 1329 n++; 1330 XtSetArg(args[n], XtNlabel, (cur->image == None) ? 1331 menu_is_separator(cur->name) ? 1332 "" : 1333 (char *)cur->dname 1334 : 1335 (char *)None); 1336 n++; 1337 } 1338 if (cur->id != NULL) 1339 { 1340 XtUnmanageChild(cur->id); 1341 XtSetValues(cur->id, args, n); 1342 XtManageChild(cur->id); 1343 } 1344 } 1345 } 1346 } 1347 } 1348 gui.toolbar_height = gui_mch_compute_toolbar_height(); 1349 XtManageChild(toolBar); 1350 if (XtIsManaged(menuBar)) 1351 { 1352 XtVaSetValues(textArea, 1353 XtNvertDistance, gui.toolbar_height + gui.menu_height, 1354 NULL); 1355 XtVaSetValues(toolBar, 1356 XtNvertDistance, gui.menu_height, 1357 NULL); 1358 } 1359 else 1360 { 1361 XtVaSetValues(textArea, 1362 XtNvertDistance, gui.toolbar_height, 1363 NULL); 1364 XtVaSetValues(toolBar, 1365 XtNvertDistance, 0, 1366 NULL); 1367 } 1368 } 1369 else 1370 { 1371 gui.toolbar_height = 0; 1372 if (XtIsManaged(menuBar)) 1373 XtVaSetValues(textArea, 1374 XtNvertDistance, gui.menu_height, 1375 NULL); 1376 else 1377 XtVaSetValues(textArea, 1378 XtNvertDistance, 0, 1379 NULL); 1380 1381 XtUnmanageChild(toolBar); 1382 } 1383 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT); 1384 } 1385 1386 1387 int 1388 gui_mch_compute_toolbar_height(void) 1389 { 1390 Dimension height; /* total Toolbar height */ 1391 Dimension whgt; /* height of each widget */ 1392 Dimension marginHeight; /* XmNmarginHeight of toolBar */ 1393 Dimension shadowThickness; /* thickness of Xtparent(toolBar) */ 1394 WidgetList children; /* list of toolBar's children */ 1395 Cardinal numChildren; /* how many children toolBar has */ 1396 int i; 1397 1398 height = 0; 1399 shadowThickness = 0; 1400 marginHeight = 0; 1401 if (toolBar != (Widget)0) 1402 { 1403 XtVaGetValues(toolBar, 1404 XtNborderWidth, &shadowThickness, 1405 XtNvSpace, &marginHeight, 1406 XtNchildren, &children, 1407 XtNnumChildren, &numChildren, 1408 NULL); 1409 for (i = 0; i < (int)numChildren; i++) 1410 { 1411 whgt = 0; 1412 1413 XtVaGetValues(children[i], XtNheight, &whgt, NULL); 1414 if (height < whgt) 1415 height = whgt; 1416 } 1417 } 1418 1419 return (int)(height + (marginHeight << 1) + (shadowThickness << 1)); 1420 } 1421 1422 void 1423 gui_mch_get_toolbar_colors( 1424 Pixel *bgp, 1425 Pixel *fgp, 1426 Pixel *bsp, 1427 Pixel *tsp, 1428 Pixel *hsp) 1429 { 1430 XtVaGetValues(toolBar, XtNbackground, bgp, XtNborderColor, fgp, NULL); 1431 *bsp = *bgp; 1432 *tsp = *fgp; 1433 *hsp = *tsp; 1434 } 1435 #endif 1436 1437 1438 void 1439 gui_mch_toggle_tearoffs(int enable UNUSED) 1440 { 1441 /* no tearoff menus */ 1442 } 1443 1444 void 1445 gui_mch_new_menu_colors(void) 1446 { 1447 if (menuBar == (Widget)0) 1448 return; 1449 if (gui.menu_fg_pixel != INVALCOLOR) 1450 XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL); 1451 gui_athena_menu_colors(menuBar); 1452 #ifdef FEAT_TOOLBAR 1453 gui_athena_menu_colors(toolBar); 1454 #endif 1455 1456 gui_mch_submenu_change(root_menu, TRUE); 1457 } 1458 1459 /* 1460 * Destroy the machine specific menu widget. 1461 */ 1462 void 1463 gui_mch_destroy_menu(vimmenu_T *menu) 1464 { 1465 Widget parent; 1466 1467 /* There is no item for the toolbar. */ 1468 if (menu->id == (Widget)0) 1469 return; 1470 1471 parent = XtParent(menu->id); 1472 1473 /* When removing the last "pulldown" menu item from a pane, adjust the 1474 * right margins of the remaining widgets. 1475 */ 1476 if (menu->submenu_id != (Widget)0) 1477 { 1478 /* Go through the menu items in the parent of this item and 1479 * adjust their margins, if necessary. 1480 * This takes care of the case when we delete the last menu item in a 1481 * pane that has a submenu. In this case, there will be no arrow 1482 * pixmaps shown anymore. 1483 */ 1484 { 1485 WidgetList children; 1486 Cardinal num_children; 1487 int i; 1488 Dimension right_margin = 0; 1489 Boolean get_left_margin = False; 1490 1491 XtVaGetValues(parent, XtNchildren, &children, 1492 XtNnumChildren, &num_children, 1493 NULL); 1494 if (gui_athena_menu_has_submenus(parent, menu->id)) 1495 right_margin = puller_width; 1496 else 1497 get_left_margin = True; 1498 1499 for (i = 0; i < (int)num_children; ++i) 1500 { 1501 if (children[i] == menu->id) 1502 continue; 1503 if (get_left_margin == True) 1504 { 1505 Dimension left_margin; 1506 1507 XtVaGetValues(children[i], XtNleftMargin, &left_margin, 1508 NULL); 1509 XtVaSetValues(children[i], XtNrightMargin, left_margin, 1510 NULL); 1511 } 1512 else 1513 XtVaSetValues(children[i], XtNrightMargin, right_margin, 1514 NULL); 1515 } 1516 } 1517 } 1518 /* Please be sure to destroy the parent widget first (i.e. menu->id). 1519 * 1520 * This code should be basically identical to that in the file gui_motif.c 1521 * because they are both Xt based. 1522 */ 1523 if (menu->id != (Widget)0) 1524 { 1525 Cardinal num_children; 1526 Dimension height, space, border; 1527 1528 XtVaGetValues(menuBar, 1529 XtNvSpace, &space, 1530 XtNborderWidth, &border, 1531 NULL); 1532 XtVaGetValues(menu->id, 1533 XtNheight, &height, 1534 NULL); 1535 #if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL_GUI) 1536 if (parent == toolBar && menu->tip != NULL) 1537 { 1538 /* We try to destroy this before the actual menu, because there are 1539 * callbacks, etc. that will be unregistered during the tooltip 1540 * destruction. 1541 * 1542 * If you call "gui_mch_destroy_beval_area()" after destroying 1543 * menu->id, then the tooltip's window will have already been 1544 * deallocated by Xt, and unknown behaviour will ensue (probably 1545 * a core dump). 1546 */ 1547 gui_mch_destroy_beval_area(menu->tip); 1548 menu->tip = NULL; 1549 } 1550 #endif 1551 /* 1552 * This is a hack to stop the Athena simpleMenuWidget from getting a 1553 * BadValue error when a menu's last child is destroyed. We check to 1554 * see if this is the last child and if so, don't delete it. The parent 1555 * will be deleted soon anyway, and it will delete its children like 1556 * all good widgets do. 1557 */ 1558 /* NOTE: The cause of the BadValue X Protocol Error is because when the 1559 * last child is destroyed, it is first unmanaged, thus causing a 1560 * geometry resize request from the parent Shell widget. 1561 * Since the Shell widget has no more children, it is resized to have 1562 * width/height of 0. XConfigureWindow() is then called with the 1563 * width/height of 0, which generates the BadValue. 1564 * 1565 * This happens in phase two of the widget destruction process. 1566 */ 1567 { 1568 if (parent != menuBar 1569 #ifdef FEAT_TOOLBAR 1570 && parent != toolBar 1571 #endif 1572 ) 1573 { 1574 XtVaGetValues(parent, XtNnumChildren, &num_children, NULL); 1575 if (num_children > 1) 1576 XtDestroyWidget(menu->id); 1577 } 1578 else 1579 XtDestroyWidget(menu->id); 1580 menu->id = (Widget)0; 1581 } 1582 1583 if (parent == menuBar) 1584 { 1585 if (!gui.menu_height_fixed) 1586 gui.menu_height = height + 2 * (space + border); 1587 } 1588 #ifdef FEAT_TOOLBAR 1589 else if (parent == toolBar) 1590 { 1591 /* When removing last toolbar item, don't display the toolbar. */ 1592 XtVaGetValues(toolBar, XtNnumChildren, &num_children, NULL); 1593 if (num_children == 0) 1594 gui_mch_show_toolbar(FALSE); 1595 else 1596 gui.toolbar_height = gui_mch_compute_toolbar_height(); 1597 } 1598 #endif 1599 } 1600 if (menu->submenu_id != (Widget)0) 1601 { 1602 XtDestroyWidget(menu->submenu_id); 1603 menu->submenu_id = (Widget)0; 1604 } 1605 } 1606 1607 static void 1608 gui_athena_menu_timeout( 1609 XtPointer client_data, 1610 XtIntervalId *id UNUSED) 1611 { 1612 Widget w = (Widget)client_data; 1613 Widget popup; 1614 1615 timer = 0; 1616 if (XtIsSubclass(w,smeBSBObjectClass)) 1617 { 1618 Pixmap p; 1619 1620 XtVaGetValues(w, XtNrightBitmap, &p, NULL); 1621 if ((p != None) && (p != XtUnspecifiedPixmap)) 1622 { 1623 /* We are dealing with an item that has a submenu */ 1624 popup = get_popup_entry(XtParent(w)); 1625 if (popup == (Widget)0) 1626 return; 1627 XtPopup(popup, XtGrabNonexclusive); 1628 } 1629 } 1630 } 1631 1632 /* This routine is used to calculate the position (in screen coordinates) 1633 * where a submenu should appear relative to the menu entry that popped it 1634 * up. It should appear even with and just slightly to the left of the 1635 * rightmost end of the menu entry that caused the popup. 1636 * 1637 * This is called when XtPopup() is called. 1638 */ 1639 static void 1640 gui_athena_popup_callback( 1641 Widget w, 1642 XtPointer client_data, 1643 XtPointer call_data UNUSED) 1644 { 1645 /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */ 1646 vimmenu_T *menu = (vimmenu_T *)client_data; 1647 Dimension width; 1648 Position root_x, root_y; 1649 1650 /* First, popdown any siblings that may have menus popped up */ 1651 { 1652 vimmenu_T *i; 1653 1654 for (i = menu->parent->children; i != NULL; i = i->next) 1655 { 1656 if (i->submenu_id != NULL && XtIsManaged(i->submenu_id)) 1657 XtPopdown(i->submenu_id); 1658 } 1659 } 1660 XtVaGetValues(XtParent(w), 1661 XtNwidth, &width, 1662 NULL); 1663 /* Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id */ 1664 /* i.e. This IS the active entry */ 1665 XtTranslateCoords(menu->id,width - 5, 0, &root_x, &root_y); 1666 XtVaSetValues(w, XtNx, root_x, 1667 XtNy, root_y, 1668 NULL); 1669 } 1670 1671 static void 1672 gui_athena_popdown_submenus_action( 1673 Widget w, 1674 XEvent *event, 1675 String *args, 1676 Cardinal *nargs) 1677 { 1678 WidgetList children; 1679 Cardinal num_children; 1680 1681 XtVaGetValues(w, XtNchildren, &children, 1682 XtNnumChildren, &num_children, 1683 NULL); 1684 for (; num_children > 0; --num_children) 1685 { 1686 Widget child = children[num_children - 1]; 1687 1688 if (has_submenu(child)) 1689 { 1690 Widget temp_w; 1691 1692 temp_w = submenu_widget(child); 1693 gui_athena_popdown_submenus_action(temp_w,event,args,nargs); 1694 XtPopdown(temp_w); 1695 } 1696 } 1697 } 1698 1699 /* Used to determine if the given widget has a submenu that can be popped up. */ 1700 static Boolean 1701 has_submenu(Widget widget) 1702 { 1703 if ((widget != NULL) && XtIsSubclass(widget,smeBSBObjectClass)) 1704 { 1705 Pixmap p; 1706 1707 XtVaGetValues(widget, XtNrightBitmap, &p, NULL); 1708 if ((p != None) && (p != XtUnspecifiedPixmap)) 1709 return True; 1710 } 1711 return False; 1712 } 1713 1714 static void 1715 gui_athena_delayed_arm_action( 1716 Widget w, 1717 XEvent *event, 1718 String *args, 1719 Cardinal *nargs) 1720 { 1721 Dimension width, height; 1722 1723 if (event->type != MotionNotify) 1724 return; 1725 1726 XtVaGetValues(w, 1727 XtNwidth, &width, 1728 XtNheight, &height, 1729 NULL); 1730 1731 if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height) 1732 return; 1733 1734 { 1735 static Widget previous_active_widget = NULL; 1736 Widget current; 1737 1738 current = XawSimpleMenuGetActiveEntry(w); 1739 if (current != previous_active_widget) 1740 { 1741 if (timer) 1742 { 1743 /* If the timeout hasn't been triggered, remove it */ 1744 XtRemoveTimeOut(timer); 1745 } 1746 gui_athena_popdown_submenus_action(w,event,args,nargs); 1747 if (has_submenu(current)) 1748 { 1749 XtAppAddTimeOut(XtWidgetToApplicationContext(w), 600L, 1750 gui_athena_menu_timeout, 1751 (XtPointer)current); 1752 } 1753 previous_active_widget = current; 1754 } 1755 } 1756 } 1757 1758 static Widget 1759 get_popup_entry(Widget w) 1760 { 1761 Widget menuw; 1762 1763 /* Get the active entry for the current menu */ 1764 if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)0) 1765 return NULL; 1766 1767 return submenu_widget(menuw); 1768 } 1769 1770 /* Given the widget that has been determined to have a submenu, return the submenu widget 1771 * that is to be popped up. 1772 */ 1773 static Widget 1774 submenu_widget(Widget widget) 1775 { 1776 /* Precondition: has_submenu(widget) == True 1777 * XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True 1778 */ 1779 1780 char_u *pullright_name; 1781 Widget popup; 1782 1783 pullright_name = make_pull_name((char_u *)XtName(widget)); 1784 popup = XtNameToWidget(XtParent(widget), (char *)pullright_name); 1785 vim_free(pullright_name); 1786 1787 return popup; 1788 /* Postcondition: (popup != NULL) implies 1789 * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */ 1790 } 1791 1792 void 1793 gui_mch_show_popupmenu(vimmenu_T *menu) 1794 { 1795 int rootx, rooty, winx, winy; 1796 Window root, child; 1797 unsigned int mask; 1798 1799 if (menu->submenu_id == (Widget)0) 1800 return; 1801 1802 /* Position the popup menu at the pointer */ 1803 if (XQueryPointer(gui.dpy, XtWindow(vimShell), &root, &child, 1804 &rootx, &rooty, &winx, &winy, &mask)) 1805 { 1806 rootx -= 30; 1807 if (rootx < 0) 1808 rootx = 0; 1809 rooty -= 5; 1810 if (rooty < 0) 1811 rooty = 0; 1812 XtVaSetValues(menu->submenu_id, 1813 XtNx, rootx, 1814 XtNy, rooty, 1815 NULL); 1816 } 1817 1818 XtOverrideTranslations(menu->submenu_id, popupTrans); 1819 XtPopupSpringLoaded(menu->submenu_id); 1820 } 1821 1822 #endif /* FEAT_MENU */ 1823 1824 /* 1825 * Set the menu and scrollbar colors to their default values. 1826 */ 1827 void 1828 gui_mch_def_colors(void) 1829 { 1830 /* 1831 * Get the colors ourselves. Using the automatic conversion doesn't 1832 * handle looking for approximate colors. 1833 */ 1834 if (gui.in_use) 1835 { 1836 gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name); 1837 gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name); 1838 gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name); 1839 gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name); 1840 #ifdef FEAT_BEVAL_GUI 1841 gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name); 1842 gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name); 1843 #endif 1844 } 1845 } 1846 1847 1848 /* 1849 * Scrollbar stuff. 1850 */ 1851 1852 void 1853 gui_mch_set_scrollbar_thumb( 1854 scrollbar_T *sb, 1855 long val, 1856 long size, 1857 long max) 1858 { 1859 double v, s; 1860 1861 if (sb->id == (Widget)0) 1862 return; 1863 1864 /* 1865 * Athena scrollbar must go from 0.0 to 1.0. 1866 */ 1867 if (max == 0) 1868 { 1869 /* So you can't scroll it at all (normally it scrolls past end) */ 1870 #ifdef FEAT_GUI_NEXTAW 1871 XawScrollbarSetThumb(sb->id, 0.0, 1.0); 1872 #else 1873 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0); 1874 #endif 1875 } 1876 else 1877 { 1878 v = (double)val / (double)(max + 1); 1879 s = (double)size / (double)(max + 1); 1880 #ifdef FEAT_GUI_NEXTAW 1881 XawScrollbarSetThumb(sb->id, v, s); 1882 #else 1883 vim_XawScrollbarSetThumb(sb->id, v, s, 1.0); 1884 #endif 1885 } 1886 } 1887 1888 void 1889 gui_mch_set_scrollbar_pos( 1890 scrollbar_T *sb, 1891 int x, 1892 int y, 1893 int w, 1894 int h) 1895 { 1896 if (sb->id == (Widget)0) 1897 return; 1898 1899 XtUnmanageChild(sb->id); 1900 XtVaSetValues(sb->id, 1901 XtNhorizDistance, x, 1902 XtNvertDistance, y, 1903 XtNwidth, w, 1904 XtNheight, h, 1905 NULL); 1906 XtManageChild(sb->id); 1907 } 1908 1909 void 1910 gui_mch_enable_scrollbar(scrollbar_T *sb, int flag) 1911 { 1912 if (sb->id != (Widget)0) 1913 { 1914 if (flag) 1915 XtManageChild(sb->id); 1916 else 1917 XtUnmanageChild(sb->id); 1918 } 1919 } 1920 1921 void 1922 gui_mch_create_scrollbar( 1923 scrollbar_T *sb, 1924 int orient) /* SBAR_VERT or SBAR_HORIZ */ 1925 { 1926 sb->id = XtVaCreateWidget("scrollBar", 1927 #ifdef FEAT_GUI_NEXTAW 1928 scrollbarWidgetClass, vimForm, 1929 #else 1930 vim_scrollbarWidgetClass, vimForm, 1931 #endif 1932 XtNresizable, True, 1933 XtNtop, XtChainTop, 1934 XtNbottom, XtChainTop, 1935 XtNleft, XtChainLeft, 1936 XtNright, XtChainLeft, 1937 XtNborderWidth, 0, 1938 XtNorientation, (orient == SBAR_VERT) ? XtorientVertical 1939 : XtorientHorizontal, 1940 XtNforeground, gui.scroll_fg_pixel, 1941 XtNbackground, gui.scroll_bg_pixel, 1942 NULL); 1943 if (sb->id == (Widget)0) 1944 return; 1945 1946 XtAddCallback(sb->id, XtNjumpProc, 1947 gui_athena_scroll_cb_jump, (XtPointer)sb->ident); 1948 XtAddCallback(sb->id, XtNscrollProc, 1949 gui_athena_scroll_cb_scroll, (XtPointer)sb->ident); 1950 1951 #ifdef FEAT_GUI_NEXTAW 1952 XawScrollbarSetThumb(sb->id, 0.0, 1.0); 1953 #else 1954 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0); 1955 #endif 1956 } 1957 1958 void 1959 gui_mch_destroy_scrollbar(scrollbar_T *sb) 1960 { 1961 if (sb->id != (Widget)0) 1962 XtDestroyWidget(sb->id); 1963 } 1964 1965 void 1966 gui_mch_set_scrollbar_colors(scrollbar_T *sb) 1967 { 1968 if (sb->id != (Widget)0) 1969 XtVaSetValues(sb->id, 1970 XtNforeground, gui.scroll_fg_pixel, 1971 XtNbackground, gui.scroll_bg_pixel, 1972 NULL); 1973 1974 /* This is needed for the rectangle below the vertical scrollbars. */ 1975 if (sb == &gui.bottom_sbar && vimForm != (Widget)0) 1976 gui_athena_scroll_colors(vimForm); 1977 } 1978 1979 /* 1980 * Miscellaneous stuff: 1981 */ 1982 Window 1983 gui_x11_get_wid(void) 1984 { 1985 return XtWindow(textArea); 1986 } 1987 1988 #if defined(FEAT_BROWSE) || defined(PROTO) 1989 /* 1990 * Put up a file requester. 1991 * Returns the selected name in allocated memory, or NULL for Cancel. 1992 */ 1993 char_u * 1994 gui_mch_browse( 1995 int saving UNUSED, /* select file to write */ 1996 char_u *title, /* title for the window */ 1997 char_u *dflt, /* default name */ 1998 char_u *ext UNUSED, /* extension added */ 1999 char_u *initdir, /* initial directory, NULL for current dir */ 2000 char_u *filter UNUSED) /* file name filter */ 2001 { 2002 Position x, y; 2003 char_u dirbuf[MAXPATHL]; 2004 2005 /* Concatenate "initdir" and "dflt". */ 2006 if (initdir == NULL || *initdir == NUL) 2007 mch_dirname(dirbuf, MAXPATHL); 2008 else if (STRLEN(initdir) + 2 < MAXPATHL) 2009 STRCPY(dirbuf, initdir); 2010 else 2011 dirbuf[0] = NUL; 2012 if (dflt != NULL && *dflt != NUL 2013 && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL) 2014 { 2015 add_pathsep(dirbuf); 2016 STRCAT(dirbuf, dflt); 2017 } 2018 2019 /* Position the file selector just below the menubar */ 2020 XtTranslateCoords(vimShell, (Position)0, (Position) 2021 #ifdef FEAT_MENU 2022 gui.menu_height 2023 #else 2024 0 2025 #endif 2026 , &x, &y); 2027 return (char_u *)vim_SelFile(vimShell, (char *)title, (char *)dirbuf, 2028 NULL, (int)x, (int)y, gui.menu_fg_pixel, gui.menu_bg_pixel, 2029 gui.scroll_fg_pixel, gui.scroll_bg_pixel); 2030 } 2031 #endif 2032 2033 #if defined(FEAT_GUI_DIALOG) || defined(PROTO) 2034 2035 static int dialogStatus; 2036 static Atom dialogatom; 2037 2038 /* 2039 * Callback function for the textfield. When CR is hit this works like 2040 * hitting the "OK" button, ESC like "Cancel". 2041 */ 2042 static void 2043 keyhit_callback( 2044 Widget w UNUSED, 2045 XtPointer client_data UNUSED, 2046 XEvent *event, 2047 Boolean *cont UNUSED) 2048 { 2049 char buf[2]; 2050 2051 if (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) 2052 { 2053 if (*buf == CAR) 2054 dialogStatus = 1; 2055 else if (*buf == ESC) 2056 dialogStatus = 0; 2057 } 2058 } 2059 2060 static void 2061 butproc( 2062 Widget w UNUSED, 2063 XtPointer client_data, 2064 XtPointer call_data UNUSED) 2065 { 2066 dialogStatus = (int)(long)client_data + 1; 2067 } 2068 2069 /* 2070 * Function called when dialog window closed. 2071 */ 2072 static void 2073 dialog_wm_handler( 2074 Widget w UNUSED, 2075 XtPointer client_data UNUSED, 2076 XEvent *event, 2077 Boolean *dum UNUSED) 2078 { 2079 if (event->type == ClientMessage 2080 && (Atom)((XClientMessageEvent *)event)->data.l[0] == dialogatom) 2081 dialogStatus = 0; 2082 } 2083 2084 int 2085 gui_mch_dialog( 2086 int type UNUSED, 2087 char_u *title, 2088 char_u *message, 2089 char_u *buttons, 2090 int dfltbutton UNUSED, 2091 char_u *textfield, 2092 int ex_cmd UNUSED) 2093 { 2094 char_u *buts; 2095 char_u *p, *next; 2096 XtAppContext app; 2097 XEvent event; 2098 Position wd, hd; 2099 Position wv, hv; 2100 Position x, y; 2101 Widget dialog; 2102 Widget dialogshell; 2103 Widget dialogmessage; 2104 Widget dialogtextfield = 0; 2105 Widget dialogButton; 2106 Widget prev_dialogButton = NULL; 2107 int butcount; 2108 int vertical; 2109 2110 if (title == NULL) 2111 title = (char_u *)_("Vim dialog"); 2112 dialogStatus = -1; 2113 2114 /* if our pointer is currently hidden, then we should show it. */ 2115 gui_mch_mousehide(FALSE); 2116 2117 /* Check 'v' flag in 'guioptions': vertical button placement. */ 2118 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); 2119 2120 /* The shell is created each time, to make sure it is resized properly */ 2121 dialogshell = XtVaCreatePopupShell("dialogShell", 2122 transientShellWidgetClass, vimShell, 2123 XtNtitle, title, 2124 NULL); 2125 if (dialogshell == (Widget)0) 2126 goto error; 2127 2128 dialog = XtVaCreateManagedWidget("dialog", 2129 formWidgetClass, dialogshell, 2130 XtNdefaultDistance, 20, 2131 NULL); 2132 if (dialog == (Widget)0) 2133 goto error; 2134 gui_athena_menu_colors(dialog); 2135 dialogmessage = XtVaCreateManagedWidget("dialogMessage", 2136 labelWidgetClass, dialog, 2137 XtNlabel, message, 2138 XtNtop, XtChainTop, 2139 XtNbottom, XtChainTop, 2140 XtNleft, XtChainLeft, 2141 XtNright, XtChainLeft, 2142 XtNresizable, True, 2143 XtNborderWidth, 0, 2144 NULL); 2145 gui_athena_menu_colors(dialogmessage); 2146 2147 if (textfield != NULL) 2148 { 2149 dialogtextfield = XtVaCreateManagedWidget("textfield", 2150 asciiTextWidgetClass, dialog, 2151 XtNwidth, 400, 2152 XtNtop, XtChainTop, 2153 XtNbottom, XtChainTop, 2154 XtNleft, XtChainLeft, 2155 XtNright, XtChainRight, 2156 XtNfromVert, dialogmessage, 2157 XtNresizable, True, 2158 XtNstring, textfield, 2159 XtNlength, IOSIZE, 2160 XtNuseStringInPlace, True, 2161 XtNeditType, XawtextEdit, 2162 XtNwrap, XawtextWrapNever, 2163 XtNresize, XawtextResizeHeight, 2164 NULL); 2165 XtManageChild(dialogtextfield); 2166 XtAddEventHandler(dialogtextfield, KeyPressMask, False, 2167 (XtEventHandler)keyhit_callback, (XtPointer)NULL); 2168 XawTextSetInsertionPoint(dialogtextfield, 2169 (XawTextPosition)STRLEN(textfield)); 2170 XtSetKeyboardFocus(dialog, dialogtextfield); 2171 } 2172 2173 /* make a copy, so that we can insert NULs */ 2174 buts = vim_strsave(buttons); 2175 if (buts == NULL) 2176 return -1; 2177 2178 p = buts; 2179 for (butcount = 0; *p; ++butcount) 2180 { 2181 for (next = p; *next; ++next) 2182 { 2183 if (*next == DLG_HOTKEY_CHAR) 2184 STRMOVE(next, next + 1); 2185 if (*next == DLG_BUTTON_SEP) 2186 { 2187 *next++ = NUL; 2188 break; 2189 } 2190 } 2191 dialogButton = XtVaCreateManagedWidget("button", 2192 commandWidgetClass, dialog, 2193 XtNlabel, p, 2194 XtNtop, XtChainBottom, 2195 XtNbottom, XtChainBottom, 2196 XtNleft, XtChainLeft, 2197 XtNright, XtChainLeft, 2198 XtNfromVert, textfield == NULL ? dialogmessage : dialogtextfield, 2199 XtNvertDistance, vertical ? 4 : 20, 2200 XtNresizable, False, 2201 NULL); 2202 gui_athena_menu_colors(dialogButton); 2203 if (butcount > 0) 2204 XtVaSetValues(dialogButton, 2205 vertical ? XtNfromVert : XtNfromHoriz, prev_dialogButton, 2206 NULL); 2207 2208 XtAddCallback(dialogButton, XtNcallback, butproc, (XtPointer)(long_u)butcount); 2209 p = next; 2210 prev_dialogButton = dialogButton; 2211 } 2212 vim_free(buts); 2213 2214 XtRealizeWidget(dialogshell); 2215 2216 /* Setup for catching the close-window event, don't let it close Vim! */ 2217 dialogatom = XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False); 2218 XSetWMProtocols(gui.dpy, XtWindow(dialogshell), &dialogatom, 1); 2219 XtAddEventHandler(dialogshell, NoEventMask, True, dialog_wm_handler, NULL); 2220 2221 XtVaGetValues(dialogshell, 2222 XtNwidth, &wd, 2223 XtNheight, &hd, 2224 NULL); 2225 XtVaGetValues(vimShell, 2226 XtNwidth, &wv, 2227 XtNheight, &hv, 2228 NULL); 2229 XtTranslateCoords(vimShell, 2230 (Position)((wv - wd) / 2), 2231 (Position)((hv - hd) / 2), 2232 &x, &y); 2233 if (x < 0) 2234 x = 0; 2235 if (y < 0) 2236 y = 0; 2237 XtVaSetValues(dialogshell, XtNx, x, XtNy, y, NULL); 2238 2239 /* Position the mouse pointer in the dialog, required for when focus 2240 * follows mouse. */ 2241 XWarpPointer(gui.dpy, (Window)0, XtWindow(dialogshell), 0, 0, 0, 0, 20, 40); 2242 2243 2244 app = XtWidgetToApplicationContext(dialogshell); 2245 2246 XtPopup(dialogshell, XtGrabNonexclusive); 2247 2248 for (;;) 2249 { 2250 XtAppNextEvent(app, &event); 2251 XtDispatchEvent(&event); 2252 if (dialogStatus >= 0) 2253 break; 2254 } 2255 2256 XtPopdown(dialogshell); 2257 2258 if (textfield != NULL && dialogStatus < 0) 2259 *textfield = NUL; 2260 2261 error: 2262 XtDestroyWidget(dialogshell); 2263 2264 return dialogStatus; 2265 } 2266 #endif 2267 2268 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU) 2269 /* 2270 * Set the colors of Widget "id" to the menu colors. 2271 */ 2272 static void 2273 gui_athena_menu_colors(Widget id) 2274 { 2275 if (gui.menu_bg_pixel != INVALCOLOR) 2276 XtVaSetValues(id, XtNbackground, gui.menu_bg_pixel, NULL); 2277 if (gui.menu_fg_pixel != INVALCOLOR) 2278 XtVaSetValues(id, XtNforeground, gui.menu_fg_pixel, NULL); 2279 } 2280 #endif 2281 2282 /* 2283 * Set the colors of Widget "id" to the scroll colors. 2284 */ 2285 static void 2286 gui_athena_scroll_colors(Widget id) 2287 { 2288 if (gui.scroll_bg_pixel != INVALCOLOR) 2289 XtVaSetValues(id, XtNbackground, gui.scroll_bg_pixel, NULL); 2290 if (gui.scroll_fg_pixel != INVALCOLOR) 2291 XtVaSetValues(id, XtNforeground, gui.scroll_fg_pixel, NULL); 2292 } 2293