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