1/* vi:set ts=8 sts=4 sw=4: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * GUI/Motif support by Robert Webb 5 * 6 * Do ":help uganda" in Vim to read copying and usage conditions. 7 * Do ":help credits" in Vim to see a list of people who contributed. 8 * See README.txt for an overview of the Vim source code. 9 */ 10 11#include <Xm/Form.h> 12#include <Xm/RowColumn.h> 13#include <Xm/PushB.h> 14#include <Xm/Text.h> 15#include <Xm/TextF.h> 16#include <Xm/Separator.h> 17#include <Xm/Label.h> 18#include <Xm/CascadeB.h> 19#include <Xm/ScrollBar.h> 20#include <Xm/MenuShell.h> 21#include <Xm/DrawingA.h> 22#if (XmVersion >= 1002) 23# include <Xm/RepType.h> 24#endif 25#include <Xm/Frame.h> 26#include <Xm/LabelG.h> 27#include <Xm/ToggleBG.h> 28#include <Xm/SeparatoG.h> 29#include <Xm/XmP.h> 30 31#include <X11/keysym.h> 32#include <X11/Xatom.h> 33#include <X11/StringDefs.h> 34#include <X11/Intrinsic.h> 35 36#include "vim.h" 37 38#ifdef HAVE_X11_XPM_H 39# include <X11/xpm.h> 40#else 41# ifdef HAVE_XM_XPMP_H 42# include <Xm/XpmP.h> 43# endif 44#endif 45#ifdef HAVE_XM_NOTEBOOK_H 46# include <Xm/Notebook.h> 47#endif 48 49#include "gui_xmebw.h" /* for our Enhanced Button Widget */ 50 51#if defined(FEAT_GUI_DIALOG) && defined(HAVE_XPM) 52# include "../pixmaps/alert.xpm" 53# include "../pixmaps/error.xpm" 54# include "../pixmaps/generic.xpm" 55# include "../pixmaps/info.xpm" 56# include "../pixmaps/quest.xpm" 57#endif 58 59#define MOTIF_POPUP 60 61extern Widget vimShell; 62 63static Widget vimForm; 64static Widget textAreaForm; 65Widget textArea; 66#ifdef FEAT_TOOLBAR 67static Widget toolBarFrame; 68static Widget toolBar; 69#endif 70#ifdef FEAT_GUI_TABLINE 71static Widget tabLine; 72static Widget tabLine_menu = 0; 73static int showing_tabline = 0; 74#endif 75#ifdef FEAT_FOOTER 76static Widget footer; 77#endif 78#ifdef FEAT_MENU 79# if (XmVersion >= 1002) 80/* remember the last set value for the tearoff item */ 81static int tearoff_val = (int)XmTEAR_OFF_ENABLED; 82# endif 83static Widget menuBar; 84#endif 85 86static void scroll_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 87#ifdef FEAT_GUI_TABLINE 88static void tabline_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 89static void tabline_button_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 90static void tabline_menu_cb __ARGS((Widget w, XtPointer closure, XEvent *e, Boolean *continue_dispatch)); 91static void tabline_balloon_cb __ARGS((BalloonEval *beval, int state)); 92#endif 93#ifdef FEAT_TOOLBAR 94# ifdef FEAT_FOOTER 95static void toolbarbutton_enter_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *)); 96static void toolbarbutton_leave_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *)); 97# endif 98static void reset_focus __ARGS((void)); 99#endif 100#ifdef FEAT_FOOTER 101static int gui_mch_compute_footer_height __ARGS((void)); 102#endif 103#ifdef WSDEBUG 104static void attachDump(Widget, char *); 105#endif 106 107static void gui_motif_menu_colors __ARGS((Widget id)); 108static void gui_motif_scroll_colors __ARGS((Widget id)); 109 110#if (XmVersion >= 1002) 111# define STRING_TAG XmFONTLIST_DEFAULT_TAG 112#else 113# define STRING_TAG XmSTRING_DEFAULT_CHARSET 114#endif 115 116/* 117 * Call-back routines. 118 */ 119 120 static void 121scroll_cb(w, client_data, call_data) 122 Widget w UNUSED; 123 XtPointer client_data, call_data; 124{ 125 scrollbar_T *sb; 126 long value; 127 int dragging; 128 129 sb = gui_find_scrollbar((long)client_data); 130 131 value = ((XmScrollBarCallbackStruct *)call_data)->value; 132 dragging = (((XmScrollBarCallbackStruct *)call_data)->reason == 133 (int)XmCR_DRAG); 134 gui_drag_scrollbar(sb, value, dragging); 135} 136 137#ifdef FEAT_GUI_TABLINE 138 static void 139tabline_cb(w, client_data, call_data) 140 Widget w UNUSED; 141 XtPointer client_data UNUSED; 142 XtPointer call_data; 143{ 144 XmNotebookCallbackStruct *nptr; 145 146 nptr = (XmNotebookCallbackStruct *)call_data; 147 if (nptr->reason != (int)XmCR_NONE) 148 send_tabline_event(nptr->page_number); 149} 150 151 static void 152tabline_button_cb(w, client_data, call_data) 153 Widget w; 154 XtPointer client_data UNUSED; 155 XtPointer call_data UNUSED; 156{ 157 int cmd, tab_idx; 158 159 XtVaGetValues(w, XmNuserData, &cmd, NULL); 160 XtVaGetValues(tabLine_menu, XmNuserData, &tab_idx, NULL); 161 162 send_tabline_menu_event(tab_idx, cmd); 163} 164 165/* 166 * Tabline single mouse click timeout handler 167 */ 168 static void 169motif_tabline_timer_cb (timed_out, interval_id) 170 XtPointer timed_out; 171 XtIntervalId *interval_id UNUSED; 172{ 173 *((int *)timed_out) = TRUE; 174} 175 176/* 177 * check if the tabline tab scroller is clicked 178 */ 179 static int 180tabline_scroller_clicked(scroller_name, event) 181 char *scroller_name; 182 XButtonPressedEvent *event; 183{ 184 Widget tab_scroll_w; 185 Position pos_x, pos_y; 186 Dimension width, height; 187 188 tab_scroll_w = XtNameToWidget(tabLine, scroller_name); 189 if (tab_scroll_w != (Widget)0) { 190 XtVaGetValues(tab_scroll_w, XmNx, &pos_x, XmNy, &pos_y, XmNwidth, 191 &width, XmNheight, &height, NULL); 192 if (pos_x >= 0) { 193 /* Tab scroller (next) is visible */ 194 if ((event->x >= pos_x) && (event->x <= pos_x + width) && 195 (event->y >= pos_y) && (event->y <= pos_y + height)) { 196 /* Clicked on the scroller */ 197 return TRUE; 198 } 199 } 200 } 201 return FALSE; 202} 203 204 static void 205tabline_menu_cb(w, closure, e, continue_dispatch) 206 Widget w; 207 XtPointer closure UNUSED; 208 XEvent *e; 209 Boolean *continue_dispatch UNUSED; 210{ 211 Widget tab_w; 212 XButtonPressedEvent *event; 213 int tab_idx = 0; 214 WidgetList children; 215 Cardinal numChildren; 216 static XtIntervalId timer = (XtIntervalId)0; 217 static int timed_out = TRUE; 218 219 event = (XButtonPressedEvent *)e; 220 221 if (event->button == Button1) 222 { 223 if (tabline_scroller_clicked("MajorTabScrollerNext", event) 224 || tabline_scroller_clicked("MajorTabScrollerPrevious", event)) 225 return; 226 227 if (!timed_out) 228 { 229 XtRemoveTimeOut(timer); 230 timed_out = TRUE; 231 232 /* 233 * Double click on the tabline gutter, add a new tab 234 */ 235 send_tabline_menu_event(0, TABLINE_MENU_NEW); 236 } 237 else 238 { 239 /* 240 * Single click on the tabline gutter, start a timer to check 241 * for double clicks 242 */ 243 timer = XtAppAddTimeOut(app_context, (long_u)p_mouset, 244 motif_tabline_timer_cb, &timed_out); 245 timed_out = FALSE; 246 } 247 return; 248 } 249 250 if (event->button != Button3) 251 return; 252 253 /* When ignoring events don't show the menu. */ 254 if (hold_gui_events 255# ifdef FEAT_CMDWIN 256 || cmdwin_type != 0 257# endif 258 ) 259 return; 260 261 if (event->subwindow != None) 262 { 263 tab_w = XtWindowToWidget(XtDisplay(w), event->subwindow); 264 /* LINTED: avoid warning: dubious operation on enum */ 265 if (tab_w != (Widget)0 && XmIsPushButton(tab_w)) 266 XtVaGetValues(tab_w, XmNpageNumber, &tab_idx, NULL); 267 } 268 269 XtVaSetValues(tabLine_menu, XmNuserData, tab_idx, NULL); 270 XtVaGetValues(tabLine_menu, XmNchildren, &children, XmNnumChildren, 271 &numChildren, NULL); 272 XtManageChildren(children, numChildren); 273 XmMenuPosition(tabLine_menu, (XButtonPressedEvent *)e) ; 274 XtManageChild(tabLine_menu); 275} 276 277 static void 278tabline_balloon_cb(beval, state) 279 BalloonEval *beval; 280 int state UNUSED; 281{ 282 int nr; 283 tabpage_T *tp; 284 285 if (beval->target == (Widget)0) 286 return; 287 288 XtVaGetValues(beval->target, XmNpageNumber, &nr, NULL); 289 tp = find_tabpage(nr); 290 if (tp == NULL) 291 return; 292 293 get_tabline_label(tp, TRUE); 294 gui_mch_post_balloon(beval, NameBuff); 295} 296 297#endif 298 299/* 300 * End of call-back routines 301 */ 302 303/* 304 * Implement three dimensional shading of insensitive labels. 305 * By Marcin Dalecki. 306 */ 307 308#include <Xm/XmP.h> 309#include <Xm/LabelP.h> 310 311static XtExposeProc old_label_expose = NULL; 312 313static void label_expose __ARGS((Widget _w, XEvent *_event, Region _region)); 314 315 static void 316label_expose(_w, _event, _region) 317 Widget _w; 318 XEvent *_event; 319 Region _region; 320{ 321 GC insensitiveGC; 322 XmLabelWidget lw = (XmLabelWidget)_w; 323 unsigned char label_type = (int)XmSTRING; 324 325 XtVaGetValues(_w, XmNlabelType, &label_type, (XtPointer)0); 326 327 if (XtIsSensitive(_w) || label_type != (int)XmSTRING) 328 (*old_label_expose)(_w, _event, _region); 329 else 330 { 331 XGCValues values; 332 XtGCMask mask; 333 XtGCMask dynamic; 334 XFontStruct *fs; 335 336 _XmFontListGetDefaultFont(lw->label.font, &fs); 337 338 /* FIXME: we should be doing the whole drawing ourself here. */ 339 insensitiveGC = lw->label.insensitive_GC; 340 341 mask = GCForeground | GCBackground | GCGraphicsExposures; 342 dynamic = GCClipMask | GCClipXOrigin | GCClipYOrigin; 343 values.graphics_exposures = False; 344 345 if (fs != 0) 346 { 347 mask |= GCFont; 348 values.font = fs->fid; 349 } 350 351 if (lw->primitive.top_shadow_pixmap != None 352 && lw->primitive.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP) 353 { 354 mask |= GCFillStyle | GCTile; 355 values.fill_style = FillTiled; 356 values.tile = lw->primitive.top_shadow_pixmap; 357 } 358 359 lw->label.TextRect.x += 1; 360 lw->label.TextRect.y += 1; 361 if (lw->label._acc_text != 0) 362 { 363 lw->label.acc_TextRect.x += 1; 364 lw->label.acc_TextRect.y += 1; 365 } 366 367 values.foreground = lw->primitive.top_shadow_color; 368 values.background = lw->core.background_pixel; 369 370 lw->label.insensitive_GC = XtAllocateGC((Widget)lw, 0, mask, 371 &values, dynamic, (XtGCMask)0); 372 (*old_label_expose)(_w, _event, _region); 373 XtReleaseGC(_w, lw->label.insensitive_GC); 374 375 lw->label.TextRect.x -= 1; 376 lw->label.TextRect.y -= 1; 377 if (lw->label._acc_text != 0) 378 { 379 lw->label.acc_TextRect.x -= 1; 380 lw->label.acc_TextRect.y -= 1; 381 } 382 383 values.foreground = lw->primitive.bottom_shadow_color; 384 values.background = lw->core.background_pixel; 385 386 lw->label.insensitive_GC = XtAllocateGC((Widget) lw, 0, mask, 387 &values, dynamic, (XtGCMask)0); 388 (*old_label_expose)(_w, _event, _region); 389 XtReleaseGC(_w, lw->label.insensitive_GC); 390 391 lw->label.insensitive_GC = insensitiveGC; 392 } 393} 394 395/* 396 * Create all the motif widgets necessary. 397 */ 398 void 399gui_x11_create_widgets() 400{ 401#ifdef FEAT_GUI_TABLINE 402 Widget button, scroller; 403 Arg args[10]; 404 int n; 405 XmString xms; 406#endif 407 408 /* 409 * Install the 3D shade effect drawing routines. 410 */ 411 if (old_label_expose == NULL) 412 { 413 old_label_expose = xmLabelWidgetClass->core_class.expose; 414 xmLabelWidgetClass->core_class.expose = label_expose; 415 } 416 417 /* 418 * Start out by adding the configured border width into the border offset 419 */ 420 gui.border_offset = gui.border_width; 421 422 /* 423 * Install the tearOffModel resource converter. 424 */ 425#if (XmVersion >= 1002) 426 XmRepTypeInstallTearOffModelConverter(); 427#endif 428 429 /* Make sure the "Quit" menu entry of the window manager is ignored */ 430 XtVaSetValues(vimShell, XmNdeleteResponse, XmDO_NOTHING, NULL); 431 432 vimForm = XtVaCreateManagedWidget("vimForm", 433 xmFormWidgetClass, vimShell, 434 XmNborderWidth, 0, 435 XmNhighlightThickness, 0, 436 XmNshadowThickness, 0, 437 XmNmarginWidth, 0, 438 XmNmarginHeight, 0, 439 XmNresizePolicy, XmRESIZE_ANY, 440 NULL); 441 gui_motif_menu_colors(vimForm); 442 443#ifdef FEAT_MENU 444 { 445 Arg al[7]; /* Make sure there is enough room for arguments! */ 446 int ac = 0; 447 448# if (XmVersion >= 1002) 449 XtSetArg(al[ac], XmNtearOffModel, tearoff_val); ac++; 450# endif 451 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; 452 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; 453 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; 454# ifndef FEAT_TOOLBAR 455 /* Always stick to right hand side. */ 456 XtSetArg(al[ac], XmNrightOffset, 0); ac++; 457# endif 458 XtSetArg(al[ac], XmNmarginHeight, 0); ac++; 459 menuBar = XmCreateMenuBar(vimForm, "menuBar", al, ac); 460 XtManageChild(menuBar); 461 462 /* Remember the default colors, needed for ":hi clear". */ 463 XtVaGetValues(menuBar, 464 XmNbackground, &gui.menu_def_bg_pixel, 465 XmNforeground, &gui.menu_def_fg_pixel, 466 NULL); 467 gui_motif_menu_colors(menuBar); 468 } 469#endif 470 471#ifdef FEAT_TOOLBAR 472 /* 473 * Create an empty ToolBar. We should get buttons defined from menu.vim. 474 */ 475 toolBarFrame = XtVaCreateWidget("toolBarFrame", 476 xmFrameWidgetClass, vimForm, 477 XmNshadowThickness, 0, 478 XmNmarginHeight, 0, 479 XmNmarginWidth, 0, 480 XmNleftAttachment, XmATTACH_FORM, 481 XmNrightAttachment, XmATTACH_FORM, 482 NULL); 483 gui_motif_menu_colors(toolBarFrame); 484 485 toolBar = XtVaCreateManagedWidget("toolBar", 486 xmRowColumnWidgetClass, toolBarFrame, 487 XmNchildType, XmFRAME_WORKAREA_CHILD, 488 XmNrowColumnType, XmWORK_AREA, 489 XmNorientation, XmHORIZONTAL, 490 XmNtraversalOn, False, 491 XmNisHomogeneous, False, 492 XmNpacking, XmPACK_TIGHT, 493 XmNspacing, 0, 494 XmNshadowThickness, 0, 495 XmNhighlightThickness, 0, 496 XmNmarginHeight, 0, 497 XmNmarginWidth, 0, 498 XmNadjustLast, True, 499 NULL); 500 gui_motif_menu_colors(toolBar); 501 502#endif 503 504#ifdef FEAT_GUI_TABLINE 505 /* Create the Vim GUI tabline */ 506 n = 0; 507 XtSetArg(args[n], XmNbindingType, XmNONE); n++; 508 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; 509 XtSetArg(args[n], XmNbackPageSize, XmNONE); n++; 510 XtSetArg(args[n], XmNbackPageNumber, 0); n++; 511 XtSetArg(args[n], XmNbackPagePlacement, XmTOP_RIGHT); n++; 512 XtSetArg(args[n], XmNmajorTabSpacing, 0); n++; 513 XtSetArg(args[n], XmNshadowThickness, 0); n++; 514 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 515 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 516 tabLine = XmCreateNotebook(vimForm, "Vim tabline", args, n); 517 518 XtAddCallback(tabLine, XmNpageChangedCallback, (XtCallbackProc)tabline_cb, 519 NULL); 520 XtAddEventHandler(tabLine, ButtonPressMask, False, 521 (XtEventHandler)tabline_menu_cb, NULL); 522 523 gui.tabline_height = TABLINE_HEIGHT; 524 525 /* 526 * Set the size of the minor next/prev scrollers to zero, so 527 * that they are not displayed. Due to a bug in OpenMotif 2.3, 528 * even if these children widget are unmanaged, they are again 529 * managed by the Notebook widget and the notebook widget geometry 530 * is adjusted to account for the minor scroller widgets. 531 */ 532 scroller = XtNameToWidget(tabLine, "MinorTabScrollerNext"); 533 XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False, 534 XmNtraversalOn, False, NULL); 535 scroller = XtNameToWidget(tabLine, "MinorTabScrollerPrevious"); 536 XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False, 537 XmNtraversalOn, False, NULL); 538 539 /* Create the tabline popup menu */ 540 tabLine_menu = XmCreatePopupMenu(tabLine, "tabline popup", NULL, 0); 541 542 /* Add the buttons to the menu */ 543 n = 0; 544 XtSetArg(args[n], XmNuserData, TABLINE_MENU_CLOSE); n++; 545 xms = XmStringCreate((char *)"Close tab", STRING_TAG); 546 XtSetArg(args[n], XmNlabelString, xms); n++; 547 button = XmCreatePushButton(tabLine_menu, "Close", args, n); 548 XtAddCallback(button, XmNactivateCallback, 549 (XtCallbackProc)tabline_button_cb, NULL); 550 XmStringFree(xms); 551 552 n = 0; 553 XtSetArg(args[n], XmNuserData, TABLINE_MENU_NEW); n++; 554 xms = XmStringCreate((char *)"New Tab", STRING_TAG); 555 XtSetArg(args[n], XmNlabelString, xms); n++; 556 button = XmCreatePushButton(tabLine_menu, "New Tab", args, n); 557 XtAddCallback(button, XmNactivateCallback, 558 (XtCallbackProc)tabline_button_cb, NULL); 559 XmStringFree(xms); 560 561 n = 0; 562 XtSetArg(args[n], XmNuserData, TABLINE_MENU_OPEN); n++; 563 xms = XmStringCreate((char *)"Open tab...", STRING_TAG); 564 XtSetArg(args[n], XmNlabelString, xms); n++; 565 button = XmCreatePushButton(tabLine_menu, "Open tab...", args, n); 566 XtAddCallback(button, XmNactivateCallback, 567 (XtCallbackProc)tabline_button_cb, NULL); 568 XmStringFree(xms); 569#endif 570 571 textAreaForm = XtVaCreateManagedWidget("textAreaForm", 572 xmFormWidgetClass, vimForm, 573 XmNleftAttachment, XmATTACH_FORM, 574 XmNrightAttachment, XmATTACH_FORM, 575 XmNbottomAttachment, XmATTACH_FORM, 576 XmNtopAttachment, XmATTACH_FORM, 577 XmNmarginWidth, 0, 578 XmNmarginHeight, 0, 579 XmNresizePolicy, XmRESIZE_ANY, 580 NULL); 581 gui_motif_scroll_colors(textAreaForm); 582 583 textArea = XtVaCreateManagedWidget("textArea", 584 xmDrawingAreaWidgetClass, textAreaForm, 585 XmNforeground, gui.norm_pixel, 586 XmNbackground, gui.back_pixel, 587 XmNleftAttachment, XmATTACH_FORM, 588 XmNtopAttachment, XmATTACH_FORM, 589 XmNrightAttachment, XmATTACH_FORM, 590 XmNbottomAttachment, XmATTACH_FORM, 591 592 /* 593 * These take some control away from the user, but avoids making them 594 * add resources to get a decent looking setup. 595 */ 596 XmNborderWidth, 0, 597 XmNhighlightThickness, 0, 598 XmNshadowThickness, 0, 599 NULL); 600 601#ifdef FEAT_FOOTER 602 /* 603 * Create the Footer. 604 */ 605 footer = XtVaCreateWidget("footer", 606 xmLabelGadgetClass, vimForm, 607 XmNalignment, XmALIGNMENT_BEGINNING, 608 XmNmarginHeight, 0, 609 XmNmarginWidth, 0, 610 XmNtraversalOn, False, 611 XmNrecomputeSize, False, 612 XmNleftAttachment, XmATTACH_FORM, 613 XmNleftOffset, 5, 614 XmNrightAttachment, XmATTACH_FORM, 615 XmNbottomAttachment, XmATTACH_FORM, 616 NULL); 617 gui_mch_set_footer((char_u *) ""); 618#endif 619 620 /* 621 * Install the callbacks. 622 */ 623 gui_x11_callbacks(textArea, vimForm); 624 625 /* Pretend we don't have input focus, we will get an event if we do. */ 626 gui.in_focus = FALSE; 627} 628 629/* 630 * Called when the GUI is not going to start after all. 631 */ 632 void 633gui_x11_destroy_widgets() 634{ 635 textArea = NULL; 636#ifdef FEAT_MENU 637 menuBar = NULL; 638#endif 639} 640 641 void 642gui_mch_set_text_area_pos(x, y, w, h) 643 int x UNUSED; 644 int y UNUSED; 645 int w UNUSED; 646 int h UNUSED; 647{ 648#ifdef FEAT_TOOLBAR 649 /* Give keyboard focus to the textArea instead of the toolbar. */ 650 reset_focus(); 651#endif 652} 653 654 void 655gui_x11_set_back_color() 656{ 657 if (textArea != NULL) 658#if (XmVersion >= 1002) 659 XmChangeColor(textArea, gui.back_pixel); 660#else 661 XtVaSetValues(textArea, 662 XmNbackground, gui.back_pixel, 663 NULL); 664#endif 665} 666 667/* 668 * Manage dialog centered on pointer. This could be used by the Athena code as 669 * well. 670 */ 671 void 672manage_centered(dialog_child) 673 Widget dialog_child; 674{ 675 Widget shell = XtParent(dialog_child); 676 Window root, child; 677 unsigned int mask; 678 unsigned int width, height, border_width, depth; 679 int x, y, win_x, win_y, maxX, maxY; 680 Boolean mappedWhenManaged; 681 682 /* Temporarily set value of XmNmappedWhenManaged 683 to stop the dialog from popping up right away */ 684 XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, NULL); 685 XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL); 686 687 XtManageChild(dialog_child); 688 689 /* Get the pointer position (x, y) */ 690 XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child, 691 &x, &y, &win_x, &win_y, &mask); 692 693 /* Translate the pointer position (x, y) into a position for the new 694 window that will place the pointer at its center */ 695 XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &win_x, &win_y, 696 &width, &height, &border_width, &depth); 697 width += 2 * border_width; 698 height += 2 * border_width; 699 x -= width / 2; 700 y -= height / 2; 701 702 /* Ensure that the dialog remains on screen */ 703 maxX = XtScreen(shell)->width - width; 704 maxY = XtScreen(shell)->height - height; 705 if (x < 0) 706 x = 0; 707 if (x > maxX) 708 x = maxX; 709 if (y < 0) 710 y = 0; 711 if (y > maxY) 712 y = maxY; 713 714 /* Set desired window position in the DialogShell */ 715 XtVaSetValues(shell, XmNx, x, XmNy, y, NULL); 716 717 /* Map the widget */ 718 XtMapWidget(shell); 719 720 /* Restore the value of XmNmappedWhenManaged */ 721 XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, NULL); 722} 723 724#if defined(FEAT_MENU) || defined(FEAT_SUN_WORKSHOP) \ 725 || defined(FEAT_GUI_DIALOG) || defined(PROTO) 726 727/* 728 * Encapsulate the way an XmFontList is created. 729 */ 730 XmFontList 731gui_motif_create_fontlist(font) 732 XFontStruct *font; 733{ 734 XmFontList font_list; 735 736# if (XmVersion <= 1001) 737 /* Motif 1.1 method */ 738 font_list = XmFontListCreate(font, STRING_TAG); 739# else 740 /* Motif 1.2 method */ 741 XmFontListEntry font_list_entry; 742 743 font_list_entry = XmFontListEntryCreate(STRING_TAG, XmFONT_IS_FONT, 744 (XtPointer)font); 745 font_list = XmFontListAppendEntry(NULL, font_list_entry); 746 XmFontListEntryFree(&font_list_entry); 747# endif 748 return font_list; 749} 750 751# if ((XmVersion > 1001) && defined(FEAT_XFONTSET)) || defined(PROTO) 752 XmFontList 753gui_motif_fontset2fontlist(fontset) 754 XFontSet *fontset; 755{ 756 XmFontList font_list; 757 758 /* Motif 1.2 method */ 759 XmFontListEntry font_list_entry; 760 761 font_list_entry = XmFontListEntryCreate(STRING_TAG, 762 XmFONT_IS_FONTSET, 763 (XtPointer)*fontset); 764 font_list = XmFontListAppendEntry(NULL, font_list_entry); 765 XmFontListEntryFree(&font_list_entry); 766 return font_list; 767} 768# endif 769 770#endif 771 772#if defined(FEAT_MENU) || defined(PROTO) 773/* 774 * Menu stuff. 775 */ 776 777static void gui_motif_add_actext __ARGS((vimmenu_T *menu)); 778#if (XmVersion >= 1002) 779static void toggle_tearoff __ARGS((Widget wid)); 780static void gui_mch_recurse_tearoffs __ARGS((vimmenu_T *menu)); 781#endif 782static void submenu_change __ARGS((vimmenu_T *mp, int colors)); 783 784static void do_set_mnemonics __ARGS((int enable)); 785static int menu_enabled = TRUE; 786 787 void 788gui_mch_enable_menu(flag) 789 int flag; 790{ 791 if (flag) 792 { 793 XtManageChild(menuBar); 794#ifdef FEAT_TOOLBAR 795 if (XtIsManaged(XtParent(toolBar))) 796 { 797 /* toolBar is attached to top form */ 798 XtVaSetValues(XtParent(toolBar), 799 XmNtopAttachment, XmATTACH_WIDGET, 800 XmNtopWidget, menuBar, 801 NULL); 802#ifdef FEAT_GUI_TABLINE 803 if (showing_tabline) 804 { 805 XtVaSetValues(tabLine, 806 XmNtopAttachment, XmATTACH_WIDGET, 807 XmNtopWidget, XtParent(toolBar), 808 NULL); 809 XtVaSetValues(textAreaForm, 810 XmNtopAttachment, XmATTACH_WIDGET, 811 XmNtopWidget, tabLine, 812 NULL); 813 } 814 else 815#endif 816 XtVaSetValues(textAreaForm, 817 XmNtopAttachment, XmATTACH_WIDGET, 818 XmNtopWidget, XtParent(toolBar), 819 NULL); 820 } 821 else 822#endif 823 { 824#ifdef FEAT_GUI_TABLINE 825 if (showing_tabline) 826 { 827 XtVaSetValues(tabLine, 828 XmNtopAttachment, XmATTACH_WIDGET, 829 XmNtopWidget, menuBar, 830 NULL); 831 XtVaSetValues(textAreaForm, 832 XmNtopAttachment, XmATTACH_WIDGET, 833 XmNtopWidget, tabLine, 834 NULL); 835 } 836 else 837#endif 838 XtVaSetValues(textAreaForm, 839 XmNtopAttachment, XmATTACH_WIDGET, 840 XmNtopWidget, menuBar, 841 NULL); 842 } 843 } 844 else 845 { 846 XtUnmanageChild(menuBar); 847#ifdef FEAT_TOOLBAR 848 if (XtIsManaged(XtParent(toolBar))) 849 { 850 XtVaSetValues(XtParent(toolBar), 851 XmNtopAttachment, XmATTACH_FORM, 852 NULL); 853#ifdef FEAT_GUI_TABLINE 854 if (showing_tabline) 855 { 856 XtVaSetValues(tabLine, 857 XmNtopAttachment, XmATTACH_WIDGET, 858 XmNtopWidget, XtParent(toolBar), 859 NULL); 860 XtVaSetValues(textAreaForm, 861 XmNtopAttachment, XmATTACH_WIDGET, 862 XmNtopWidget, tabLine, 863 NULL); 864 } 865 else 866#endif 867 XtVaSetValues(textAreaForm, 868 XmNtopAttachment, XmATTACH_WIDGET, 869 XmNtopWidget, XtParent(toolBar), 870 NULL); 871 } 872 else 873#endif 874 { 875#ifdef FEAT_GUI_TABLINE 876 if (showing_tabline) 877 { 878 XtVaSetValues(tabLine, 879 XmNtopAttachment, XmATTACH_FORM, 880 NULL); 881 XtVaSetValues(textAreaForm, 882 XmNtopAttachment, XmATTACH_WIDGET, 883 XmNtopWidget, tabLine, 884 NULL); 885 } 886 else 887#endif 888 XtVaSetValues(textAreaForm, 889 XmNtopAttachment, XmATTACH_FORM, 890 NULL); 891 } 892 } 893 894} 895 896/* 897 * Enable or disable mnemonics for the toplevel menus. 898 */ 899 void 900gui_motif_set_mnemonics(enable) 901 int enable; 902{ 903 /* 904 * Don't enable menu mnemonics when the menu bar is disabled, LessTif 905 * crashes when using a mnemonic then. 906 */ 907 if (!menu_enabled) 908 enable = FALSE; 909 do_set_mnemonics(enable); 910} 911 912 static void 913do_set_mnemonics(enable) 914 int enable; 915{ 916 vimmenu_T *menu; 917 918 for (menu = root_menu; menu != NULL; menu = menu->next) 919 if (menu->id != (Widget)0) 920 XtVaSetValues(menu->id, 921 XmNmnemonic, enable ? menu->mnemonic : NUL, 922 NULL); 923} 924 925 void 926gui_mch_add_menu(menu, idx) 927 vimmenu_T *menu; 928 int idx; 929{ 930 XmString label; 931 Widget shell; 932 vimmenu_T *parent = menu->parent; 933 934#ifdef MOTIF_POPUP 935 if (menu_is_popup(menu->name)) 936 { 937 Arg arg[2]; 938 int n = 0; 939 940 /* Only create the popup menu when it's actually used, otherwise there 941 * is a delay when using the right mouse button. */ 942# if (XmVersion <= 1002) 943 if (mouse_model_popup()) 944# endif 945 { 946 if (gui.menu_bg_pixel != INVALCOLOR) 947 { 948 XtSetArg(arg[0], XmNbackground, gui.menu_bg_pixel); n++; 949 } 950 if (gui.menu_fg_pixel != INVALCOLOR) 951 { 952 XtSetArg(arg[1], XmNforeground, gui.menu_fg_pixel); n++; 953 } 954 menu->submenu_id = XmCreatePopupMenu(textArea, "contextMenu", 955 arg, n); 956 menu->id = (Widget)0; 957 } 958 return; 959 } 960#endif 961 962 if (!menu_is_menubar(menu->name) 963 || (parent != NULL && parent->submenu_id == (Widget)0)) 964 return; 965 966 label = XmStringCreate((char *)menu->dname, STRING_TAG); 967 if (label == NULL) 968 return; 969 menu->id = XtVaCreateWidget("subMenu", 970 xmCascadeButtonWidgetClass, 971 (parent == NULL) ? menuBar : parent->submenu_id, 972 XmNlabelString, label, 973 XmNmnemonic, p_wak[0] == 'n' ? NUL : menu->mnemonic, 974#if (XmVersion >= 1002) 975 /* submenu: count the tearoff item (needed for LessTif) */ 976 XmNpositionIndex, idx + (parent != NULL 977 && tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0), 978#endif 979 NULL); 980 gui_motif_menu_colors(menu->id); 981 gui_motif_menu_fontlist(menu->id); 982 XmStringFree(label); 983 984 if (menu->id == (Widget)0) /* failed */ 985 return; 986 987 /* add accelerator text */ 988 gui_motif_add_actext(menu); 989 990 shell = XtVaCreateWidget("subMenuShell", 991 xmMenuShellWidgetClass, menu->id, 992 XmNwidth, 1, 993 XmNheight, 1, 994 NULL); 995 gui_motif_menu_colors(shell); 996 menu->submenu_id = XtVaCreateWidget("rowColumnMenu", 997 xmRowColumnWidgetClass, shell, 998 XmNrowColumnType, XmMENU_PULLDOWN, 999 NULL); 1000 gui_motif_menu_colors(menu->submenu_id); 1001 1002 if (menu->submenu_id == (Widget)0) /* failed */ 1003 return; 1004 1005#if (XmVersion >= 1002) 1006 /* Set the colors for the tear off widget */ 1007 toggle_tearoff(menu->submenu_id); 1008#endif 1009 1010 XtVaSetValues(menu->id, 1011 XmNsubMenuId, menu->submenu_id, 1012 NULL); 1013 1014 /* 1015 * The "Help" menu is a special case, and should be placed at the far 1016 * right hand side of the menu-bar. It's recognized by its high priority. 1017 */ 1018 if (parent == NULL && menu->priority >= 9999) 1019 XtVaSetValues(menuBar, 1020 XmNmenuHelpWidget, menu->id, 1021 NULL); 1022 1023 /* 1024 * When we add a top-level item to the menu bar, we can figure out how 1025 * high the menu bar should be. 1026 */ 1027 if (parent == NULL) 1028 gui_mch_compute_menu_height(menu->id); 1029} 1030 1031 1032/* 1033 * Add mnemonic and accelerator text to a menu button. 1034 */ 1035 static void 1036gui_motif_add_actext(menu) 1037 vimmenu_T *menu; 1038{ 1039 XmString label; 1040 1041 /* Add accelerator text, if there is one */ 1042 if (menu->actext != NULL && menu->id != (Widget)0) 1043 { 1044 label = XmStringCreate((char *)menu->actext, STRING_TAG); 1045 if (label == NULL) 1046 return; 1047 XtVaSetValues(menu->id, XmNacceleratorText, label, NULL); 1048 XmStringFree(label); 1049 } 1050} 1051 1052 void 1053gui_mch_toggle_tearoffs(enable) 1054 int enable; 1055{ 1056#if (XmVersion >= 1002) 1057 if (enable) 1058 tearoff_val = (int)XmTEAR_OFF_ENABLED; 1059 else 1060 tearoff_val = (int)XmTEAR_OFF_DISABLED; 1061 toggle_tearoff(menuBar); 1062 gui_mch_recurse_tearoffs(root_menu); 1063#endif 1064} 1065 1066#if (XmVersion >= 1002) 1067/* 1068 * Set the tearoff for one menu widget on or off, and set the color of the 1069 * tearoff widget. 1070 */ 1071 static void 1072toggle_tearoff(wid) 1073 Widget wid; 1074{ 1075 Widget w; 1076 1077 XtVaSetValues(wid, XmNtearOffModel, tearoff_val, NULL); 1078 if (tearoff_val == (int)XmTEAR_OFF_ENABLED 1079 && (w = XmGetTearOffControl(wid)) != (Widget)0) 1080 gui_motif_menu_colors(w); 1081} 1082 1083 static void 1084gui_mch_recurse_tearoffs(menu) 1085 vimmenu_T *menu; 1086{ 1087 while (menu != NULL) 1088 { 1089 if (!menu_is_popup(menu->name)) 1090 { 1091 if (menu->submenu_id != (Widget)0) 1092 toggle_tearoff(menu->submenu_id); 1093 gui_mch_recurse_tearoffs(menu->children); 1094 } 1095 menu = menu->next; 1096 } 1097} 1098#endif 1099 1100 int 1101gui_mch_text_area_extra_height() 1102{ 1103 Dimension shadowHeight; 1104 1105 XtVaGetValues(textAreaForm, XmNshadowThickness, &shadowHeight, NULL); 1106 return shadowHeight; 1107} 1108 1109/* 1110 * Compute the height of the menu bar. 1111 * We need to check all the items for their position and height, for the case 1112 * there are several rows, and/or some characters extend higher or lower. 1113 */ 1114 void 1115gui_mch_compute_menu_height(id) 1116 Widget id; /* can be NULL when deleting menu */ 1117{ 1118 Dimension y, maxy; 1119 Dimension margin, shadow; 1120 vimmenu_T *mp; 1121 static Dimension height = 21; /* normal height of a menu item */ 1122 1123 /* 1124 * Get the height of the new item, before managing it, because it will 1125 * still reflect the font size. After managing it depends on the menu 1126 * height, which is what we just wanted to get!. 1127 */ 1128 if (id != (Widget)0) 1129 XtVaGetValues(id, XmNheight, &height, NULL); 1130 1131 /* Find any menu Widget, to be able to call XtManageChild() */ 1132 else 1133 for (mp = root_menu; mp != NULL; mp = mp->next) 1134 if (mp->id != (Widget)0 && menu_is_menubar(mp->name)) 1135 { 1136 id = mp->id; 1137 break; 1138 } 1139 1140 /* 1141 * Now manage the menu item, to make them all be positioned (makes an 1142 * extra row when needed, removes it when not needed). 1143 */ 1144 if (id != (Widget)0) 1145 XtManageChild(id); 1146 1147 /* 1148 * Now find the menu item that is the furthest down, and get it's position. 1149 */ 1150 maxy = 0; 1151 for (mp = root_menu; mp != NULL; mp = mp->next) 1152 { 1153 if (mp->id != (Widget)0 && menu_is_menubar(mp->name)) 1154 { 1155 XtVaGetValues(mp->id, XmNy, &y, NULL); 1156 if (y > maxy) 1157 maxy = y; 1158 } 1159 } 1160 1161 XtVaGetValues(menuBar, 1162 XmNmarginHeight, &margin, 1163 XmNshadowThickness, &shadow, 1164 NULL); 1165 1166 /* 1167 * This computation is the result of trial-and-error: 1168 * maxy = The maximum position of an item; required for when there are 1169 * two or more rows 1170 * height = height of an item, before managing it; Hopefully this will 1171 * change with the font height. Includes shadow-border. 1172 * shadow = shadow-border; must be subtracted from the height. 1173 * margin = margin around the menu buttons; Must be added. 1174 * Add 4 for the underlining of shortcut keys. 1175 */ 1176 gui.menu_height = maxy + height - 2 * shadow + 2 * margin + 4; 1177 1178 /* Somehow the menu bar doesn't resize automatically. Set it here, 1179 * even though this is a catch 22. Don't do this when starting up, 1180 * somehow the menu gets very high then. */ 1181 if (gui.shell_created) 1182 XtVaSetValues(menuBar, XmNheight, gui.menu_height, NULL); 1183} 1184 1185#ifdef FEAT_TOOLBAR 1186 1187/* 1188 * Icons used by the toolbar code. 1189 */ 1190#include "gui_x11_pm.h" 1191 1192static int check_xpm __ARGS((char_u *path)); 1193static char **get_toolbar_pixmap __ARGS((vimmenu_T *menu, char **fname)); 1194static int add_pixmap_args __ARGS((vimmenu_T *menu, Arg *args, int n)); 1195 1196/* 1197 * Read an Xpm file. Return OK or FAIL. 1198 */ 1199 static int 1200check_xpm(path) 1201 char_u *path; 1202{ 1203 XpmAttributes attrs; 1204 int status; 1205 Pixmap mask; 1206 Pixmap map; 1207 1208 attrs.valuemask = 0; 1209 1210 /* Create the "sensitive" pixmap */ 1211 status = XpmReadFileToPixmap(gui.dpy, 1212 RootWindow(gui.dpy, DefaultScreen(gui.dpy)), 1213 (char *)path, &map, &mask, &attrs); 1214 XpmFreeAttributes(&attrs); 1215 1216 if (status == XpmSuccess) 1217 return OK; 1218 return FAIL; 1219} 1220 1221 1222/* 1223 * Allocated a pixmap for toolbar menu "menu". 1224 * When it's to be read from a file, "fname" is set to the file name 1225 * (in allocated memory). 1226 * Return a blank pixmap if it fails. 1227 */ 1228 static char ** 1229get_toolbar_pixmap(menu, fname) 1230 vimmenu_T *menu; 1231 char **fname; 1232{ 1233 char_u buf[MAXPATHL]; /* buffer storing expanded pathname */ 1234 char **xpm = NULL; /* xpm array */ 1235 int res; 1236 1237 *fname = NULL; 1238 buf[0] = NUL; /* start with NULL path */ 1239 1240 if (menu->iconfile != NULL) 1241 { 1242 /* Use the "icon=" argument. */ 1243 gui_find_iconfile(menu->iconfile, buf, "xpm"); 1244 res = check_xpm(buf); 1245 1246 /* If it failed, try using the menu name. */ 1247 if (res == FAIL && gui_find_bitmap(menu->name, buf, "xpm") == OK) 1248 res = check_xpm(buf); 1249 if (res == OK) 1250 { 1251 *fname = (char *)vim_strsave(buf); 1252 return tb_blank_xpm; 1253 } 1254 } 1255 1256 if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL) 1257 { 1258 if (menu->iconidx >= 0 && menu->iconidx 1259 < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0]))) 1260 xpm = built_in_pixmaps[menu->iconidx]; 1261 else 1262 xpm = tb_blank_xpm; 1263 } 1264 1265 return xpm; 1266} 1267 1268/* 1269 * Add arguments for the toolbar pixmap to a menu item. 1270 */ 1271 static int 1272add_pixmap_args(menu, args, n) 1273 vimmenu_T *menu; 1274 Arg *args; 1275 int n; 1276{ 1277 vim_free(menu->xpm_fname); 1278 menu->xpm = get_toolbar_pixmap(menu, &menu->xpm_fname); 1279 if (menu->xpm == NULL) 1280 { 1281 XtSetArg(args[n], XmNlabelType, XmSTRING); n++; 1282 } 1283 else 1284 { 1285 if (menu->xpm_fname != NULL) 1286 { 1287 XtSetArg(args[n], XmNpixmapFile, menu->xpm_fname); n++; 1288 } 1289 XtSetArg(args[n], XmNpixmapData, menu->xpm); n++; 1290 XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++; 1291 } 1292 return n; 1293} 1294#endif /* FEAT_TOOLBAR */ 1295 1296 void 1297gui_mch_add_menu_item(menu, idx) 1298 vimmenu_T *menu; 1299 int idx; 1300{ 1301 XmString label; 1302 vimmenu_T *parent = menu->parent; 1303 1304# ifdef EBCDIC 1305 menu->mnemonic = 0; 1306# endif 1307 1308# if (XmVersion <= 1002) 1309 /* Don't add Popup menu items when the popup menu isn't used. */ 1310 if (menu_is_child_of_popup(menu) && !mouse_model_popup()) 1311 return; 1312# endif 1313 1314# ifdef FEAT_TOOLBAR 1315 if (menu_is_toolbar(parent->name)) 1316 { 1317 WidgetClass type; 1318 XmString xms = NULL; /* fallback label if pixmap not found */ 1319 int n; 1320 Arg args[18]; 1321 1322 n = 0; 1323 if (menu_is_separator(menu->name)) 1324 { 1325 char *cp; 1326 Dimension wid; 1327 1328 /* 1329 * A separator has the format "-sep%d[:%d]-". The optional :%d is 1330 * a width specifier. If no width is specified then we choose one. 1331 */ 1332 cp = (char *)vim_strchr(menu->name, ':'); 1333 if (cp != NULL) 1334 wid = (Dimension)atoi(++cp); 1335 else 1336 wid = 4; 1337 1338 type = xmSeparatorWidgetClass; 1339 XtSetArg(args[n], XmNwidth, wid); n++; 1340 XtSetArg(args[n], XmNminWidth, wid); n++; 1341 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; 1342 XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++; 1343 } 1344 else 1345 { 1346 /* Without shadows one can't sense whatever the button has been 1347 * pressed or not! However we wan't to save a bit of space... 1348 * Need the highlightThickness to see the focus. 1349 */ 1350 XtSetArg(args[n], XmNhighlightThickness, 1); n++; 1351 XtSetArg(args[n], XmNhighlightOnEnter, True); n++; 1352 XtSetArg(args[n], XmNmarginWidth, 0); n++; 1353 XtSetArg(args[n], XmNmarginHeight, 0); n++; 1354 XtSetArg(args[n], XmNtraversalOn, False); n++; 1355 /* Set the label here, so that we can switch between icons/text 1356 * by changing the XmNlabelType resource. */ 1357 xms = XmStringCreate((char *)menu->dname, STRING_TAG); 1358 XtSetArg(args[n], XmNlabelString, xms); n++; 1359 1360 n = add_pixmap_args(menu, args, n); 1361 1362 type = xmEnhancedButtonWidgetClass; 1363 } 1364 1365 XtSetArg(args[n], XmNpositionIndex, idx); n++; 1366 if (menu->id == NULL) 1367 { 1368 menu->id = XtCreateManagedWidget((char *)menu->dname, 1369 type, toolBar, args, n); 1370 if (menu->id != NULL && type == xmEnhancedButtonWidgetClass) 1371 { 1372 XtAddCallback(menu->id, 1373 XmNactivateCallback, gui_x11_menu_cb, menu); 1374# ifdef FEAT_FOOTER 1375 XtAddEventHandler(menu->id, EnterWindowMask, False, 1376 toolbarbutton_enter_cb, menu); 1377 XtAddEventHandler(menu->id, LeaveWindowMask, False, 1378 toolbarbutton_leave_cb, menu); 1379# endif 1380 } 1381 } 1382 else 1383 XtSetValues(menu->id, args, n); 1384 if (xms != NULL) 1385 XmStringFree(xms); 1386 1387# ifdef FEAT_BEVAL 1388 gui_mch_menu_set_tip(menu); 1389# endif 1390 1391 menu->parent = parent; 1392 menu->submenu_id = NULL; 1393 /* When adding first item to toolbar it might have to be enabled .*/ 1394 if (!XtIsManaged(XtParent(toolBar)) 1395 && vim_strchr(p_go, GO_TOOLBAR) != NULL) 1396 gui_mch_show_toolbar(TRUE); 1397 gui.toolbar_height = gui_mch_compute_toolbar_height(); 1398 return; 1399 } /* toolbar menu item */ 1400# endif 1401 1402 /* No parent, must be a non-menubar menu */ 1403 if (parent->submenu_id == (Widget)0) 1404 return; 1405 1406 menu->submenu_id = (Widget)0; 1407 1408 /* Add menu separator */ 1409 if (menu_is_separator(menu->name)) 1410 { 1411 menu->id = XtVaCreateWidget("subMenu", 1412 xmSeparatorGadgetClass, parent->submenu_id, 1413#if (XmVersion >= 1002) 1414 /* count the tearoff item (needed for LessTif) */ 1415 XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED 1416 ? 1 : 0), 1417#endif 1418 NULL); 1419 gui_motif_menu_colors(menu->id); 1420 return; 1421 } 1422 1423 label = XmStringCreate((char *)menu->dname, STRING_TAG); 1424 if (label == NULL) 1425 return; 1426 menu->id = XtVaCreateWidget("subMenu", 1427 xmPushButtonWidgetClass, parent->submenu_id, 1428 XmNlabelString, label, 1429 XmNmnemonic, menu->mnemonic, 1430#if (XmVersion >= 1002) 1431 /* count the tearoff item (needed for LessTif) */ 1432 XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED 1433 ? 1 : 0), 1434#endif 1435 NULL); 1436 gui_motif_menu_colors(menu->id); 1437 gui_motif_menu_fontlist(menu->id); 1438 XmStringFree(label); 1439 1440 if (menu->id != (Widget)0) 1441 { 1442 XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb, 1443 (XtPointer)menu); 1444 /* add accelerator text */ 1445 gui_motif_add_actext(menu); 1446 } 1447} 1448 1449#if (XmVersion <= 1002) || defined(PROTO) 1450/* 1451 * This function will destroy/create the popup menus dynamically, 1452 * according to the value of 'mousemodel'. 1453 * This will fix the "right mouse button freeze" that occurs when 1454 * there exists a popup menu but it isn't managed. 1455 */ 1456 void 1457gui_motif_update_mousemodel(menu) 1458 vimmenu_T *menu; 1459{ 1460 int idx = 0; 1461 1462 /* When GUI hasn't started the menus have not been created. */ 1463 if (!gui.in_use) 1464 return; 1465 1466 while (menu) 1467 { 1468 if (menu->children != NULL) 1469 { 1470 if (menu_is_popup(menu->name)) 1471 { 1472 if (mouse_model_popup()) 1473 { 1474 /* Popup menu will be used. Create the popup menus. */ 1475 gui_mch_add_menu(menu, idx); 1476 gui_motif_update_mousemodel(menu->children); 1477 } 1478 else 1479 { 1480 /* Popup menu will not be used. Destroy the popup menus. */ 1481 gui_motif_update_mousemodel(menu->children); 1482 gui_mch_destroy_menu(menu); 1483 } 1484 } 1485 } 1486 else if (menu_is_child_of_popup(menu)) 1487 { 1488 if (mouse_model_popup()) 1489 gui_mch_add_menu_item(menu, idx); 1490 else 1491 gui_mch_destroy_menu(menu); 1492 } 1493 menu = menu->next; 1494 ++idx; 1495 } 1496} 1497#endif 1498 1499 void 1500gui_mch_new_menu_colors() 1501{ 1502 if (menuBar == (Widget)0) 1503 return; 1504 gui_motif_menu_colors(menuBar); 1505#ifdef FEAT_TOOLBAR 1506 gui_motif_menu_colors(toolBarFrame); 1507 gui_motif_menu_colors(toolBar); 1508#endif 1509 1510 submenu_change(root_menu, TRUE); 1511} 1512 1513 void 1514gui_mch_new_menu_font() 1515{ 1516 if (menuBar == (Widget)0) 1517 return; 1518 submenu_change(root_menu, FALSE); 1519 { 1520 Dimension height; 1521 Position w, h; 1522 1523 XtVaGetValues(menuBar, XmNheight, &height, NULL); 1524 gui.menu_height = height; 1525 1526 XtVaGetValues(vimShell, XtNwidth, &w, XtNheight, &h, NULL); 1527 gui_resize_shell(w, h 1528#ifdef FEAT_XIM 1529 - xim_get_status_area_height() 1530#endif 1531 ); 1532 } 1533 gui_set_shellsize(FALSE, TRUE, RESIZE_VERT); 1534 ui_new_shellsize(); 1535} 1536 1537#if defined(FEAT_BEVAL) || defined(PROTO) 1538 void 1539gui_mch_new_tooltip_font() 1540{ 1541# ifdef FEAT_TOOLBAR 1542 vimmenu_T *menu; 1543 1544 if (toolBar == (Widget)0) 1545 return; 1546 1547 menu = gui_find_menu((char_u *)"ToolBar"); 1548 if (menu != NULL) 1549 submenu_change(menu, FALSE); 1550# endif 1551} 1552 1553 void 1554gui_mch_new_tooltip_colors() 1555{ 1556# ifdef FEAT_TOOLBAR 1557 vimmenu_T *toolbar; 1558 1559 if (toolBar == (Widget)0) 1560 return; 1561 1562 toolbar = gui_find_menu((char_u *)"ToolBar"); 1563 if (toolbar != NULL) 1564 submenu_change(toolbar, TRUE); 1565# endif 1566} 1567#endif 1568 1569 static void 1570submenu_change(menu, colors) 1571 vimmenu_T *menu; 1572 int colors; /* TRUE for colors, FALSE for font */ 1573{ 1574 vimmenu_T *mp; 1575 1576 for (mp = menu; mp != NULL; mp = mp->next) 1577 { 1578 if (mp->id != (Widget)0) 1579 { 1580 if (colors) 1581 { 1582 gui_motif_menu_colors(mp->id); 1583#ifdef FEAT_TOOLBAR 1584 /* For a toolbar item: Free the pixmap and allocate a new one, 1585 * so that the background color is right. */ 1586 if (mp->xpm != NULL) 1587 { 1588 int n = 0; 1589 Arg args[18]; 1590 1591 n = add_pixmap_args(mp, args, n); 1592 XtSetValues(mp->id, args, n); 1593 } 1594# ifdef FEAT_BEVAL 1595 /* If we have a tooltip, then we need to change it's font */ 1596 if (mp->tip != NULL) 1597 { 1598 Arg args[2]; 1599 1600 args[0].name = XmNbackground; 1601 args[0].value = gui.tooltip_bg_pixel; 1602 args[1].name = XmNforeground; 1603 args[1].value = gui.tooltip_fg_pixel; 1604 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); 1605 } 1606# endif 1607#endif 1608 } 1609 else 1610 { 1611 gui_motif_menu_fontlist(mp->id); 1612#ifdef FEAT_BEVAL 1613 /* If we have a tooltip, then we need to change it's font */ 1614 if (mp->tip != NULL) 1615 { 1616 Arg args[1]; 1617 1618 args[0].name = XmNfontList; 1619 args[0].value = (XtArgVal)gui_motif_fontset2fontlist( 1620 &gui.tooltip_fontset); 1621 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); 1622 } 1623#endif 1624 } 1625 } 1626 1627 if (mp->children != NULL) 1628 { 1629#if (XmVersion >= 1002) 1630 /* Set the colors/font for the tear off widget */ 1631 if (mp->submenu_id != (Widget)0) 1632 { 1633 if (colors) 1634 gui_motif_menu_colors(mp->submenu_id); 1635 else 1636 gui_motif_menu_fontlist(mp->submenu_id); 1637 toggle_tearoff(mp->submenu_id); 1638 } 1639#endif 1640 /* Set the colors for the children */ 1641 submenu_change(mp->children, colors); 1642 } 1643 } 1644} 1645 1646/* 1647 * Destroy the machine specific menu widget. 1648 */ 1649 void 1650gui_mch_destroy_menu(menu) 1651 vimmenu_T *menu; 1652{ 1653 /* Please be sure to destroy the parent widget first (i.e. menu->id). 1654 * On the other hand, problems have been reported that the submenu must be 1655 * deleted first... 1656 * 1657 * This code should be basically identical to that in the file gui_athena.c 1658 * because they are both Xt based. 1659 */ 1660 if (menu->submenu_id != (Widget)0) 1661 { 1662 XtDestroyWidget(menu->submenu_id); 1663 menu->submenu_id = (Widget)0; 1664 } 1665 1666 if (menu->id != (Widget)0) 1667 { 1668 Widget parent; 1669 1670 parent = XtParent(menu->id); 1671#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL) 1672 if (parent == toolBar && menu->tip != NULL) 1673 { 1674 /* We try to destroy this before the actual menu, because there are 1675 * callbacks, etc. that will be unregistered during the tooltip 1676 * destruction. 1677 * 1678 * If you call "gui_mch_destroy_beval_area()" after destroying 1679 * menu->id, then the tooltip's window will have already been 1680 * deallocated by Xt, and unknown behaviour will ensue (probably 1681 * a core dump). 1682 */ 1683 gui_mch_destroy_beval_area(menu->tip); 1684 menu->tip = NULL; 1685 } 1686#endif 1687 XtDestroyWidget(menu->id); 1688 menu->id = (Widget)0; 1689 if (parent == menuBar) 1690 gui_mch_compute_menu_height((Widget)0); 1691#ifdef FEAT_TOOLBAR 1692 else if (parent == toolBar) 1693 { 1694 Cardinal num_children; 1695 1696 /* When removing last toolbar item, don't display the toolbar. */ 1697 XtVaGetValues(toolBar, XmNnumChildren, &num_children, NULL); 1698 if (num_children == 0) 1699 gui_mch_show_toolbar(FALSE); 1700 else 1701 gui.toolbar_height = gui_mch_compute_toolbar_height(); 1702 } 1703#endif 1704 } 1705} 1706 1707 void 1708gui_mch_show_popupmenu(menu) 1709 vimmenu_T *menu UNUSED; 1710{ 1711#ifdef MOTIF_POPUP 1712 XmMenuPosition(menu->submenu_id, gui_x11_get_last_mouse_event()); 1713 XtManageChild(menu->submenu_id); 1714#endif 1715} 1716 1717#endif /* FEAT_MENU */ 1718 1719/* 1720 * Set the menu and scrollbar colors to their default values. 1721 */ 1722 void 1723gui_mch_def_colors() 1724{ 1725 if (gui.in_use) 1726 { 1727 /* Use the values saved when starting up. These should come from the 1728 * window manager or a resources file. */ 1729 gui.menu_fg_pixel = gui.menu_def_fg_pixel; 1730 gui.menu_bg_pixel = gui.menu_def_bg_pixel; 1731 gui.scroll_fg_pixel = gui.scroll_def_fg_pixel; 1732 gui.scroll_bg_pixel = gui.scroll_def_bg_pixel; 1733#ifdef FEAT_BEVAL 1734 gui.tooltip_fg_pixel = 1735 gui_get_color((char_u *)gui.rsrc_tooltip_fg_name); 1736 gui.tooltip_bg_pixel = 1737 gui_get_color((char_u *)gui.rsrc_tooltip_bg_name); 1738#endif 1739 } 1740} 1741 1742 1743/* 1744 * Scrollbar stuff. 1745 */ 1746 1747 void 1748gui_mch_set_scrollbar_thumb(sb, val, size, max) 1749 scrollbar_T *sb; 1750 long val; 1751 long size; 1752 long max; 1753{ 1754 if (sb->id != (Widget)0) 1755 XtVaSetValues(sb->id, 1756 XmNvalue, val, 1757 XmNsliderSize, size, 1758 XmNpageIncrement, (size > 2 ? size - 2 : 1), 1759 XmNmaximum, max + 1, /* Motif has max one past the end */ 1760 NULL); 1761} 1762 1763 void 1764gui_mch_set_scrollbar_pos(sb, x, y, w, h) 1765 scrollbar_T *sb; 1766 int x; 1767 int y; 1768 int w; 1769 int h; 1770{ 1771 if (sb->id != (Widget)0) 1772 { 1773 if (sb->type == SBAR_LEFT || sb->type == SBAR_RIGHT) 1774 { 1775 if (y == 0) 1776 h -= gui.border_offset; 1777 else 1778 y -= gui.border_offset; 1779 XtVaSetValues(sb->id, 1780 XmNtopOffset, y, 1781 XmNbottomOffset, -y - h, 1782 XmNwidth, w, 1783 NULL); 1784 } 1785 else 1786 XtVaSetValues(sb->id, 1787 XmNtopOffset, y, 1788 XmNleftOffset, x, 1789 XmNrightOffset, gui.which_scrollbars[SBAR_RIGHT] 1790 ? gui.scrollbar_width : 0, 1791 XmNheight, h, 1792 NULL); 1793 XtManageChild(sb->id); 1794 } 1795} 1796 1797 void 1798gui_mch_enable_scrollbar(sb, flag) 1799 scrollbar_T *sb; 1800 int flag; 1801{ 1802 Arg args[16]; 1803 int n; 1804 1805 if (sb->id != (Widget)0) 1806 { 1807 n = 0; 1808 if (flag) 1809 { 1810 switch (sb->type) 1811 { 1812 case SBAR_LEFT: 1813 XtSetArg(args[n], XmNleftOffset, gui.scrollbar_width); n++; 1814 break; 1815 1816 case SBAR_RIGHT: 1817 XtSetArg(args[n], XmNrightOffset, gui.scrollbar_width); n++; 1818 break; 1819 1820 case SBAR_BOTTOM: 1821 XtSetArg(args[n], XmNbottomOffset, gui.scrollbar_height);n++; 1822 break; 1823 } 1824 XtSetValues(textArea, args, n); 1825 XtManageChild(sb->id); 1826 } 1827 else 1828 { 1829 if (!gui.which_scrollbars[sb->type]) 1830 { 1831 /* The scrollbars of this type are all disabled, adjust the 1832 * textArea attachment offset. */ 1833 switch (sb->type) 1834 { 1835 case SBAR_LEFT: 1836 XtSetArg(args[n], XmNleftOffset, 0); n++; 1837 break; 1838 1839 case SBAR_RIGHT: 1840 XtSetArg(args[n], XmNrightOffset, 0); n++; 1841 break; 1842 1843 case SBAR_BOTTOM: 1844 XtSetArg(args[n], XmNbottomOffset, 0);n++; 1845 break; 1846 } 1847 XtSetValues(textArea, args, n); 1848 } 1849 XtUnmanageChild(sb->id); 1850 } 1851 } 1852} 1853 1854 void 1855gui_mch_create_scrollbar(sb, orient) 1856 scrollbar_T *sb; 1857 int orient; /* SBAR_VERT or SBAR_HORIZ */ 1858{ 1859 Arg args[16]; 1860 int n; 1861 1862 n = 0; 1863 XtSetArg(args[n], XmNminimum, 0); n++; 1864 XtSetArg(args[n], XmNorientation, 1865 (orient == SBAR_VERT) ? XmVERTICAL : XmHORIZONTAL); n++; 1866 1867 switch (sb->type) 1868 { 1869 case SBAR_LEFT: 1870 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 1871 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++; 1872 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 1873 break; 1874 1875 case SBAR_RIGHT: 1876 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 1877 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++; 1878 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 1879 break; 1880 1881 case SBAR_BOTTOM: 1882 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 1883 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 1884 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; 1885 break; 1886 } 1887 1888 sb->id = XtCreateWidget("scrollBar", 1889 xmScrollBarWidgetClass, textAreaForm, args, n); 1890 1891 /* Remember the default colors, needed for ":hi clear". */ 1892 if (gui.scroll_def_bg_pixel == (guicolor_T)0 1893 && gui.scroll_def_fg_pixel == (guicolor_T)0) 1894 XtVaGetValues(sb->id, 1895 XmNbackground, &gui.scroll_def_bg_pixel, 1896 XmNforeground, &gui.scroll_def_fg_pixel, 1897 NULL); 1898 1899 if (sb->id != (Widget)0) 1900 { 1901 gui_mch_set_scrollbar_colors(sb); 1902 XtAddCallback(sb->id, XmNvalueChangedCallback, 1903 scroll_cb, (XtPointer)sb->ident); 1904 XtAddCallback(sb->id, XmNdragCallback, 1905 scroll_cb, (XtPointer)sb->ident); 1906 XtAddEventHandler(sb->id, KeyPressMask, FALSE, gui_x11_key_hit_cb, 1907 (XtPointer)0); 1908 } 1909} 1910 1911#if defined(FEAT_WINDOWS) || defined(PROTO) 1912 void 1913gui_mch_destroy_scrollbar(sb) 1914 scrollbar_T *sb; 1915{ 1916 if (sb->id != (Widget)0) 1917 XtDestroyWidget(sb->id); 1918} 1919#endif 1920 1921 void 1922gui_mch_set_scrollbar_colors(sb) 1923 scrollbar_T *sb; 1924{ 1925 if (sb->id != (Widget)0) 1926 { 1927 if (gui.scroll_bg_pixel != INVALCOLOR) 1928 { 1929#if (XmVersion>=1002) 1930 XmChangeColor(sb->id, gui.scroll_bg_pixel); 1931#else 1932 XtVaSetValues(sb->id, 1933 XmNtroughColor, gui.scroll_bg_pixel, 1934 NULL); 1935#endif 1936 } 1937 1938 if (gui.scroll_fg_pixel != INVALCOLOR) 1939 XtVaSetValues(sb->id, 1940 XmNforeground, gui.scroll_fg_pixel, 1941#if (XmVersion<1002) 1942 XmNbackground, gui.scroll_fg_pixel, 1943#endif 1944 NULL); 1945 } 1946 1947 /* This is needed for the rectangle below the vertical scrollbars. */ 1948 if (sb == &gui.bottom_sbar && textAreaForm != (Widget)0) 1949 gui_motif_scroll_colors(textAreaForm); 1950} 1951 1952/* 1953 * Miscellaneous stuff: 1954 */ 1955 1956 Window 1957gui_x11_get_wid() 1958{ 1959 return(XtWindow(textArea)); 1960} 1961 1962/* 1963 * Look for a widget in the widget tree w, with a mnemonic matching keycode. 1964 * When one is found, simulate a button press on that widget and give it the 1965 * keyboard focus. If the mnemonic is on a label, look in the userData field 1966 * of the label to see if it points to another widget, and give that the focus. 1967 */ 1968 static void 1969do_mnemonic(Widget w, unsigned int keycode) 1970{ 1971 WidgetList children; 1972 int numChildren, i; 1973 Boolean isMenu; 1974 KeySym mnemonic = '\0'; 1975 char mneString[2]; 1976 Widget userData; 1977 unsigned char rowColType; 1978 1979 if (XtIsComposite(w)) 1980 { 1981 if (XtClass(w) == xmRowColumnWidgetClass) 1982 { 1983 XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL); 1984 isMenu = (rowColType != (unsigned char)XmWORK_AREA); 1985 } 1986 else 1987 isMenu = False; 1988 if (!isMenu) 1989 { 1990 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, 1991 &numChildren, NULL); 1992 for (i = 0; i < numChildren; i++) 1993 do_mnemonic(children[i], keycode); 1994 } 1995 } 1996 else 1997 { 1998 XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL); 1999 if (mnemonic != '\0') 2000 { 2001 mneString[0] = mnemonic; 2002 mneString[1] = '\0'; 2003 if (XKeysymToKeycode(XtDisplay(XtParent(w)), 2004 XStringToKeysym(mneString)) == keycode) 2005 { 2006 if (XtClass(w) == xmLabelWidgetClass 2007 || XtClass(w) == xmLabelGadgetClass) 2008 { 2009 XtVaGetValues(w, XmNuserData, &userData, NULL); 2010 if (userData != NULL && XtIsWidget(userData)) 2011 XmProcessTraversal(userData, XmTRAVERSE_CURRENT); 2012 } 2013 else 2014 { 2015 XKeyPressedEvent keyEvent; 2016 2017 XmProcessTraversal(w, XmTRAVERSE_CURRENT); 2018 2019 vim_memset((char *) &keyEvent, 0, sizeof(XKeyPressedEvent)); 2020 keyEvent.type = KeyPress; 2021 keyEvent.serial = 1; 2022 keyEvent.send_event = True; 2023 keyEvent.display = XtDisplay(w); 2024 keyEvent.window = XtWindow(w); 2025 XtCallActionProc(w, "Activate", (XEvent *) & keyEvent, 2026 NULL, 0); 2027 } 2028 } 2029 } 2030 } 2031} 2032 2033/* 2034 * Callback routine for dialog mnemonic processing. 2035 */ 2036 static void 2037mnemonic_event(Widget w, XtPointer call_data UNUSED, XKeyEvent *event) 2038{ 2039 do_mnemonic(w, event->keycode); 2040} 2041 2042 2043/* 2044 * Search the widget tree under w for widgets with mnemonics. When found, add 2045 * a passive grab to the dialog widget for the mnemonic character, thus 2046 * directing mnemonic events to the dialog widget. 2047 */ 2048 static void 2049add_mnemonic_grabs(Widget dialog, Widget w) 2050{ 2051 char mneString[2]; 2052 WidgetList children; 2053 int numChildren, i; 2054 Boolean isMenu; 2055 KeySym mnemonic = '\0'; 2056 unsigned char rowColType; 2057 2058 if (XtIsComposite(w)) 2059 { 2060 if (XtClass(w) == xmRowColumnWidgetClass) 2061 { 2062 XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL); 2063 isMenu = (rowColType != (unsigned char)XmWORK_AREA); 2064 } 2065 else 2066 isMenu = False; 2067 if (!isMenu) 2068 { 2069 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, 2070 &numChildren, NULL); 2071 for (i = 0; i < numChildren; i++) 2072 add_mnemonic_grabs(dialog, children[i]); 2073 } 2074 } 2075 else 2076 { 2077 XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL); 2078 if (mnemonic != '\0') 2079 { 2080 mneString[0] = mnemonic; 2081 mneString[1] = '\0'; 2082 XtGrabKey(dialog, XKeysymToKeycode(XtDisplay(dialog), 2083 XStringToKeysym(mneString)), 2084 Mod1Mask, True, GrabModeAsync, GrabModeAsync); 2085 } 2086 } 2087} 2088 2089/* 2090 * Add a handler for mnemonics in a dialog. Motif itself only handles 2091 * mnemonics in menus. Mnemonics added or changed after this call will be 2092 * ignored. 2093 * 2094 * To add a mnemonic to a text field or list, set the XmNmnemonic resource on 2095 * the appropriate label and set the XmNuserData resource of the label to the 2096 * widget to get the focus when the mnemonic is typed. 2097 */ 2098 static void 2099activate_dialog_mnemonics(Widget dialog) 2100{ 2101 if (!dialog) 2102 return; 2103 2104 XtAddEventHandler(dialog, KeyPressMask, False, 2105 (XtEventHandler) mnemonic_event, (XtPointer) NULL); 2106 add_mnemonic_grabs(dialog, dialog); 2107} 2108 2109/* 2110 * Removes the event handler and key-grabs for dialog mnemonic handling. 2111 */ 2112 static void 2113suppress_dialog_mnemonics(Widget dialog) 2114{ 2115 if (!dialog) 2116 return; 2117 2118 XtUngrabKey(dialog, AnyKey, Mod1Mask); 2119 XtRemoveEventHandler(dialog, KeyPressMask, False, 2120 (XtEventHandler) mnemonic_event, (XtPointer) NULL); 2121} 2122 2123#if defined(FEAT_BROWSE) || defined(FEAT_GUI_DIALOG) 2124static void set_fontlist __ARGS((Widget wg)); 2125 2126/* 2127 * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget. 2128 */ 2129 static void 2130set_fontlist(id) 2131 Widget id; 2132{ 2133 XmFontList fl; 2134 2135#ifdef FONTSET_ALWAYS 2136 if (gui.fontset != NOFONTSET) 2137 { 2138 fl = gui_motif_fontset2fontlist((XFontSet *)&gui.fontset); 2139 if (fl != NULL) 2140 { 2141 if (XtIsManaged(id)) 2142 { 2143 XtUnmanageChild(id); 2144 XtVaSetValues(id, XmNfontList, fl, NULL); 2145 /* We should force the widget to recalculate it's 2146 * geometry now. */ 2147 XtManageChild(id); 2148 } 2149 else 2150 XtVaSetValues(id, XmNfontList, fl, NULL); 2151 XmFontListFree(fl); 2152 } 2153 } 2154#else 2155 if (gui.norm_font != NOFONT) 2156 { 2157 fl = gui_motif_create_fontlist((XFontStruct *)gui.norm_font); 2158 if (fl != NULL) 2159 { 2160 if (XtIsManaged(id)) 2161 { 2162 XtUnmanageChild(id); 2163 XtVaSetValues(id, XmNfontList, fl, NULL); 2164 /* We should force the widget to recalculate it's 2165 * geometry now. */ 2166 XtManageChild(id); 2167 } 2168 else 2169 XtVaSetValues(id, XmNfontList, fl, NULL); 2170 XmFontListFree(fl); 2171 } 2172 } 2173#endif 2174} 2175#endif 2176 2177#if defined(FEAT_BROWSE) || defined(PROTO) 2178 2179/* 2180 * file selector related stuff 2181 */ 2182 2183#include <Xm/FileSB.h> 2184#include <Xm/XmStrDefs.h> 2185 2186typedef struct dialog_callback_arg 2187{ 2188 char * args; /* not used right now */ 2189 int id; 2190} dcbarg_T; 2191 2192static Widget dialog_wgt; 2193static char *browse_fname = NULL; 2194static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET; 2195 /* used to set up XmStrings */ 2196 2197static void DialogCancelCB __ARGS((Widget, XtPointer, XtPointer)); 2198static void DialogAcceptCB __ARGS((Widget, XtPointer, XtPointer)); 2199 2200/* 2201 * This function is used to translate the predefined label text of the 2202 * precomposed dialogs. We do this explicitly to allow: 2203 * 2204 * - usage of gettext for translation, as in all the other places. 2205 * 2206 * - equalize the messages between different GUI implementations as far as 2207 * possible. 2208 */ 2209static void set_predefined_label __ARGS((Widget parent, String name, char *new_label)); 2210 2211static void 2212set_predefined_label(parent, name, new_label) 2213 Widget parent; 2214 String name; 2215 char *new_label; 2216{ 2217 XmString str; 2218 Widget w; 2219 char_u *p, *next; 2220 KeySym mnemonic = NUL; 2221 2222 w = XtNameToWidget(parent, name); 2223 2224 if (!w) 2225 return; 2226 2227 p = vim_strsave((char_u *)new_label); 2228 if (p == NULL) 2229 return; 2230 for (next = p; *next; ++next) 2231 { 2232 if (*next == DLG_HOTKEY_CHAR) 2233 { 2234 int len = STRLEN(next); 2235 2236 if (len > 0) 2237 { 2238 mch_memmove(next, next + 1, len); 2239 mnemonic = next[0]; 2240 } 2241 } 2242 } 2243 2244 str = XmStringCreate((char *)p, STRING_TAG); 2245 vim_free(p); 2246 2247 if (str != NULL) 2248 { 2249 XtVaSetValues(w, 2250 XmNlabelString, str, 2251 XmNmnemonic, mnemonic, 2252 NULL); 2253 XmStringFree(str); 2254 } 2255 gui_motif_menu_fontlist(w); 2256} 2257 2258static void 2259set_predefined_fontlist(parent, name) 2260 Widget parent; 2261 String name; 2262{ 2263 Widget w; 2264 w = XtNameToWidget(parent, name); 2265 2266 if (!w) 2267 return; 2268 2269 set_fontlist(w); 2270} 2271 2272/* 2273 * Put up a file requester. 2274 * Returns the selected name in allocated memory, or NULL for Cancel. 2275 */ 2276 char_u * 2277gui_mch_browse(saving, title, dflt, ext, initdir, filter) 2278 int saving UNUSED; /* select file to write */ 2279 char_u *title; /* title for the window */ 2280 char_u *dflt; /* default name */ 2281 char_u *ext UNUSED; /* not used (extension added) */ 2282 char_u *initdir; /* initial directory, NULL for current dir */ 2283 char_u *filter; /* file name filter */ 2284{ 2285 char_u dirbuf[MAXPATHL]; 2286 char_u dfltbuf[MAXPATHL]; 2287 char_u *pattern; 2288 char_u *tofree = NULL; 2289 2290 /* There a difference between the resource name and value, Therefore, we 2291 * avoid to (ab-)use the (maybe internationalized!) dialog title as a 2292 * dialog name. 2293 */ 2294 2295 dialog_wgt = XmCreateFileSelectionDialog(vimShell, "browseDialog", NULL, 0); 2296 2297 if (initdir == NULL || *initdir == NUL) 2298 { 2299 mch_dirname(dirbuf, MAXPATHL); 2300 initdir = dirbuf; 2301 } 2302 2303 if (dflt == NULL) 2304 dflt = (char_u *)""; 2305 else if (STRLEN(initdir) + STRLEN(dflt) + 2 < MAXPATHL) 2306 { 2307 /* The default selection should be the full path, "dflt" is only the 2308 * file name. */ 2309 STRCPY(dfltbuf, initdir); 2310 add_pathsep(dfltbuf); 2311 STRCAT(dfltbuf, dflt); 2312 dflt = dfltbuf; 2313 } 2314 2315 /* Can only use one pattern for a file name. Get the first pattern out of 2316 * the filter. An empty pattern means everything matches. */ 2317 if (filter == NULL) 2318 pattern = (char_u *)""; 2319 else 2320 { 2321 char_u *s, *p; 2322 2323 s = filter; 2324 for (p = filter; *p != NUL; ++p) 2325 { 2326 if (*p == '\t') /* end of description, start of pattern */ 2327 s = p + 1; 2328 if (*p == ';' || *p == '\n') /* end of (first) pattern */ 2329 break; 2330 } 2331 pattern = vim_strnsave(s, p - s); 2332 tofree = pattern; 2333 if (pattern == NULL) 2334 pattern = (char_u *)""; 2335 } 2336 2337 XtVaSetValues(dialog_wgt, 2338 XtVaTypedArg, 2339 XmNdirectory, XmRString, (char *)initdir, STRLEN(initdir) + 1, 2340 XtVaTypedArg, 2341 XmNdirSpec, XmRString, (char *)dflt, STRLEN(dflt) + 1, 2342 XtVaTypedArg, 2343 XmNpattern, XmRString, (char *)pattern, STRLEN(pattern) + 1, 2344 XtVaTypedArg, 2345 XmNdialogTitle, XmRString, (char *)title, STRLEN(title) + 1, 2346 NULL); 2347 2348 set_predefined_label(dialog_wgt, "Apply", _("&Filter")); 2349 set_predefined_label(dialog_wgt, "Cancel", _("&Cancel")); 2350 set_predefined_label(dialog_wgt, "Dir", _("Directories")); 2351 set_predefined_label(dialog_wgt, "FilterLabel", _("Filter")); 2352 set_predefined_label(dialog_wgt, "Help", _("&Help")); 2353 set_predefined_label(dialog_wgt, "Items", _("Files")); 2354 set_predefined_label(dialog_wgt, "OK", _("&OK")); 2355 set_predefined_label(dialog_wgt, "Selection", _("Selection")); 2356 2357 /* This is to save us from silly external settings using not fixed with 2358 * fonts for file selection. 2359 */ 2360 set_predefined_fontlist(dialog_wgt, "DirListSW.DirList"); 2361 set_predefined_fontlist(dialog_wgt, "ItemsListSW.ItemsList"); 2362 2363 gui_motif_menu_colors(dialog_wgt); 2364 if (gui.scroll_bg_pixel != INVALCOLOR) 2365 XtVaSetValues(dialog_wgt, XmNtroughColor, gui.scroll_bg_pixel, NULL); 2366 2367 XtAddCallback(dialog_wgt, XmNokCallback, DialogAcceptCB, (XtPointer)0); 2368 XtAddCallback(dialog_wgt, XmNcancelCallback, DialogCancelCB, (XtPointer)0); 2369 /* We have no help in this window, so hide help button */ 2370 XtUnmanageChild(XmFileSelectionBoxGetChild(dialog_wgt, 2371 (unsigned char)XmDIALOG_HELP_BUTTON)); 2372 2373 manage_centered(dialog_wgt); 2374 activate_dialog_mnemonics(dialog_wgt); 2375 2376 /* sit in a loop until the dialog box has gone away */ 2377 do 2378 { 2379 XtAppProcessEvent(XtWidgetToApplicationContext(dialog_wgt), 2380 (XtInputMask)XtIMAll); 2381 } while (XtIsManaged(dialog_wgt)); 2382 2383 suppress_dialog_mnemonics(dialog_wgt); 2384 XtDestroyWidget(dialog_wgt); 2385 vim_free(tofree); 2386 2387 if (browse_fname == NULL) 2388 return NULL; 2389 return vim_strsave((char_u *)browse_fname); 2390} 2391 2392/* 2393 * The code below was originally taken from 2394 * /usr/examples/motif/xmsamplers/xmeditor.c 2395 * on Digital Unix 4.0d, but heavily modified. 2396 */ 2397 2398/* 2399 * Process callback from Dialog cancel actions. 2400 */ 2401 static void 2402DialogCancelCB(w, client_data, call_data) 2403 Widget w UNUSED; /* widget id */ 2404 XtPointer client_data UNUSED; /* data from application */ 2405 XtPointer call_data UNUSED; /* data from widget class */ 2406{ 2407 if (browse_fname != NULL) 2408 { 2409 XtFree(browse_fname); 2410 browse_fname = NULL; 2411 } 2412 XtUnmanageChild(dialog_wgt); 2413} 2414 2415/* 2416 * Process callback from Dialog actions. 2417 */ 2418 static void 2419DialogAcceptCB(w, client_data, call_data) 2420 Widget w UNUSED; /* widget id */ 2421 XtPointer client_data UNUSED; /* data from application */ 2422 XtPointer call_data; /* data from widget class */ 2423{ 2424 XmFileSelectionBoxCallbackStruct *fcb; 2425 2426 if (browse_fname != NULL) 2427 { 2428 XtFree(browse_fname); 2429 browse_fname = NULL; 2430 } 2431 fcb = (XmFileSelectionBoxCallbackStruct *)call_data; 2432 2433 /* get the filename from the file selection box */ 2434 XmStringGetLtoR(fcb->value, charset, &browse_fname); 2435 2436 /* popdown the file selection box */ 2437 XtUnmanageChild(dialog_wgt); 2438} 2439 2440#endif /* FEAT_BROWSE */ 2441 2442#if defined(FEAT_GUI_DIALOG) || defined(PROTO) 2443 2444static int dialogStatus; 2445 2446static void keyhit_callback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont)); 2447static void butproc __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 2448 2449/* 2450 * Callback function for the textfield. When CR is hit this works like 2451 * hitting the "OK" button, ESC like "Cancel". 2452 */ 2453 static void 2454keyhit_callback(w, client_data, event, cont) 2455 Widget w; 2456 XtPointer client_data UNUSED; 2457 XEvent *event; 2458 Boolean *cont UNUSED; 2459{ 2460 char buf[2]; 2461 KeySym key_sym; 2462 2463 if (XLookupString(&(event->xkey), buf, 2, &key_sym, NULL) == 1) 2464 { 2465 if (*buf == CAR) 2466 dialogStatus = 1; 2467 else if (*buf == ESC) 2468 dialogStatus = 2; 2469 } 2470 if ((key_sym == XK_Left || key_sym == XK_Right) 2471 && !(event->xkey.state & ShiftMask)) 2472 XmTextFieldClearSelection(w, XtLastTimestampProcessed(gui.dpy)); 2473} 2474 2475 static void 2476butproc(w, client_data, call_data) 2477 Widget w UNUSED; 2478 XtPointer client_data; 2479 XtPointer call_data UNUSED; 2480{ 2481 dialogStatus = (int)(long)client_data + 1; 2482} 2483 2484#ifdef HAVE_XPM 2485 2486static Widget create_pixmap_label(Widget parent, String name, char **data, ArgList args, Cardinal arg); 2487 2488 static Widget 2489create_pixmap_label(parent, name, data, args, arg) 2490 Widget parent; 2491 String name; 2492 char **data; 2493 ArgList args; 2494 Cardinal arg; 2495{ 2496 Widget label; 2497 Display *dsp; 2498 Screen *scr; 2499 int depth; 2500 Pixmap pixmap = 0; 2501 XpmAttributes attr; 2502 Boolean rs; 2503 XpmColorSymbol color[5] = 2504 { 2505 {"none", NULL, 0}, 2506 {"iconColor1", NULL, 0}, 2507 {"bottomShadowColor", NULL, 0}, 2508 {"topShadowColor", NULL, 0}, 2509 {"selectColor", NULL, 0} 2510 }; 2511 2512 label = XmCreateLabelGadget(parent, name, args, arg); 2513 2514 /* 2515 * We need to be careful here, since in case of gadgets, there is 2516 * no way to get the background color directly from the widget itself. 2517 * In such cases we get it from The Core part of his parent instead. 2518 */ 2519 dsp = XtDisplayOfObject(label); 2520 scr = XtScreenOfObject(label); 2521 XtVaGetValues(XtIsSubclass(label, coreWidgetClass) 2522 ? label : XtParent(label), 2523 XmNdepth, &depth, 2524 XmNbackground, &color[0].pixel, 2525 XmNforeground, &color[1].pixel, 2526 XmNbottomShadowColor, &color[2].pixel, 2527 XmNtopShadowColor, &color[3].pixel, 2528 XmNhighlight, &color[4].pixel, 2529 NULL); 2530 2531 attr.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth; 2532 attr.colorsymbols = color; 2533 attr.numsymbols = 5; 2534 attr.closeness = 65535; 2535 attr.depth = depth; 2536 XpmCreatePixmapFromData(dsp, RootWindowOfScreen(scr), 2537 data, &pixmap, NULL, &attr); 2538 2539 XtVaGetValues(label, XmNrecomputeSize, &rs, NULL); 2540 XtVaSetValues(label, XmNrecomputeSize, True, NULL); 2541 XtVaSetValues(label, 2542 XmNlabelType, XmPIXMAP, 2543 XmNlabelPixmap, pixmap, 2544 NULL); 2545 XtVaSetValues(label, XmNrecomputeSize, rs, NULL); 2546 2547 return label; 2548} 2549#endif 2550 2551 int 2552gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) 2553 int type UNUSED; 2554 char_u *title; 2555 char_u *message; 2556 char_u *button_names; 2557 int dfltbutton; 2558 char_u *textfield; /* buffer of size IOSIZE */ 2559{ 2560 char_u *buts; 2561 char_u *p, *next; 2562 XtAppContext app; 2563 XmString label; 2564 int butcount; 2565 Widget w; 2566 Widget dialogform = NULL; 2567 Widget form = NULL; 2568 Widget dialogtextfield = NULL; 2569 Widget *buttons; 2570 Widget sep_form = NULL; 2571 Boolean vertical; 2572 Widget separator = NULL; 2573 int n; 2574 Arg args[6]; 2575#ifdef HAVE_XPM 2576 char **icon_data = NULL; 2577 Widget dialogpixmap = NULL; 2578#endif 2579 2580 if (title == NULL) 2581 title = (char_u *)_("Vim dialog"); 2582 2583 /* if our pointer is currently hidden, then we should show it. */ 2584 gui_mch_mousehide(FALSE); 2585 2586 dialogform = XmCreateFormDialog(vimShell, (char *)"dialog", NULL, 0); 2587 2588 /* Check 'v' flag in 'guioptions': vertical button placement. */ 2589 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); 2590 2591 /* Set the title of the Dialog window */ 2592 label = XmStringCreateSimple((char *)title); 2593 if (label == NULL) 2594 return -1; 2595 XtVaSetValues(dialogform, 2596 XmNdialogTitle, label, 2597 XmNhorizontalSpacing, 4, 2598 XmNverticalSpacing, vertical ? 0 : 4, 2599 NULL); 2600 XmStringFree(label); 2601 2602 /* make a copy, so that we can insert NULs */ 2603 buts = vim_strsave(button_names); 2604 if (buts == NULL) 2605 return -1; 2606 2607 /* Count the number of buttons and allocate buttons[]. */ 2608 butcount = 1; 2609 for (p = buts; *p; ++p) 2610 if (*p == DLG_BUTTON_SEP) 2611 ++butcount; 2612 buttons = (Widget *)alloc((unsigned)(butcount * sizeof(Widget))); 2613 if (buttons == NULL) 2614 { 2615 vim_free(buts); 2616 return -1; 2617 } 2618 2619 /* 2620 * Create the buttons. 2621 */ 2622 sep_form = (Widget) 0; 2623 p = buts; 2624 for (butcount = 0; *p; ++butcount) 2625 { 2626 KeySym mnemonic = NUL; 2627 2628 for (next = p; *next; ++next) 2629 { 2630 if (*next == DLG_HOTKEY_CHAR) 2631 { 2632 int len = STRLEN(next); 2633 2634 if (len > 0) 2635 { 2636 mch_memmove(next, next + 1, len); 2637 mnemonic = next[0]; 2638 } 2639 } 2640 if (*next == DLG_BUTTON_SEP) 2641 { 2642 *next++ = NUL; 2643 break; 2644 } 2645 } 2646 label = XmStringCreate(_((char *)p), STRING_TAG); 2647 if (label == NULL) 2648 break; 2649 2650 buttons[butcount] = XtVaCreateManagedWidget("button", 2651 xmPushButtonWidgetClass, dialogform, 2652 XmNlabelString, label, 2653 XmNmnemonic, mnemonic, 2654 XmNbottomAttachment, XmATTACH_FORM, 2655 XmNbottomOffset, 4, 2656 XmNshowAsDefault, butcount == dfltbutton - 1, 2657 XmNdefaultButtonShadowThickness, 1, 2658 NULL); 2659 XmStringFree(label); 2660 gui_motif_menu_fontlist(buttons[butcount]); 2661 2662 /* Layout properly. */ 2663 2664 if (butcount > 0) 2665 { 2666 if (vertical) 2667 XtVaSetValues(buttons[butcount], 2668 XmNtopWidget, buttons[butcount - 1], 2669 NULL); 2670 else 2671 { 2672 if (*next == NUL) 2673 { 2674 XtVaSetValues(buttons[butcount], 2675 XmNrightAttachment, XmATTACH_FORM, 2676 XmNrightOffset, 4, 2677 NULL); 2678 2679 /* fill in a form as invisible separator */ 2680 sep_form = XtVaCreateWidget("separatorForm", 2681 xmFormWidgetClass, dialogform, 2682 XmNleftAttachment, XmATTACH_WIDGET, 2683 XmNleftWidget, buttons[butcount - 1], 2684 XmNrightAttachment, XmATTACH_WIDGET, 2685 XmNrightWidget, buttons[butcount], 2686 XmNbottomAttachment, XmATTACH_FORM, 2687 XmNbottomOffset, 4, 2688 NULL); 2689 XtManageChild(sep_form); 2690 } 2691 else 2692 { 2693 XtVaSetValues(buttons[butcount], 2694 XmNleftAttachment, XmATTACH_WIDGET, 2695 XmNleftWidget, buttons[butcount - 1], 2696 NULL); 2697 } 2698 } 2699 } 2700 else if (!vertical) 2701 { 2702 if (*next == NUL) 2703 { 2704 XtVaSetValues(buttons[0], 2705 XmNrightAttachment, XmATTACH_FORM, 2706 XmNrightOffset, 4, 2707 NULL); 2708 2709 /* fill in a form as invisible separator */ 2710 sep_form = XtVaCreateWidget("separatorForm", 2711 xmFormWidgetClass, dialogform, 2712 XmNleftAttachment, XmATTACH_FORM, 2713 XmNleftOffset, 4, 2714 XmNrightAttachment, XmATTACH_WIDGET, 2715 XmNrightWidget, buttons[0], 2716 XmNbottomAttachment, XmATTACH_FORM, 2717 XmNbottomOffset, 4, 2718 NULL); 2719 XtManageChild(sep_form); 2720 } 2721 else 2722 XtVaSetValues(buttons[0], 2723 XmNleftAttachment, XmATTACH_FORM, 2724 XmNleftOffset, 4, 2725 NULL); 2726 } 2727 2728 XtAddCallback(buttons[butcount], XmNactivateCallback, 2729 (XtCallbackProc)butproc, (XtPointer)(long)butcount); 2730 p = next; 2731 } 2732 vim_free(buts); 2733 2734 separator = (Widget) 0; 2735 if (butcount > 0) 2736 { 2737 /* Create the separator for beauty. */ 2738 n = 0; 2739 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; 2740 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; 2741 XtSetArg(args[n], XmNbottomWidget, buttons[0]); n++; 2742 XtSetArg(args[n], XmNbottomOffset, 4); n++; 2743 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 2744 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 2745 separator = XmCreateSeparatorGadget(dialogform, "separator", args, n); 2746 XtManageChild(separator); 2747 } 2748 2749 if (textfield != NULL) 2750 { 2751 dialogtextfield = XtVaCreateWidget("textField", 2752 xmTextFieldWidgetClass, dialogform, 2753 XmNleftAttachment, XmATTACH_FORM, 2754 XmNrightAttachment, XmATTACH_FORM, 2755 NULL); 2756 if (butcount > 0) 2757 XtVaSetValues(dialogtextfield, 2758 XmNbottomAttachment, XmATTACH_WIDGET, 2759 XmNbottomWidget, separator, 2760 NULL); 2761 else 2762 XtVaSetValues(dialogtextfield, 2763 XmNbottomAttachment, XmATTACH_FORM, 2764 NULL); 2765 2766 set_fontlist(dialogtextfield); 2767 XmTextFieldSetString(dialogtextfield, (char *)textfield); 2768 XtManageChild(dialogtextfield); 2769 XtAddEventHandler(dialogtextfield, KeyPressMask, False, 2770 (XtEventHandler)keyhit_callback, (XtPointer)NULL); 2771 } 2772 2773 /* Form holding both message and pixmap labels */ 2774 form = XtVaCreateWidget("separatorForm", 2775 xmFormWidgetClass, dialogform, 2776 XmNleftAttachment, XmATTACH_FORM, 2777 XmNrightAttachment, XmATTACH_FORM, 2778 XmNtopAttachment, XmATTACH_FORM, 2779 NULL); 2780 XtManageChild(form); 2781 2782#ifdef HAVE_XPM 2783 /* Add a pixmap, left of the message. */ 2784 switch (type) 2785 { 2786 case VIM_GENERIC: 2787 icon_data = generic_xpm; 2788 break; 2789 case VIM_ERROR: 2790 icon_data = error_xpm; 2791 break; 2792 case VIM_WARNING: 2793 icon_data = alert_xpm; 2794 break; 2795 case VIM_INFO: 2796 icon_data = info_xpm; 2797 break; 2798 case VIM_QUESTION: 2799 icon_data = quest_xpm; 2800 break; 2801 default: 2802 icon_data = generic_xpm; 2803 } 2804 2805 n = 0; 2806 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 2807 XtSetArg(args[n], XmNtopOffset, 8); n++; 2808 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; 2809 XtSetArg(args[n], XmNbottomOffset, 8); n++; 2810 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 2811 XtSetArg(args[n], XmNleftOffset, 8); n++; 2812 2813 dialogpixmap = create_pixmap_label(form, "dialogPixmap", 2814 icon_data, args, n); 2815 XtManageChild(dialogpixmap); 2816#endif 2817 2818 /* Create the dialog message. 2819 * Since LessTif is apparently having problems with the creation of 2820 * properly localized string, we use LtoR here. The symptom is that the 2821 * string sill not show properly in multiple lines as it does in native 2822 * Motif. 2823 */ 2824 label = XmStringCreateLtoR((char *)message, STRING_TAG); 2825 if (label == NULL) 2826 return -1; 2827 w = XtVaCreateManagedWidget("dialogMessage", 2828 xmLabelGadgetClass, form, 2829 XmNlabelString, label, 2830 XmNalignment, XmALIGNMENT_BEGINNING, 2831 XmNtopAttachment, XmATTACH_FORM, 2832 XmNtopOffset, 8, 2833#ifdef HAVE_XPM 2834 XmNleftAttachment, XmATTACH_WIDGET, 2835 XmNleftWidget, dialogpixmap, 2836#else 2837 XmNleftAttachment, XmATTACH_FORM, 2838#endif 2839 XmNleftOffset, 8, 2840 XmNrightAttachment, XmATTACH_FORM, 2841 XmNrightOffset, 8, 2842 XmNbottomAttachment, XmATTACH_FORM, 2843 XmNbottomOffset, 8, 2844 NULL); 2845 XmStringFree(label); 2846 set_fontlist(w); 2847 2848 if (textfield != NULL) 2849 { 2850 XtVaSetValues(form, 2851 XmNbottomAttachment, XmATTACH_WIDGET, 2852 XmNbottomWidget, dialogtextfield, 2853 NULL); 2854 } 2855 else 2856 { 2857 if (butcount > 0) 2858 XtVaSetValues(form, 2859 XmNbottomAttachment, XmATTACH_WIDGET, 2860 XmNbottomWidget, separator, 2861 NULL); 2862 else 2863 XtVaSetValues(form, 2864 XmNbottomAttachment, XmATTACH_FORM, 2865 NULL); 2866 } 2867 2868 if (dfltbutton < 1) 2869 dfltbutton = 1; 2870 if (dfltbutton > butcount) 2871 dfltbutton = butcount; 2872 XtVaSetValues(dialogform, 2873 XmNdefaultButton, buttons[dfltbutton - 1], NULL); 2874 if (textfield != NULL) 2875 XtVaSetValues(dialogform, XmNinitialFocus, dialogtextfield, NULL); 2876 else 2877 XtVaSetValues(dialogform, XmNinitialFocus, buttons[dfltbutton - 1], 2878 NULL); 2879 2880 manage_centered(dialogform); 2881 activate_dialog_mnemonics(dialogform); 2882 2883 if (textfield != NULL && *textfield != NUL) 2884 { 2885 /* This only works after the textfield has been realised. */ 2886 XmTextFieldSetSelection(dialogtextfield, 2887 (XmTextPosition)0, (XmTextPosition)STRLEN(textfield), 2888 XtLastTimestampProcessed(gui.dpy)); 2889 XmTextFieldSetCursorPosition(dialogtextfield, 2890 (XmTextPosition)STRLEN(textfield)); 2891 } 2892 2893 app = XtWidgetToApplicationContext(dialogform); 2894 2895 /* Loop until a button is pressed or the dialog is killed somehow. */ 2896 dialogStatus = -1; 2897 for (;;) 2898 { 2899 XtAppProcessEvent(app, (XtInputMask)XtIMAll); 2900 if (dialogStatus >= 0 || !XtIsManaged(dialogform)) 2901 break; 2902 } 2903 2904 vim_free(buttons); 2905 2906 if (textfield != NULL) 2907 { 2908 p = (char_u *)XmTextGetString(dialogtextfield); 2909 if (p == NULL || dialogStatus < 0) 2910 *textfield = NUL; 2911 else 2912 vim_strncpy(textfield, p, IOSIZE - 1); 2913 XtFree((char *)p); 2914 } 2915 2916 suppress_dialog_mnemonics(dialogform); 2917 XtDestroyWidget(dialogform); 2918 2919 return dialogStatus; 2920} 2921#endif /* FEAT_GUI_DIALOG */ 2922 2923#if defined(FEAT_FOOTER) || defined(PROTO) 2924 2925 static int 2926gui_mch_compute_footer_height() 2927{ 2928 Dimension height; /* total Toolbar height */ 2929 Dimension top; /* XmNmarginTop */ 2930 Dimension bottom; /* XmNmarginBottom */ 2931 Dimension shadow; /* XmNshadowThickness */ 2932 2933 XtVaGetValues(footer, 2934 XmNheight, &height, 2935 XmNmarginTop, &top, 2936 XmNmarginBottom, &bottom, 2937 XmNshadowThickness, &shadow, 2938 NULL); 2939 2940 return (int) height + top + bottom + (shadow << 1); 2941} 2942 2943 void 2944gui_mch_enable_footer(showit) 2945 int showit; 2946{ 2947 if (showit) 2948 { 2949 gui.footer_height = gui_mch_compute_footer_height(); 2950 XtManageChild(footer); 2951 } 2952 else 2953 { 2954 gui.footer_height = 0; 2955 XtUnmanageChild(footer); 2956 } 2957 XtVaSetValues(textAreaForm, XmNbottomOffset, gui.footer_height, NULL); 2958} 2959 2960 void 2961gui_mch_set_footer(s) 2962 char_u *s; 2963{ 2964 XmString xms; 2965 2966 xms = XmStringCreate((char *)s, STRING_TAG); 2967 if (xms != NULL) 2968 { 2969 XtVaSetValues(footer, XmNlabelString, xms, NULL); 2970 XmStringFree(xms); 2971 } 2972} 2973 2974#endif 2975 2976 2977#if defined(FEAT_TOOLBAR) || defined(PROTO) 2978 void 2979gui_mch_show_toolbar(int showit) 2980{ 2981 Cardinal numChildren; /* how many children toolBar has */ 2982 2983 if (toolBar == (Widget)0) 2984 return; 2985 XtVaGetValues(toolBar, XmNnumChildren, &numChildren, NULL); 2986 if (showit && numChildren > 0) 2987 { 2988 /* Assume that we want to show the toolbar if p_toolbar contains 2989 * valid option settings, therefore p_toolbar must not be NULL. 2990 */ 2991 WidgetList children; 2992 2993 XtVaGetValues(toolBar, XmNchildren, &children, NULL); 2994 { 2995 void (*action)(BalloonEval *); 2996 int text = 0; 2997 2998 if (strstr((const char *)p_toolbar, "tooltips")) 2999 action = &gui_mch_enable_beval_area; 3000 else 3001 action = &gui_mch_disable_beval_area; 3002 if (strstr((const char *)p_toolbar, "text")) 3003 text = 1; 3004 else if (strstr((const char *)p_toolbar, "icons")) 3005 text = -1; 3006 if (text != 0) 3007 { 3008 vimmenu_T *toolbar; 3009 vimmenu_T *cur; 3010 3011 for (toolbar = root_menu; toolbar; toolbar = toolbar->next) 3012 if (menu_is_toolbar(toolbar->dname)) 3013 break; 3014 /* Assumption: toolbar is NULL if there is no toolbar, 3015 * otherwise it contains the toolbar menu structure. 3016 * 3017 * Assumption: "numChildren" == the number of items in the list 3018 * of items beginning with toolbar->children. 3019 */ 3020 if (toolbar) 3021 { 3022 for (cur = toolbar->children; cur; cur = cur->next) 3023 { 3024 Arg args[1]; 3025 int n = 0; 3026 3027 /* Enable/Disable tooltip (OK to enable while 3028 * currently enabled). */ 3029 if (cur->tip != NULL) 3030 (*action)(cur->tip); 3031 if (!menu_is_separator(cur->name)) 3032 { 3033 if (text == 1 || cur->xpm == NULL) 3034 { 3035 XtSetArg(args[n], XmNlabelType, XmSTRING); 3036 ++n; 3037 } 3038 if (cur->id != NULL) 3039 { 3040 XtUnmanageChild(cur->id); 3041 XtSetValues(cur->id, args, n); 3042 XtManageChild(cur->id); 3043 } 3044 } 3045 } 3046 } 3047 } 3048 } 3049 gui.toolbar_height = gui_mch_compute_toolbar_height(); 3050 XtManageChild(XtParent(toolBar)); 3051#ifdef FEAT_GUI_TABLINE 3052 if (showing_tabline) 3053 { 3054 XtVaSetValues(tabLine, 3055 XmNtopAttachment, XmATTACH_WIDGET, 3056 XmNtopWidget, XtParent(toolBar), 3057 NULL); 3058 XtVaSetValues(textAreaForm, 3059 XmNtopAttachment, XmATTACH_WIDGET, 3060 XmNtopWidget, tabLine, 3061 NULL); 3062 } 3063 else 3064#endif 3065 XtVaSetValues(textAreaForm, 3066 XmNtopAttachment, XmATTACH_WIDGET, 3067 XmNtopWidget, XtParent(toolBar), 3068 NULL); 3069 if (XtIsManaged(menuBar)) 3070 XtVaSetValues(XtParent(toolBar), 3071 XmNtopAttachment, XmATTACH_WIDGET, 3072 XmNtopWidget, menuBar, 3073 NULL); 3074 else 3075 XtVaSetValues(XtParent(toolBar), 3076 XmNtopAttachment, XmATTACH_FORM, 3077 NULL); 3078 } 3079 else 3080 { 3081 gui.toolbar_height = 0; 3082 if (XtIsManaged(menuBar)) 3083 { 3084#ifdef FEAT_GUI_TABLINE 3085 if (showing_tabline) 3086 { 3087 XtVaSetValues(tabLine, 3088 XmNtopAttachment, XmATTACH_WIDGET, 3089 XmNtopWidget, menuBar, 3090 NULL); 3091 XtVaSetValues(textAreaForm, 3092 XmNtopAttachment, XmATTACH_WIDGET, 3093 XmNtopWidget, tabLine, 3094 NULL); 3095 } 3096 else 3097#endif 3098 XtVaSetValues(textAreaForm, 3099 XmNtopAttachment, XmATTACH_WIDGET, 3100 XmNtopWidget, menuBar, 3101 NULL); 3102 } 3103 else 3104 { 3105#ifdef FEAT_GUI_TABLINE 3106 if (showing_tabline) 3107 { 3108 XtVaSetValues(tabLine, 3109 XmNtopAttachment, XmATTACH_FORM, 3110 NULL); 3111 XtVaSetValues(textAreaForm, 3112 XmNtopAttachment, XmATTACH_WIDGET, 3113 XmNtopWidget, tabLine, 3114 NULL); 3115 } 3116 else 3117#endif 3118 XtVaSetValues(textAreaForm, 3119 XmNtopAttachment, XmATTACH_FORM, 3120 NULL); 3121 } 3122 3123 XtUnmanageChild(XtParent(toolBar)); 3124 } 3125 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT); 3126} 3127 3128/* 3129 * A toolbar button has been pushed; now reset the input focus 3130 * such that the user can type page up/down etc. and have the 3131 * input go to the editor window, not the button 3132 */ 3133 static void 3134reset_focus() 3135{ 3136 if (textArea != NULL) 3137 XmProcessTraversal(textArea, XmTRAVERSE_CURRENT); 3138} 3139 3140 int 3141gui_mch_compute_toolbar_height() 3142{ 3143 Dimension borders; 3144 Dimension height; /* total Toolbar height */ 3145 Dimension whgt; /* height of each widget */ 3146 WidgetList children; /* list of toolBar's children */ 3147 Cardinal numChildren; /* how many children toolBar has */ 3148 int i; 3149 3150 borders = 0; 3151 height = 0; 3152 if (toolBar != (Widget)0 && toolBarFrame != (Widget)0) 3153 { /* get height of XmFrame parent */ 3154 Dimension fst; 3155 Dimension fmh; 3156 Dimension tst; 3157 Dimension tmh; 3158 3159 XtVaGetValues(toolBarFrame, 3160 XmNshadowThickness, &fst, 3161 XmNmarginHeight, &fmh, 3162 NULL); 3163 borders += fst + fmh; 3164 XtVaGetValues(toolBar, 3165 XmNshadowThickness, &tst, 3166 XmNmarginHeight, &tmh, 3167 XmNchildren, &children, 3168 XmNnumChildren, &numChildren, NULL); 3169 borders += tst + tmh; 3170 for (i = 0; i < (int)numChildren; i++) 3171 { 3172 whgt = 0; 3173 XtVaGetValues(children[i], XmNheight, &whgt, NULL); 3174 if (height < whgt) 3175 height = whgt; 3176 } 3177 } 3178#ifdef LESSTIF_VERSION 3179 /* Hack: When starting up we get wrong dimensions. */ 3180 if (height < 10) 3181 height = 24; 3182#endif 3183 3184 return (int)(height + (borders << 1)); 3185} 3186 3187 void 3188motif_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp) 3189 Pixel *bgp; 3190 Pixel *fgp; 3191 Pixel *bsp; 3192 Pixel *tsp; 3193 Pixel *hsp; 3194{ 3195 XtVaGetValues(toolBar, 3196 XmNbackground, bgp, 3197 XmNforeground, fgp, 3198 XmNbottomShadowColor, bsp, 3199 XmNtopShadowColor, tsp, 3200 XmNhighlightColor, hsp, 3201 NULL); 3202} 3203 3204# ifdef FEAT_FOOTER 3205/* 3206 * The next toolbar enter/leave callbacks should really do balloon help. But 3207 * I have to use footer help for backwards compatability. Hopefully both will 3208 * get implemented and the user will have a choice. 3209 */ 3210 static void 3211toolbarbutton_enter_cb(w, client_data, event, cont) 3212 Widget w UNUSED; 3213 XtPointer client_data; 3214 XEvent *event UNUSED; 3215 Boolean *cont UNUSED; 3216{ 3217 vimmenu_T *menu = (vimmenu_T *) client_data; 3218 3219 if (menu->strings[MENU_INDEX_TIP] != NULL) 3220 { 3221 if (vim_strchr(p_go, GO_FOOTER) != NULL) 3222 gui_mch_set_footer(menu->strings[MENU_INDEX_TIP]); 3223 } 3224} 3225 3226 static void 3227toolbarbutton_leave_cb(w, client_data, event, cont) 3228 Widget w UNUSED; 3229 XtPointer client_data UNUSED; 3230 XEvent *event UNUSED; 3231 Boolean *cont UNUSED; 3232{ 3233 gui_mch_set_footer((char_u *) ""); 3234} 3235# endif 3236#endif 3237 3238#if defined(FEAT_GUI_TABLINE) || defined(PROTO) 3239/* 3240 * Show or hide the tabline. 3241 */ 3242 void 3243gui_mch_show_tabline(int showit) 3244{ 3245 if (tabLine == (Widget)0) 3246 return; 3247 3248 if (!showit != !showing_tabline) 3249 { 3250 if (showit) 3251 { 3252 XtManageChild(tabLine); 3253 XtUnmanageChild(XtNameToWidget(tabLine, "PageScroller")); 3254 XtUnmanageChild(XtNameToWidget(tabLine, "MinorTabScrollerNext")); 3255 XtUnmanageChild(XtNameToWidget(tabLine, 3256 "MinorTabScrollerPrevious")); 3257#ifdef FEAT_MENU 3258# ifdef FEAT_TOOLBAR 3259 if (XtIsManaged(XtParent(toolBar))) 3260 XtVaSetValues(tabLine, 3261 XmNtopAttachment, XmATTACH_WIDGET, 3262 XmNtopWidget, XtParent(toolBar), NULL); 3263 else 3264# endif 3265 if (XtIsManaged(menuBar)) 3266 XtVaSetValues(tabLine, 3267 XmNtopAttachment, XmATTACH_WIDGET, 3268 XmNtopWidget, menuBar, NULL); 3269 else 3270#endif 3271 XtVaSetValues(tabLine, 3272 XmNtopAttachment, XmATTACH_FORM, NULL); 3273 XtVaSetValues(textAreaForm, 3274 XmNtopAttachment, XmATTACH_WIDGET, 3275 XmNtopWidget, tabLine, 3276 NULL); 3277 } 3278 else 3279 { 3280 XtUnmanageChild(tabLine); 3281#ifdef FEAT_MENU 3282# ifdef FEAT_TOOLBAR 3283 if (XtIsManaged(XtParent(toolBar))) 3284 XtVaSetValues(textAreaForm, 3285 XmNtopAttachment, XmATTACH_WIDGET, 3286 XmNtopWidget, XtParent(toolBar), NULL); 3287 else 3288# endif 3289 if (XtIsManaged(menuBar)) 3290 XtVaSetValues(textAreaForm, 3291 XmNtopAttachment, XmATTACH_WIDGET, 3292 XmNtopWidget, menuBar, NULL); 3293 else 3294#endif 3295 XtVaSetValues(textAreaForm, 3296 XmNtopAttachment, XmATTACH_FORM, NULL); 3297 } 3298 showing_tabline = showit; 3299 } 3300} 3301 3302/* 3303 * Return TRUE when tabline is displayed. 3304 */ 3305 int 3306gui_mch_showing_tabline(void) 3307{ 3308 return tabLine != (Widget)0 && showing_tabline; 3309} 3310 3311/* 3312 * Update the labels of the tabline. 3313 */ 3314 void 3315gui_mch_update_tabline(void) 3316{ 3317 tabpage_T *tp; 3318 int nr = 1, n; 3319 Arg args[10]; 3320 int curtabidx = 0, currentpage; 3321 Widget tab; 3322 XmNotebookPageInfo page_info; 3323 XmNotebookPageStatus page_status; 3324 int last_page, tab_count; 3325 XmString label_str; 3326 char *label_cstr; 3327 BalloonEval *beval; 3328 3329 if (tabLine == (Widget)0) 3330 return; 3331 3332 /* Add a label for each tab page. They all contain the same text area. */ 3333 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) 3334 { 3335 if (tp == curtab) 3336 curtabidx = nr; 3337 3338 page_status = XmNotebookGetPageInfo(tabLine, nr, &page_info); 3339 if (page_status == XmPAGE_INVALID 3340 || page_info.major_tab_widget == (Widget)0) 3341 { 3342 /* Add the tab */ 3343 n = 0; 3344 XtSetArg(args[n], XmNnotebookChildType, XmMAJOR_TAB); n++; 3345 XtSetArg(args[n], XmNtraversalOn, False); n++; 3346 XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; 3347 XtSetArg(args[n], XmNhighlightThickness, 1); n++; 3348 XtSetArg(args[n], XmNshadowThickness , 1); n++; 3349 tab = XmCreatePushButton(tabLine, "-Empty-", args, n); 3350 XtManageChild(tab); 3351 beval = gui_mch_create_beval_area(tab, NULL, tabline_balloon_cb, 3352 NULL); 3353 XtVaSetValues(tab, XmNuserData, beval, NULL); 3354 } 3355 else 3356 tab = page_info.major_tab_widget; 3357 3358 XtVaSetValues(tab, XmNpageNumber, nr, NULL); 3359 3360 /* 3361 * Change the label text only if it is different 3362 */ 3363 XtVaGetValues(tab, XmNlabelString, &label_str, NULL); 3364 if (XmStringGetLtoR(label_str, XmSTRING_DEFAULT_CHARSET, &label_cstr)) 3365 { 3366 get_tabline_label(tp, FALSE); 3367 if (STRCMP(label_cstr, NameBuff) != 0) 3368 { 3369 XtVaSetValues(tab, XtVaTypedArg, XmNlabelString, XmRString, 3370 NameBuff, STRLEN(NameBuff) + 1, NULL); 3371 /* 3372 * Force a resize of the tab label button 3373 */ 3374 XtUnmanageChild(tab); 3375 XtManageChild(tab); 3376 } 3377 XtFree(label_cstr); 3378 } 3379 } 3380 3381 tab_count = nr - 1; 3382 3383 XtVaGetValues(tabLine, XmNlastPageNumber, &last_page, NULL); 3384 3385 /* Remove any old labels. */ 3386 while (nr <= last_page) 3387 { 3388 if (XmNotebookGetPageInfo(tabLine, nr, &page_info) != XmPAGE_INVALID 3389 && page_info.page_number == nr 3390 && page_info.major_tab_widget != (Widget)0) 3391 { 3392 XtVaGetValues(page_info.major_tab_widget, XmNuserData, &beval, NULL); 3393 if (beval != NULL) 3394 gui_mch_destroy_beval_area(beval); 3395 XtUnmanageChild(page_info.major_tab_widget); 3396 XtDestroyWidget(page_info.major_tab_widget); 3397 } 3398 nr++; 3399 } 3400 3401 XtVaSetValues(tabLine, XmNlastPageNumber, tab_count, NULL); 3402 3403 XtVaGetValues(tabLine, XmNcurrentPageNumber, ¤tpage, NULL); 3404 if (currentpage != curtabidx) 3405 XtVaSetValues(tabLine, XmNcurrentPageNumber, curtabidx, NULL); 3406} 3407 3408/* 3409 * Set the current tab to "nr". First tab is 1. 3410 */ 3411 void 3412gui_mch_set_curtab(nr) 3413 int nr; 3414{ 3415 int currentpage; 3416 3417 if (tabLine == (Widget)0) 3418 return; 3419 3420 XtVaGetValues(tabLine, XmNcurrentPageNumber, ¤tpage, NULL); 3421 if (currentpage != nr) 3422 XtVaSetValues(tabLine, XmNcurrentPageNumber, nr, NULL); 3423} 3424#endif 3425 3426/* 3427 * Set the colors of Widget "id" to the menu colors. 3428 */ 3429 static void 3430gui_motif_menu_colors(id) 3431 Widget id; 3432{ 3433 if (gui.menu_bg_pixel != INVALCOLOR) 3434#if (XmVersion >= 1002) 3435 XmChangeColor(id, gui.menu_bg_pixel); 3436#else 3437 XtVaSetValues(id, XmNbackground, gui.menu_bg_pixel, NULL); 3438#endif 3439 if (gui.menu_fg_pixel != INVALCOLOR) 3440 XtVaSetValues(id, XmNforeground, gui.menu_fg_pixel, NULL); 3441} 3442 3443/* 3444 * Set the colors of Widget "id" to the scrollbar colors. 3445 */ 3446 static void 3447gui_motif_scroll_colors(id) 3448 Widget id; 3449{ 3450 if (gui.scroll_bg_pixel != INVALCOLOR) 3451#if (XmVersion >= 1002) 3452 XmChangeColor(id, gui.scroll_bg_pixel); 3453#else 3454 XtVaSetValues(id, XmNbackground, gui.scroll_bg_pixel, NULL); 3455#endif 3456 if (gui.scroll_fg_pixel != INVALCOLOR) 3457 XtVaSetValues(id, XmNforeground, gui.scroll_fg_pixel, NULL); 3458} 3459 3460/* 3461 * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font. 3462 */ 3463 void 3464gui_motif_menu_fontlist(id) 3465 Widget id UNUSED; 3466{ 3467#ifdef FEAT_MENU 3468#ifdef FONTSET_ALWAYS 3469 if (gui.menu_fontset != NOFONTSET) 3470 { 3471 XmFontList fl; 3472 3473 fl = gui_motif_fontset2fontlist((XFontSet *)&gui.menu_fontset); 3474 if (fl != NULL) 3475 { 3476 if (XtIsManaged(id)) 3477 { 3478 XtUnmanageChild(id); 3479 XtVaSetValues(id, XmNfontList, fl, NULL); 3480 /* We should force the widget to recalculate it's 3481 * geometry now. */ 3482 XtManageChild(id); 3483 } 3484 else 3485 XtVaSetValues(id, XmNfontList, fl, NULL); 3486 XmFontListFree(fl); 3487 } 3488 } 3489#else 3490 if (gui.menu_font != NOFONT) 3491 { 3492 XmFontList fl; 3493 3494 fl = gui_motif_create_fontlist((XFontStruct *)gui.menu_font); 3495 if (fl != NULL) 3496 { 3497 if (XtIsManaged(id)) 3498 { 3499 XtUnmanageChild(id); 3500 XtVaSetValues(id, XmNfontList, fl, NULL); 3501 /* We should force the widget to recalculate it's 3502 * geometry now. */ 3503 XtManageChild(id); 3504 } 3505 else 3506 XtVaSetValues(id, XmNfontList, fl, NULL); 3507 XmFontListFree(fl); 3508 } 3509 } 3510#endif 3511#endif 3512} 3513 3514 3515/* 3516 * We don't create it twice for the sake of speed. 3517 */ 3518 3519typedef struct _SharedFindReplace 3520{ 3521 Widget dialog; /* the main dialog widget */ 3522 Widget wword; /* 'Exact match' check button */ 3523 Widget mcase; /* 'match case' check button */ 3524 Widget up; /* search direction 'Up' radio button */ 3525 Widget down; /* search direction 'Down' radio button */ 3526 Widget what; /* 'Find what' entry text widget */ 3527 Widget with; /* 'Replace with' entry text widget */ 3528 Widget find; /* 'Find Next' action button */ 3529 Widget replace; /* 'Replace With' action button */ 3530 Widget all; /* 'Replace All' action button */ 3531 Widget undo; /* 'Undo' action button */ 3532 3533 Widget cancel; 3534} SharedFindReplace; 3535 3536static SharedFindReplace find_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 3537static SharedFindReplace repl_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 3538 3539static void find_replace_destroy_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 3540static void find_replace_dismiss_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 3541static void entry_activate_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 3542static void find_replace_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); 3543static void find_replace_keypress __ARGS((Widget w, SharedFindReplace * frdp, XKeyEvent * event)); 3544static void find_replace_dialog_create __ARGS((char_u *entry_text, int do_replace)); 3545 3546 static void 3547find_replace_destroy_callback(w, client_data, call_data) 3548 Widget w UNUSED; 3549 XtPointer client_data; 3550 XtPointer call_data UNUSED; 3551{ 3552 SharedFindReplace *cd = (SharedFindReplace *)client_data; 3553 3554 if (cd != NULL) 3555 /* suppress_dialog_mnemonics(cd->dialog); */ 3556 cd->dialog = (Widget)0; 3557} 3558 3559 static void 3560find_replace_dismiss_callback(w, client_data, call_data) 3561 Widget w UNUSED; 3562 XtPointer client_data; 3563 XtPointer call_data UNUSED; 3564{ 3565 SharedFindReplace *cd = (SharedFindReplace *)client_data; 3566 3567 if (cd != NULL) 3568 XtUnmanageChild(cd->dialog); 3569} 3570 3571 static void 3572entry_activate_callback(w, client_data, call_data) 3573 Widget w UNUSED; 3574 XtPointer client_data; 3575 XtPointer call_data UNUSED; 3576{ 3577 XmProcessTraversal((Widget)client_data, XmTRAVERSE_CURRENT); 3578} 3579 3580 static void 3581find_replace_callback(w, client_data, call_data) 3582 Widget w UNUSED; 3583 XtPointer client_data; 3584 XtPointer call_data UNUSED; 3585{ 3586 long_u flags = (long_u)client_data; 3587 char *find_text, *repl_text; 3588 Boolean direction_down = TRUE; 3589 Boolean wword; 3590 Boolean mcase; 3591 SharedFindReplace *sfr; 3592 3593 if (flags == FRD_UNDO) 3594 { 3595 char_u *save_cpo = p_cpo; 3596 3597 /* No need to be Vi compatible here. */ 3598 p_cpo = (char_u *)""; 3599 u_undo(1); 3600 p_cpo = save_cpo; 3601 gui_update_screen(); 3602 return; 3603 } 3604 3605 /* Get the search/replace strings from the dialog */ 3606 if (flags == FRD_FINDNEXT) 3607 { 3608 repl_text = NULL; 3609 sfr = &find_widgets; 3610 } 3611 else 3612 { 3613 repl_text = XmTextFieldGetString(repl_widgets.with); 3614 sfr = &repl_widgets; 3615 } 3616 find_text = XmTextFieldGetString(sfr->what); 3617 XtVaGetValues(sfr->down, XmNset, &direction_down, NULL); 3618 XtVaGetValues(sfr->wword, XmNset, &wword, NULL); 3619 XtVaGetValues(sfr->mcase, XmNset, &mcase, NULL); 3620 if (wword) 3621 flags |= FRD_WHOLE_WORD; 3622 if (mcase) 3623 flags |= FRD_MATCH_CASE; 3624 3625 (void)gui_do_findrepl((int)flags, (char_u *)find_text, (char_u *)repl_text, 3626 direction_down); 3627 3628 if (find_text != NULL) 3629 XtFree(find_text); 3630 if (repl_text != NULL) 3631 XtFree(repl_text); 3632} 3633 3634 static void 3635find_replace_keypress(w, frdp, event) 3636 Widget w UNUSED; 3637 SharedFindReplace *frdp; 3638 XKeyEvent *event; 3639{ 3640 KeySym keysym; 3641 3642 if (frdp == NULL) 3643 return; 3644 3645 keysym = XLookupKeysym(event, 0); 3646 3647 /* the scape key pops the whole dialog down */ 3648 if (keysym == XK_Escape) 3649 XtUnmanageChild(frdp->dialog); 3650} 3651 3652 static void 3653set_label(w, label) 3654 Widget w; 3655 char_u *label; 3656{ 3657 XmString str; 3658 char_u *p, *next; 3659 KeySym mnemonic = NUL; 3660 3661 if (!w) 3662 return; 3663 3664 p = vim_strsave(label); 3665 if (p == NULL) 3666 return; 3667 for (next = p; *next; ++next) 3668 { 3669 if (*next == DLG_HOTKEY_CHAR) 3670 { 3671 int len = STRLEN(next); 3672 3673 if (len > 0) 3674 { 3675 mch_memmove(next, next + 1, len); 3676 mnemonic = next[0]; 3677 } 3678 } 3679 } 3680 3681 str = XmStringCreateSimple((char *)p); 3682 vim_free(p); 3683 if (str) 3684 { 3685 XtVaSetValues(w, 3686 XmNlabelString, str, 3687 XmNmnemonic, mnemonic, 3688 NULL); 3689 XmStringFree(str); 3690 } 3691 gui_motif_menu_fontlist(w); 3692} 3693 3694 static void 3695find_replace_dialog_create(arg, do_replace) 3696 char_u *arg; 3697 int do_replace; 3698{ 3699 SharedFindReplace *frdp; 3700 Widget separator; 3701 Widget input_form; 3702 Widget button_form; 3703 Widget toggle_form; 3704 Widget frame; 3705 XmString str; 3706 int n; 3707 Arg args[6]; 3708 int wword = FALSE; 3709 int mcase = !p_ic; 3710 Dimension width; 3711 Dimension widest; 3712 char_u *entry_text; 3713 3714 frdp = do_replace ? &repl_widgets : &find_widgets; 3715 3716 /* Get the search string to use. */ 3717 entry_text = get_find_dialog_text(arg, &wword, &mcase); 3718 3719 /* If the dialog already exists, just raise it. */ 3720 if (frdp->dialog) 3721 { 3722 gui_motif_synch_fonts(); 3723 3724 /* If the window is already up, just pop it to the top */ 3725 if (XtIsManaged(frdp->dialog)) 3726 XMapRaised(XtDisplay(frdp->dialog), 3727 XtWindow(XtParent(frdp->dialog))); 3728 else 3729 XtManageChild(frdp->dialog); 3730 XtPopup(XtParent(frdp->dialog), XtGrabNone); 3731 XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT); 3732 3733 if (entry_text != NULL) 3734 XmTextFieldSetString(frdp->what, (char *)entry_text); 3735 vim_free(entry_text); 3736 3737 XtVaSetValues(frdp->wword, XmNset, wword, NULL); 3738 return; 3739 } 3740 3741 /* Create a fresh new dialog window */ 3742 if (do_replace) 3743 str = XmStringCreateSimple(_("VIM - Search and Replace...")); 3744 else 3745 str = XmStringCreateSimple(_("VIM - Search...")); 3746 3747 n = 0; 3748 XtSetArg(args[n], XmNautoUnmanage, False); n++; 3749 XtSetArg(args[n], XmNnoResize, True); n++; 3750 XtSetArg(args[n], XmNdialogTitle, str); n++; 3751 3752 frdp->dialog = XmCreateFormDialog(vimShell, "findReplaceDialog", args, n); 3753 XmStringFree(str); 3754 XtAddCallback(frdp->dialog, XmNdestroyCallback, 3755 find_replace_destroy_callback, frdp); 3756 3757 button_form = XtVaCreateWidget("buttonForm", 3758 xmFormWidgetClass, frdp->dialog, 3759 XmNrightAttachment, XmATTACH_FORM, 3760 XmNrightOffset, 4, 3761 XmNtopAttachment, XmATTACH_FORM, 3762 XmNtopOffset, 4, 3763 XmNbottomAttachment, XmATTACH_FORM, 3764 XmNbottomOffset, 4, 3765 NULL); 3766 3767 frdp->find = XtVaCreateManagedWidget("findButton", 3768 xmPushButtonWidgetClass, button_form, 3769 XmNsensitive, True, 3770 XmNtopAttachment, XmATTACH_FORM, 3771 XmNleftAttachment, XmATTACH_FORM, 3772 XmNrightAttachment, XmATTACH_FORM, 3773 NULL); 3774 set_label(frdp->find, _("Find &Next")); 3775 3776 XtAddCallback(frdp->find, XmNactivateCallback, 3777 find_replace_callback, 3778 (do_replace ? (XtPointer)FRD_R_FINDNEXT : (XtPointer)FRD_FINDNEXT)); 3779 3780 if (do_replace) 3781 { 3782 frdp->replace = XtVaCreateManagedWidget("replaceButton", 3783 xmPushButtonWidgetClass, button_form, 3784 XmNtopAttachment, XmATTACH_WIDGET, 3785 XmNtopWidget, frdp->find, 3786 XmNleftAttachment, XmATTACH_FORM, 3787 XmNrightAttachment, XmATTACH_FORM, 3788 NULL); 3789 set_label(frdp->replace, _("&Replace")); 3790 XtAddCallback(frdp->replace, XmNactivateCallback, 3791 find_replace_callback, (XtPointer)FRD_REPLACE); 3792 3793 frdp->all = XtVaCreateManagedWidget("replaceAllButton", 3794 xmPushButtonWidgetClass, button_form, 3795 XmNtopAttachment, XmATTACH_WIDGET, 3796 XmNtopWidget, frdp->replace, 3797 XmNleftAttachment, XmATTACH_FORM, 3798 XmNrightAttachment, XmATTACH_FORM, 3799 NULL); 3800 set_label(frdp->all, _("Replace &All")); 3801 XtAddCallback(frdp->all, XmNactivateCallback, 3802 find_replace_callback, (XtPointer)FRD_REPLACEALL); 3803 3804 frdp->undo = XtVaCreateManagedWidget("undoButton", 3805 xmPushButtonWidgetClass, button_form, 3806 XmNtopAttachment, XmATTACH_WIDGET, 3807 XmNtopWidget, frdp->all, 3808 XmNleftAttachment, XmATTACH_FORM, 3809 XmNrightAttachment, XmATTACH_FORM, 3810 NULL); 3811 set_label(frdp->undo, _("&Undo")); 3812 XtAddCallback(frdp->undo, XmNactivateCallback, 3813 find_replace_callback, (XtPointer)FRD_UNDO); 3814 } 3815 3816 frdp->cancel = XtVaCreateManagedWidget("closeButton", 3817 xmPushButtonWidgetClass, button_form, 3818 XmNleftAttachment, XmATTACH_FORM, 3819 XmNrightAttachment, XmATTACH_FORM, 3820 XmNbottomAttachment, XmATTACH_FORM, 3821 NULL); 3822 set_label(frdp->cancel, _("&Cancel")); 3823 XtAddCallback(frdp->cancel, XmNactivateCallback, 3824 find_replace_dismiss_callback, frdp); 3825 gui_motif_menu_fontlist(frdp->cancel); 3826 3827 XtManageChild(button_form); 3828 3829 n = 0; 3830 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; 3831 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; 3832 XtSetArg(args[n], XmNrightWidget, button_form); n++; 3833 XtSetArg(args[n], XmNrightOffset, 4); n++; 3834 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 3835 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; 3836 separator = XmCreateSeparatorGadget(frdp->dialog, "separator", args, n); 3837 XtManageChild(separator); 3838 3839 input_form = XtVaCreateWidget("inputForm", 3840 xmFormWidgetClass, frdp->dialog, 3841 XmNleftAttachment, XmATTACH_FORM, 3842 XmNleftOffset, 4, 3843 XmNrightAttachment, XmATTACH_WIDGET, 3844 XmNrightWidget, separator, 3845 XmNrightOffset, 4, 3846 XmNtopAttachment, XmATTACH_FORM, 3847 XmNtopOffset, 4, 3848 NULL); 3849 3850 { 3851 Widget label_what; 3852 Widget label_with = (Widget)0; 3853 3854 str = XmStringCreateSimple(_("Find what:")); 3855 label_what = XtVaCreateManagedWidget("whatLabel", 3856 xmLabelGadgetClass, input_form, 3857 XmNlabelString, str, 3858 XmNleftAttachment, XmATTACH_FORM, 3859 XmNtopAttachment, XmATTACH_FORM, 3860 XmNtopOffset, 4, 3861 NULL); 3862 XmStringFree(str); 3863 gui_motif_menu_fontlist(label_what); 3864 3865 frdp->what = XtVaCreateManagedWidget("whatText", 3866 xmTextFieldWidgetClass, input_form, 3867 XmNtopAttachment, XmATTACH_FORM, 3868 XmNrightAttachment, XmATTACH_FORM, 3869 XmNleftAttachment, XmATTACH_FORM, 3870 NULL); 3871 3872 if (do_replace) 3873 { 3874 frdp->with = XtVaCreateManagedWidget("withText", 3875 xmTextFieldWidgetClass, input_form, 3876 XmNtopAttachment, XmATTACH_WIDGET, 3877 XmNtopWidget, frdp->what, 3878 XmNtopOffset, 4, 3879 XmNleftAttachment, XmATTACH_FORM, 3880 XmNrightAttachment, XmATTACH_FORM, 3881 XmNbottomAttachment, XmATTACH_FORM, 3882 NULL); 3883 3884 XtAddCallback(frdp->with, XmNactivateCallback, 3885 find_replace_callback, (XtPointer) FRD_R_FINDNEXT); 3886 3887 str = XmStringCreateSimple(_("Replace with:")); 3888 label_with = XtVaCreateManagedWidget("withLabel", 3889 xmLabelGadgetClass, input_form, 3890 XmNlabelString, str, 3891 XmNleftAttachment, XmATTACH_FORM, 3892 XmNtopAttachment, XmATTACH_WIDGET, 3893 XmNtopWidget, frdp->what, 3894 XmNtopOffset, 4, 3895 XmNbottomAttachment, XmATTACH_FORM, 3896 NULL); 3897 XmStringFree(str); 3898 gui_motif_menu_fontlist(label_with); 3899 3900 /* 3901 * Make the entry activation only change the input focus onto the 3902 * with item. 3903 */ 3904 XtAddCallback(frdp->what, XmNactivateCallback, 3905 entry_activate_callback, frdp->with); 3906 XtAddEventHandler(frdp->with, KeyPressMask, False, 3907 (XtEventHandler)find_replace_keypress, 3908 (XtPointer) frdp); 3909 3910 } 3911 else 3912 { 3913 /* 3914 * Make the entry activation do the search. 3915 */ 3916 XtAddCallback(frdp->what, XmNactivateCallback, 3917 find_replace_callback, (XtPointer)FRD_FINDNEXT); 3918 } 3919 XtAddEventHandler(frdp->what, KeyPressMask, False, 3920 (XtEventHandler)find_replace_keypress, 3921 (XtPointer)frdp); 3922 3923 /* Get the maximum width between the label widgets and line them up. 3924 */ 3925 n = 0; 3926 XtSetArg(args[n], XmNwidth, &width); n++; 3927 XtGetValues(label_what, args, n); 3928 widest = width; 3929 if (do_replace) 3930 { 3931 XtGetValues(label_with, args, n); 3932 if (width > widest) 3933 widest = width; 3934 } 3935 3936 XtVaSetValues(frdp->what, XmNleftOffset, widest, NULL); 3937 if (do_replace) 3938 XtVaSetValues(frdp->with, XmNleftOffset, widest, NULL); 3939 3940 } 3941 3942 XtManageChild(input_form); 3943 3944 { 3945 Widget radio_box; 3946 Widget w; 3947 3948 frame = XtVaCreateWidget("directionFrame", 3949 xmFrameWidgetClass, frdp->dialog, 3950 XmNtopAttachment, XmATTACH_WIDGET, 3951 XmNtopWidget, input_form, 3952 XmNtopOffset, 4, 3953 XmNbottomAttachment, XmATTACH_FORM, 3954 XmNbottomOffset, 4, 3955 XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET, 3956 XmNrightWidget, input_form, 3957 NULL); 3958 3959 str = XmStringCreateSimple(_("Direction")); 3960 w = XtVaCreateManagedWidget("directionFrameLabel", 3961 xmLabelGadgetClass, frame, 3962 XmNlabelString, str, 3963 XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, 3964 XmNchildType, XmFRAME_TITLE_CHILD, 3965 NULL); 3966 XmStringFree(str); 3967 gui_motif_menu_fontlist(w); 3968 3969 radio_box = XmCreateRadioBox(frame, "radioBox", 3970 (ArgList)NULL, 0); 3971 3972 str = XmStringCreateSimple( _("Up")); 3973 frdp->up = XtVaCreateManagedWidget("upRadioButton", 3974 xmToggleButtonGadgetClass, radio_box, 3975 XmNlabelString, str, 3976 XmNset, False, 3977 NULL); 3978 XmStringFree(str); 3979 gui_motif_menu_fontlist(frdp->up); 3980 3981 str = XmStringCreateSimple(_("Down")); 3982 frdp->down = XtVaCreateManagedWidget("downRadioButton", 3983 xmToggleButtonGadgetClass, radio_box, 3984 XmNlabelString, str, 3985 XmNset, True, 3986 NULL); 3987 XmStringFree(str); 3988 gui_motif_menu_fontlist(frdp->down); 3989 3990 XtManageChild(radio_box); 3991 XtManageChild(frame); 3992 } 3993 3994 toggle_form = XtVaCreateWidget("toggleForm", 3995 xmFormWidgetClass, frdp->dialog, 3996 XmNleftAttachment, XmATTACH_FORM, 3997 XmNleftOffset, 4, 3998 XmNrightAttachment, XmATTACH_WIDGET, 3999 XmNrightWidget, frame, 4000 XmNrightOffset, 4, 4001 XmNtopAttachment, XmATTACH_WIDGET, 4002 XmNtopWidget, input_form, 4003 XmNtopOffset, 4, 4004 XmNbottomAttachment, XmATTACH_FORM, 4005 XmNbottomOffset, 4, 4006 NULL); 4007 4008 str = XmStringCreateSimple(_("Match whole word only")); 4009 frdp->wword = XtVaCreateManagedWidget("wordToggle", 4010 xmToggleButtonGadgetClass, toggle_form, 4011 XmNlabelString, str, 4012 XmNtopAttachment, XmATTACH_FORM, 4013 XmNtopOffset, 4, 4014 XmNleftAttachment, XmATTACH_FORM, 4015 XmNleftOffset, 4, 4016 XmNset, wword, 4017 NULL); 4018 XmStringFree(str); 4019 4020 str = XmStringCreateSimple(_("Match case")); 4021 frdp->mcase = XtVaCreateManagedWidget("caseToggle", 4022 xmToggleButtonGadgetClass, toggle_form, 4023 XmNlabelString, str, 4024 XmNleftAttachment, XmATTACH_FORM, 4025 XmNleftOffset, 4, 4026 XmNtopAttachment, XmATTACH_WIDGET, 4027 XmNtopWidget, frdp->wword, 4028 XmNtopOffset, 4, 4029 XmNset, mcase, 4030 NULL); 4031 XmStringFree(str); 4032 gui_motif_menu_fontlist(frdp->wword); 4033 gui_motif_menu_fontlist(frdp->mcase); 4034 4035 XtManageChild(toggle_form); 4036 4037 if (entry_text != NULL) 4038 XmTextFieldSetString(frdp->what, (char *)entry_text); 4039 vim_free(entry_text); 4040 4041 gui_motif_synch_fonts(); 4042 4043 manage_centered(frdp->dialog); 4044 activate_dialog_mnemonics(frdp->dialog); 4045 XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT); 4046} 4047 4048 void 4049gui_mch_find_dialog(eap) 4050 exarg_T *eap; 4051{ 4052 if (!gui.in_use) 4053 return; 4054 4055 find_replace_dialog_create(eap->arg, FALSE); 4056} 4057 4058 4059 void 4060gui_mch_replace_dialog(eap) 4061 exarg_T *eap; 4062{ 4063 if (!gui.in_use) 4064 return; 4065 4066 find_replace_dialog_create(eap->arg, TRUE); 4067} 4068 4069/* 4070 * Synchronize all gui elements, which are dependant upon the 4071 * main text font used. Those are in esp. the find/replace dialogs. 4072 * If you don't understand why this should be needed, please try to 4073 * search for "pi��" in iso8859-2. 4074 */ 4075 void 4076gui_motif_synch_fonts(void) 4077{ 4078 SharedFindReplace *frdp; 4079 int do_replace; 4080 XFontStruct *font; 4081 XmFontList font_list; 4082 4083 /* FIXME: Unless we find out how to create a XmFontList from a XFontSet, 4084 * we just give up here on font synchronization. */ 4085 font = (XFontStruct *)gui.norm_font; 4086 if (font == NULL) 4087 return; 4088 4089 font_list = gui_motif_create_fontlist(font); 4090 4091 /* OK this loop is a bit tricky... */ 4092 for (do_replace = 0; do_replace <= 1; ++do_replace) 4093 { 4094 frdp = (do_replace) ? (&repl_widgets) : (&find_widgets); 4095 if (frdp->dialog) 4096 { 4097 XtVaSetValues(frdp->what, XmNfontList, font_list, NULL); 4098 if (do_replace) 4099 XtVaSetValues(frdp->with, XmNfontList, font_list, NULL); 4100 } 4101 } 4102 4103 XmFontListFree(font_list); 4104} 4105