blob: 4fe26ec57be48c1fd2208b5e5aac9a5b4b1a310d [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* 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
30#include <X11/keysym.h>
31#include <X11/Xatom.h>
32#include <X11/StringDefs.h>
33#include <X11/Intrinsic.h>
34
35#include "vim.h"
36
37#ifdef HAVE_X11_XPM_H
38# include <X11/xpm.h>
39#else
40# ifdef HAVE_XM_XPMP_H
41# include <Xm/XpmP.h>
42# endif
43#endif
44
45#if defined(FEAT_GUI_DIALOG) && defined(HAVE_XPM)
46# include "../pixmaps/alert.xpm"
47# include "../pixmaps/error.xpm"
48# include "../pixmaps/generic.xpm"
49# include "../pixmaps/info.xpm"
50# include "../pixmaps/quest.xpm"
51#endif
52
53#define MOTIF_POPUP
54
55extern Widget vimShell;
56
57static Widget vimForm;
58static Widget textAreaForm;
59Widget textArea;
60#ifdef FEAT_TOOLBAR
61static Widget toolBarFrame;
62static Widget toolBar;
63#endif
64#ifdef FEAT_FOOTER
65static Widget footer;
66#endif
67#ifdef FEAT_MENU
68# if (XmVersion >= 1002)
69/* remember the last set value for the tearoff item */
70static int tearoff_val = (int)XmTEAR_OFF_ENABLED;
71# endif
72static Widget menuBar;
73#endif
74
75static void scroll_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
76#ifdef FEAT_TOOLBAR
77# if 0
78static void toolbar_enter_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
79static void toolbar_leave_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
80# endif
81# ifdef FEAT_FOOTER
82static void toolbarbutton_enter_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
83static void toolbarbutton_leave_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
84# endif
85static void gui_mch_reset_focus __ARGS((void));
86#endif
87#ifdef FEAT_FOOTER
88static int gui_mch_compute_footer_height __ARGS((void));
89#endif
90#ifdef WSDEBUG
91static void attachDump(Widget, char *);
92#endif
93
94static void gui_motif_menu_colors __ARGS((Widget id));
95static void gui_motif_scroll_colors __ARGS((Widget id));
96#ifdef FEAT_MENU
97static void gui_motif_menu_fontlist __ARGS((Widget id));
98#endif
99
100#if (XmVersion >= 1002)
101# define STRING_TAG XmFONTLIST_DEFAULT_TAG
102#else
103# define STRING_TAG XmSTRING_DEFAULT_CHARSET
104#endif
105
106/*
107 * Call-back routines.
108 */
109
110/* ARGSUSED */
111 static void
112scroll_cb(w, client_data, call_data)
113 Widget w;
114 XtPointer client_data, call_data;
115{
116 scrollbar_T *sb;
117 long value;
118 int dragging;
119
120 sb = gui_find_scrollbar((long)client_data);
121
122 value = ((XmScrollBarCallbackStruct *)call_data)->value;
123 dragging = (((XmScrollBarCallbackStruct *)call_data)->reason ==
124 (int)XmCR_DRAG);
125 gui_drag_scrollbar(sb, value, dragging);
126}
127
128
129/*
130 * End of call-back routines
131 */
132
133/*
134 * Create all the motif widgets necessary.
135 */
136 void
137gui_x11_create_widgets()
138{
139 /*
140 * Start out by adding the configured border width into the border offset
141 */
142 gui.border_offset = gui.border_width;
143
144 /*
145 * Install the tearOffModel resource converter.
146 */
147#if (XmVersion >= 1002)
148 XmRepTypeInstallTearOffModelConverter();
149#endif
150
151 /* Make sure the "Quit" menu entry of the window manager is ignored */
152 XtVaSetValues(vimShell, XmNdeleteResponse, XmDO_NOTHING, NULL);
153
154 vimForm = XtVaCreateManagedWidget("vimForm",
155 xmFormWidgetClass, vimShell,
156 XmNborderWidth, 0,
157 XmNhighlightThickness, 0,
158 XmNshadowThickness, 0,
159 XmNmarginWidth, 0,
160 XmNmarginHeight, 0,
161 XmNresizePolicy, XmRESIZE_ANY,
162 NULL);
163 gui_motif_menu_colors(vimForm);
164
165#ifdef FEAT_MENU
166 {
167 Arg al[7]; /* Make sure there is enough room for arguments! */
168 int ac = 0;
169
170# if (XmVersion >= 1002)
171 XtSetArg(al[ac], XmNtearOffModel, tearoff_val); ac++;
172# endif
173 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
174 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
175 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
176# ifndef FEAT_TOOLBAR
177 /* Always stick to right hand side. */
178 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
179# endif
180 menuBar = XmCreateMenuBar(vimForm, "menuBar", al, ac);
181 XtManageChild(menuBar);
182
183 /* Remember the default colors, needed for ":hi clear". */
184 XtVaGetValues(menuBar,
185 XmNbackground, &gui.menu_def_bg_pixel,
186 XmNforeground, &gui.menu_def_fg_pixel,
187 NULL);
188 gui_motif_menu_colors(menuBar);
189 }
190#endif
191
192#ifdef FEAT_TOOLBAR
193 /*
194 * Create an empty ToolBar. We should get buttons defined from menu.vim.
195 */
196 toolBarFrame = XtVaCreateWidget("toolBarFrame",
197 xmFrameWidgetClass, vimForm,
198 XmNshadowThickness, 0,
199 XmNmarginHeight, 0,
200 XmNmarginWidth, 0,
201 XmNleftAttachment, XmATTACH_FORM,
202 XmNrightAttachment, XmATTACH_FORM,
203 NULL);
204 gui_motif_menu_colors(toolBarFrame);
205
206 toolBar = XtVaCreateManagedWidget("toolBar",
207 xmRowColumnWidgetClass, toolBarFrame,
208 XmNchildType, XmFRAME_WORKAREA_CHILD,
209 XmNrowColumnType, XmWORK_AREA,
210 XmNorientation, XmHORIZONTAL,
211 XmNtraversalOn, False,
212 XmNisHomogeneous, False,
213 XmNpacking, XmPACK_TIGHT,
214 XmNspacing, 0,
215 XmNshadowThickness, 0,
216 XmNhighlightThickness, 0,
217 XmNmarginHeight, 0,
218 XmNmarginWidth, 0,
219 XmNadjustLast, True,
220 NULL);
221 gui_motif_menu_colors(toolBar);
222
223# if 0 /* these don't work, because of the XmNtraversalOn above. */
224 XtAddEventHandler(toolBar, EnterWindowMask, False,
225 toolbar_enter_cb, NULL);
226 XtAddEventHandler(toolBar, LeaveWindowMask, False,
227 toolbar_leave_cb, NULL);
228# endif
229#endif
230
231 textAreaForm = XtVaCreateManagedWidget("textAreaForm",
232 xmFormWidgetClass, vimForm,
233 XmNleftAttachment, XmATTACH_FORM,
234 XmNrightAttachment, XmATTACH_FORM,
235 XmNbottomAttachment, XmATTACH_FORM,
236 XmNtopAttachment, XmATTACH_FORM,
237 XmNmarginWidth, 0,
238 XmNmarginHeight, 0,
239 XmNresizePolicy, XmRESIZE_ANY,
240 NULL);
241 gui_motif_scroll_colors(textAreaForm);
242
243 textArea = XtVaCreateManagedWidget("textArea",
244 xmDrawingAreaWidgetClass, textAreaForm,
245 XmNforeground, gui.norm_pixel,
246 XmNbackground, gui.back_pixel,
247 XmNleftAttachment, XmATTACH_FORM,
248 XmNtopAttachment, XmATTACH_FORM,
249 XmNrightAttachment, XmATTACH_FORM,
250 XmNbottomAttachment, XmATTACH_FORM,
251
252 /*
253 * These take some control away from the user, but avoids making them
254 * add resources to get a decent looking setup.
255 */
256 XmNborderWidth, 0,
257 XmNhighlightThickness, 0,
258 XmNshadowThickness, 0,
259 NULL);
260
261#ifdef FEAT_FOOTER
262 /*
263 * Create the Footer.
264 */
265 footer = XtVaCreateWidget("footer",
266 xmLabelGadgetClass, vimForm,
267 XmNalignment, XmALIGNMENT_BEGINNING,
268 XmNmarginHeight, 0,
269 XmNmarginWidth, 0,
270 XmNtraversalOn, False,
271 XmNrecomputeSize, False,
272 XmNleftAttachment, XmATTACH_FORM,
273 XmNleftOffset, 5,
274 XmNrightAttachment, XmATTACH_FORM,
275 XmNbottomAttachment, XmATTACH_FORM,
276 NULL);
277 gui_mch_set_footer((char_u *) "");
278#endif
279
280 /*
281 * Install the callbacks.
282 */
283 gui_x11_callbacks(textArea, vimForm);
284
285 /* Pretend we don't have input focus, we will get an event if we do. */
286 gui.in_focus = FALSE;
287}
288
289/*
290 * Called when the GUI is not going to start after all.
291 */
292 void
293gui_x11_destroy_widgets()
294{
295 textArea = NULL;
296#ifdef FEAT_MENU
297 menuBar = NULL;
298#endif
299}
300
301/*ARGSUSED*/
302 void
303gui_mch_set_text_area_pos(x, y, w, h)
304 int x;
305 int y;
306 int w;
307 int h;
308{
309#ifdef FEAT_TOOLBAR
310 /* Give keyboard focus to the textArea instead of the toolbar. */
311 gui_mch_reset_focus();
312#endif
313}
314
315 void
316gui_x11_set_back_color()
317{
318 if (textArea != NULL)
319#if (XmVersion >= 1002)
320 XmChangeColor(textArea, gui.back_pixel);
321#else
322 XtVaSetValues(textArea,
323 XmNbackground, gui.back_pixel,
324 NULL);
325#endif
326}
327
328/*
329 * Manage dialog centered on pointer. This could be used by the Athena code as
330 * well.
331 */
332static void manage_centered __ARGS((Widget dialog_child));
333
334static void
335manage_centered(dialog_child)
336 Widget dialog_child;
337{
338 Widget shell = XtParent(dialog_child);
339 Window root, child;
340 unsigned int mask;
341 unsigned int width, height, border_width, depth;
342 int x, y, win_x, win_y, maxX, maxY;
343 Boolean mappedWhenManaged;
344
345 /* Temporarily set value of XmNmappedWhenManaged
346 to stop the dialog from popping up right away */
347 XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, 0);
348 XtVaSetValues(shell, XmNmappedWhenManaged, False, 0);
349
350 XtManageChild(dialog_child);
351
352 /* Get the pointer position (x, y) */
353 XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child,
354 &x, &y, &win_x, &win_y, &mask);
355
356 /* Translate the pointer position (x, y) into a position for the new
357 window that will place the pointer at its center */
358 XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &win_x, &win_y,
359 &width, &height, &border_width, &depth);
360 width += 2 * border_width;
361 height += 2 * border_width;
362 x -= width / 2;
363 y -= height / 2;
364
365 /* Ensure that the dialog remains on screen */
366 maxX = XtScreen(shell)->width - width;
367 maxY = XtScreen(shell)->height - height;
368 if (x < 0)
369 x = 0;
370 if (x > maxX)
371 x = maxX;
372 if (y < 0)
373 y = 0;
374 if (y > maxY)
375 y = maxY;
376
377 /* Set desired window position in the DialogShell */
378 XtVaSetValues(shell, XmNx, x, XmNy, y, NULL);
379
380 /* Map the widget */
381 XtMapWidget(shell);
382
383 /* Restore the value of XmNmappedWhenManaged */
384 XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, 0);
385}
386
387#if defined(FEAT_MENU) || defined(FEAT_SUN_WORKSHOP) \
388 || defined(FEAT_GUI_DIALOG) || defined(PROTO)
389
390/*
391 * Encapsulate the way an XmFontList is created.
392 */
393 XmFontList
394gui_motif_create_fontlist(font)
395 XFontStruct *font;
396{
397 XmFontList font_list;
398
399# if (XmVersion <= 1001)
400 /* Motif 1.1 method */
401 font_list = XmFontListCreate(font, STRING_TAG);
402# else
403 /* Motif 1.2 method */
404 XmFontListEntry font_list_entry;
405
406 font_list_entry = XmFontListEntryCreate(STRING_TAG, XmFONT_IS_FONT,
407 (XtPointer)font);
408 font_list = XmFontListAppendEntry(NULL, font_list_entry);
409 XmFontListEntryFree(&font_list_entry);
410# endif
411 return font_list;
412}
413
414# if ((XmVersion > 1001) && defined(FEAT_XFONTSET)) || defined(PROTO)
415 XmFontList
416gui_motif_fontset2fontlist(fontset)
417 XFontSet *fontset;
418{
419 XmFontList font_list;
420
421 /* Motif 1.2 method */
422 XmFontListEntry font_list_entry;
423
424 font_list_entry = XmFontListEntryCreate(STRING_TAG,
425 XmFONT_IS_FONTSET,
426 (XtPointer)*fontset);
427 font_list = XmFontListAppendEntry(NULL, font_list_entry);
428 XmFontListEntryFree(&font_list_entry);
429 return font_list;
430}
431# endif
432
433#endif
434
435#if defined(FEAT_MENU) || defined(PROTO)
436/*
437 * Menu stuff.
438 */
439
440static void gui_motif_add_actext __ARGS((vimmenu_T *menu));
441#if (XmVersion >= 1002)
442static void toggle_tearoff __ARGS((Widget wid));
443static void gui_mch_recurse_tearoffs __ARGS((vimmenu_T *menu));
444#endif
445static void gui_mch_submenu_change __ARGS((vimmenu_T *mp, int colors));
446
447static void do_set_mnemonics __ARGS((int enable));
448static int menu_enabled = TRUE;
449
450 void
451gui_mch_enable_menu(flag)
452 int flag;
453{
454 if (flag)
455 {
456 XtManageChild(menuBar);
457#ifdef FEAT_TOOLBAR
458 if (XtIsManaged(XtParent(toolBar)))
459 {
460 /* toolBar is attached to top form */
461 XtVaSetValues(XtParent(toolBar),
462 XmNtopAttachment, XmATTACH_WIDGET,
463 XmNtopWidget, menuBar,
464 NULL);
465 XtVaSetValues(textAreaForm,
466 XmNtopAttachment, XmATTACH_WIDGET,
467 XmNtopWidget, XtParent(toolBar),
468 NULL);
469 }
470 else
471#endif
472 {
473 XtVaSetValues(textAreaForm,
474 XmNtopAttachment, XmATTACH_WIDGET,
475 XmNtopWidget, menuBar,
476 NULL);
477 }
478 }
479 else
480 {
481 XtUnmanageChild(menuBar);
482#ifdef FEAT_TOOLBAR
483 if (XtIsManaged(XtParent(toolBar)))
484 {
485 XtVaSetValues(XtParent(toolBar),
486 XmNtopAttachment, XmATTACH_FORM,
487 NULL);
488 XtVaSetValues(textAreaForm,
489 XmNtopAttachment, XmATTACH_WIDGET,
490 XmNtopWidget, XtParent(toolBar),
491 NULL);
492 }
493 else
494#endif
495 {
496 XtVaSetValues(textAreaForm,
497 XmNtopAttachment, XmATTACH_FORM,
498 NULL);
499 }
500 }
501
502}
503
504/*
505 * Enable or disable mnemonics for the toplevel menus.
506 */
507 void
508gui_motif_set_mnemonics(enable)
509 int enable;
510{
511 /*
512 * Don't enable menu mnemonics when the menu bar is disabled, LessTif
513 * crashes when using a mnemonic then.
514 */
515 if (!menu_enabled)
516 enable = FALSE;
517 do_set_mnemonics(enable);
518}
519
520 static void
521do_set_mnemonics(enable)
522 int enable;
523{
524 vimmenu_T *menu;
525
526 for (menu = root_menu; menu != NULL; menu = menu->next)
527 if (menu->id != (Widget)0)
528 XtVaSetValues(menu->id,
529 XmNmnemonic, enable ? menu->mnemonic : NUL,
530 NULL);
531}
532
533 void
534gui_mch_add_menu(menu, idx)
535 vimmenu_T *menu;
536 int idx;
537{
538 XmString label;
539 Widget shell;
540 vimmenu_T *parent = menu->parent;
541
542#ifdef MOTIF_POPUP
543 if (menu_is_popup(menu->name))
544 {
545 Arg arg[2];
546 int n = 0;
547
548 /* Only create the popup menu when it's actually used, otherwise there
549 * is a delay when using the right mouse button. */
550# if (XmVersion <= 1002)
551 if (mouse_model_popup())
552# endif
553 {
554 if (gui.menu_bg_pixel != INVALCOLOR)
555 {
556 XtSetArg(arg[0], XmNbackground, gui.menu_bg_pixel); n++;
557 }
558 if (gui.menu_fg_pixel != INVALCOLOR)
559 {
560 XtSetArg(arg[1], XmNforeground, gui.menu_fg_pixel); n++;
561 }
562 menu->submenu_id = XmCreatePopupMenu(textArea, "contextMenu",
563 arg, n);
564 menu->id = (Widget)0;
565 }
566 return;
567 }
568#endif
569
570 if (!menu_is_menubar(menu->name)
571 || (parent != NULL && parent->submenu_id == (Widget)0))
572 return;
573
574 label = XmStringCreate((char *)menu->dname, STRING_TAG);
575 if (label == NULL)
576 return;
577 menu->id = XtVaCreateWidget("subMenu",
578 xmCascadeButtonWidgetClass,
579 (parent == NULL) ? menuBar : parent->submenu_id,
580 XmNlabelString, label,
581 XmNmnemonic, p_wak[0] == 'n' ? NUL : menu->mnemonic,
582#if (XmVersion >= 1002)
583 /* submenu: count the tearoff item (needed for LessTif) */
584 XmNpositionIndex, idx + (parent != NULL
585 && tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0),
586#endif
587 NULL);
588 gui_motif_menu_colors(menu->id);
589 gui_motif_menu_fontlist(menu->id);
590 XmStringFree(label);
591
592 if (menu->id == (Widget)0) /* failed */
593 return;
594
595 /* add accelerator text */
596 gui_motif_add_actext(menu);
597
598 shell = XtVaCreateWidget("subMenuShell",
599 xmMenuShellWidgetClass, menu->id,
600 XmNwidth, 1,
601 XmNheight, 1,
602 NULL);
603 gui_motif_menu_colors(shell);
604 menu->submenu_id = XtVaCreateWidget("rowColumnMenu",
605 xmRowColumnWidgetClass, shell,
606 XmNrowColumnType, XmMENU_PULLDOWN,
607 NULL);
608 gui_motif_menu_colors(menu->submenu_id);
609
610 if (menu->submenu_id == (Widget)0) /* failed */
611 return;
612
613#if (XmVersion >= 1002)
614 /* Set the colors for the tear off widget */
615 toggle_tearoff(menu->submenu_id);
616#endif
617
618 XtVaSetValues(menu->id,
619 XmNsubMenuId, menu->submenu_id,
620 NULL);
621
622 /*
623 * The "Help" menu is a special case, and should be placed at the far
624 * right hand side of the menu-bar. It's recognized by its high priority.
625 */
626 if (parent == NULL && menu->priority >= 9999)
627 XtVaSetValues(menuBar,
628 XmNmenuHelpWidget, menu->id,
629 NULL);
630
631 /*
632 * When we add a top-level item to the menu bar, we can figure out how
633 * high the menu bar should be.
634 */
635 if (parent == NULL)
636 gui_mch_compute_menu_height(menu->id);
637}
638
639
640/*
641 * Add mnemonic and accelerator text to a menu button.
642 */
643 static void
644gui_motif_add_actext(menu)
645 vimmenu_T *menu;
646{
647 XmString label;
648
649 /* Add accelrator text, if there is one */
650 if (menu->actext != NULL && menu->id != (Widget)0)
651 {
652 label = XmStringCreate((char *)menu->actext, STRING_TAG);
653 if (label == NULL)
654 return;
655 XtVaSetValues(menu->id, XmNacceleratorText, label, NULL);
656 XmStringFree(label);
657 }
658}
659
660 void
661gui_mch_toggle_tearoffs(enable)
662 int enable;
663{
664#if (XmVersion >= 1002)
665 if (enable)
666 tearoff_val = (int)XmTEAR_OFF_ENABLED;
667 else
668 tearoff_val = (int)XmTEAR_OFF_DISABLED;
669 toggle_tearoff(menuBar);
670 gui_mch_recurse_tearoffs(root_menu);
671#endif
672}
673
674#if (XmVersion >= 1002)
675/*
676 * Set the tearoff for one menu widget on or off, and set the color of the
677 * tearoff widget.
678 */
679 static void
680toggle_tearoff(wid)
681 Widget wid;
682{
683 Widget w;
684
685 XtVaSetValues(wid, XmNtearOffModel, tearoff_val, NULL);
686 if (tearoff_val == (int)XmTEAR_OFF_ENABLED
687 && (w = XmGetTearOffControl(wid)) != (Widget)0)
688 gui_motif_menu_colors(w);
689}
690
691 static void
692gui_mch_recurse_tearoffs(menu)
693 vimmenu_T *menu;
694{
695 while (menu != NULL)
696 {
697 if (!menu_is_popup(menu->name))
698 {
699 if (menu->submenu_id != (Widget)0)
700 toggle_tearoff(menu->submenu_id);
701 gui_mch_recurse_tearoffs(menu->children);
702 }
703 menu = menu->next;
704 }
705}
706#endif
707
708 int
709gui_mch_text_area_extra_height()
710{
711 Dimension shadowHeight;
712
713 XtVaGetValues(textAreaForm, XmNshadowThickness, &shadowHeight, NULL);
714 return shadowHeight;
715}
716
717/*
718 * Compute the height of the menu bar.
719 * We need to check all the items for their position and height, for the case
720 * there are several rows, and/or some characters extend higher or lower.
721 */
722 void
723gui_mch_compute_menu_height(id)
724 Widget id; /* can be NULL when deleting menu */
725{
726 Dimension y, maxy;
727 Dimension margin, shadow;
728 vimmenu_T *mp;
729 static Dimension height = 21; /* normal height of a menu item */
730
731 /*
732 * Get the height of the new item, before managing it, because it will
733 * still reflect the font size. After managing it depends on the menu
734 * height, which is what we just wanted to get!.
735 */
736 if (id != (Widget)0)
737 XtVaGetValues(id, XmNheight, &height, NULL);
738
739 /* Find any menu Widget, to be able to call XtManageChild() */
740 else
741 for (mp = root_menu; mp != NULL; mp = mp->next)
742 if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
743 {
744 id = mp->id;
745 break;
746 }
747
748 /*
749 * Now manage the menu item, to make them all be positioned (makes an
750 * extra row when needed, removes it when not needed).
751 */
752 if (id != (Widget)0)
753 XtManageChild(id);
754
755 /*
756 * Now find the menu item that is the furthest down, and get it's position.
757 */
758 maxy = 0;
759 for (mp = root_menu; mp != NULL; mp = mp->next)
760 {
761 if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
762 {
763 XtVaGetValues(mp->id, XmNy, &y, NULL);
764 if (y > maxy)
765 maxy = y;
766 }
767 }
768
769 XtVaGetValues(menuBar,
770 XmNmarginHeight, &margin,
771 XmNshadowThickness, &shadow,
772 NULL);
773
774 /*
775 * This computation is the result of trial-and-error:
776 * maxy = The maximum position of an item; required for when there are
777 * two or more rows
778 * height = height of an item, before managing it; Hopefully this will
779 * change with the font height. Includes shadow-border.
780 * shadow = shadow-border; must be subtracted from the height.
781 * margin = margin around the menu buttons; Must be added.
782 * Add 4 for the underlining of shortcut keys.
783 */
784 gui.menu_height = maxy + height - 2 * shadow + 2 * margin + 4;
785
786#ifdef LESSTIF_VERSION
787 /* Somehow the menu bar doesn't resize automatically. Set it here,
788 * even though this is a catch 22. Don't do this when starting up,
789 * somehow the menu gets very high then. */
790 if (gui.shell_created)
791 XtVaSetValues(menuBar, XmNheight, gui.menu_height, NULL);
792#endif
793}
794
795 void
796gui_mch_add_menu_item(menu, idx)
797 vimmenu_T *menu;
798 int idx;
799{
800 XmString label;
801 vimmenu_T *parent = menu->parent;
802
803# ifdef EBCDIC
804 menu->mnemonic = 0;
805# endif
806
807# if (XmVersion <= 1002)
808 /* Don't add Popup menu items when the popup menu isn't used. */
809 if (menu_is_child_of_popup(menu) && !mouse_model_popup())
810 return;
811# endif
812
813# ifdef FEAT_TOOLBAR
814 if (menu_is_toolbar(parent->name))
815 {
816 WidgetClass type;
817 XmString xms = NULL; /* fallback label if pixmap not found */
818 int n;
819 Arg args[18];
820
821 n = 0;
822 if (menu_is_separator(menu->name))
823 {
824 char *cp;
825 Dimension wid;
826
827 /*
828 * A separator has the format "-sep%d[:%d]-". The optional :%d is
829 * a width specifier. If no width is specified then we choose one.
830 */
831 cp = (char *)vim_strchr(menu->name, ':');
832 if (cp != NULL)
833 wid = (Dimension)atoi(++cp);
834 else
835 wid = 4;
836
837#if 0
838 /* We better use a FormWidget here, since it's far more
839 * flexible in terms of size. */
840 type = xmFormWidgetClass;
841 XtSetArg(args[n], XmNwidth, wid); n++;
842#else
843 type = xmSeparatorWidgetClass;
844 XtSetArg(args[n], XmNwidth, wid); n++;
845 XtSetArg(args[n], XmNminWidth, wid); n++;
846 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
847 XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
848#endif
849 }
850 else
851 {
852 get_toolbar_pixmap(menu, &menu->image, &menu->image_ins);
853 /* Set the label here, so that we can switch between icons/text
854 * by changing the XmNlabelType resource. */
855 xms = XmStringCreate((char *)menu->dname, STRING_TAG);
856 XtSetArg(args[n], XmNlabelString, xms); n++;
857
858#ifndef FEAT_SUN_WORKSHOP
859
860 /* Without shadows one can't sense whatever the button has been
861 * pressed or not! However we wan't to save a bit of space...
862 */
863 XtSetArg(args[n], XmNhighlightThickness, 0); n++;
864 XtSetArg(args[n], XmNhighlightOnEnter, True); n++;
865 XtSetArg(args[n], XmNmarginWidth, 0); n++;
866 XtSetArg(args[n], XmNmarginHeight, 0); n++;
867#endif
868 if (menu->image == 0)
869 {
870 XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
871 XtSetArg(args[n], XmNlabelPixmap, 0); n++;
872 XtSetArg(args[n], XmNlabelInsensitivePixmap, 0); n++;
873 }
874 else
875 {
876 XtSetArg(args[n], XmNlabelPixmap, menu->image); n++;
877 XtSetArg(args[n], XmNlabelInsensitivePixmap, menu->image_ins); n++;
878 XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
879 }
880 type = xmPushButtonWidgetClass;
881 XtSetArg(args[n], XmNwidth, 80); n++;
882 }
883
884 XtSetArg(args[n], XmNpositionIndex, idx); n++;
885 if (menu->id == NULL)
886 {
887 menu->id = XtCreateManagedWidget((char *)menu->dname,
888 type, toolBar, args, n);
889 if (menu->id != NULL && type == xmPushButtonWidgetClass)
890 {
891 XtAddCallback(menu->id,
892 XmNactivateCallback, gui_x11_menu_cb, menu);
893
894# ifdef FEAT_FOOTER
895 XtAddEventHandler(menu->id, EnterWindowMask, False,
896 toolbarbutton_enter_cb, menu);
897 XtAddEventHandler(menu->id, LeaveWindowMask, False,
898 toolbarbutton_leave_cb, menu);
899# endif
900 }
901 }
902 else
903 XtSetValues(menu->id, args, n);
904 if (xms != NULL)
905 XmStringFree(xms);
906
907#ifdef FEAT_BEVAL
908 gui_mch_menu_set_tip(menu);
909#endif
910
911 menu->parent = parent;
912 menu->submenu_id = NULL;
913 /* When adding first item to toolbar it might have to be enabled .*/
914 if (!XtIsManaged(XtParent(toolBar))
915 && vim_strchr(p_go, GO_TOOLBAR) != NULL)
916 gui_mch_show_toolbar(TRUE);
917 gui.toolbar_height = gui_mch_compute_toolbar_height();
918 return;
919 } /* toolbar menu item */
920# endif
921
922 /* No parent, must be a non-menubar menu */
923 if (parent->submenu_id == (Widget)0)
924 return;
925
926 menu->submenu_id = (Widget)0;
927
928 /* Add menu separator */
929 if (menu_is_separator(menu->name))
930 {
931 menu->id = XtVaCreateWidget("subMenu",
932 xmSeparatorGadgetClass, parent->submenu_id,
933#if (XmVersion >= 1002)
934 /* count the tearoff item (needed for LessTif) */
935 XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
936 ? 1 : 0),
937#endif
938 NULL);
939 gui_motif_menu_colors(menu->id);
940 return;
941 }
942
943 label = XmStringCreate((char *)menu->dname, STRING_TAG);
944 if (label == NULL)
945 return;
946 menu->id = XtVaCreateWidget("subMenu",
947 xmPushButtonWidgetClass, parent->submenu_id,
948 XmNlabelString, label,
949 XmNmnemonic, menu->mnemonic,
950#if (XmVersion >= 1002)
951 /* count the tearoff item (needed for LessTif) */
952 XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
953 ? 1 : 0),
954#endif
955 NULL);
956 gui_motif_menu_colors(menu->id);
957 gui_motif_menu_fontlist(menu->id);
958 XmStringFree(label);
959
960 if (menu->id != (Widget)0)
961 {
962 XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb,
963 (XtPointer)menu);
964 /* add accelerator text */
965 gui_motif_add_actext(menu);
966 }
967}
968
969#if (XmVersion <= 1002) || defined(PROTO)
970/*
971 * This function will destroy/create the popup menus dynamically,
972 * according to the value of 'mousemodel'.
973 * This will fix the "right mouse button freeze" that occurs when
974 * there exists a popup menu but it isn't managed.
975 */
976 void
977gui_motif_update_mousemodel(menu)
978 vimmenu_T *menu;
979{
980 int idx = 0;
981
982 /* When GUI hasn't started the menus have not been created. */
983 if (!gui.in_use)
984 return;
985
986 while (menu)
987 {
988 if (menu->children != NULL)
989 {
990 if (menu_is_popup(menu->name))
991 {
992 if (mouse_model_popup())
993 {
994 /* Popup menu will be used. Create the popup menus. */
995 gui_mch_add_menu(menu, idx);
996 gui_motif_update_mousemodel(menu->children);
997 }
998 else
999 {
1000 /* Popup menu will not be used. Destroy the popup menus. */
1001 gui_motif_update_mousemodel(menu->children);
1002 gui_mch_destroy_menu(menu);
1003 }
1004 }
1005 }
1006 else if (menu_is_child_of_popup(menu))
1007 {
1008 if (mouse_model_popup())
1009 gui_mch_add_menu_item(menu, idx);
1010 else
1011 gui_mch_destroy_menu(menu);
1012 }
1013 menu = menu->next;
1014 ++idx;
1015 }
1016}
1017#endif
1018
1019 void
1020gui_mch_new_menu_colors()
1021{
1022 if (menuBar == (Widget)0)
1023 return;
1024 gui_motif_menu_colors(menuBar);
1025#ifdef FEAT_TOOLBAR
1026 gui_motif_menu_colors(toolBarFrame);
1027 gui_motif_menu_colors(toolBar);
1028#endif
1029
1030 gui_mch_submenu_change(root_menu, TRUE);
1031}
1032
1033 void
1034gui_mch_new_menu_font()
1035{
1036 if (menuBar == (Widget)0)
1037 return;
1038 gui_mch_submenu_change(root_menu, FALSE);
1039 {
1040 Dimension height;
1041 Position w, h;
1042
1043 XtVaGetValues(menuBar, XmNheight, &height, NULL);
1044 gui.menu_height = height;
1045
1046 XtVaGetValues(vimShell, XtNwidth, &w, XtNheight, &h, NULL);
1047 gui_resize_shell(w, h
1048#ifdef FEAT_XIM
1049 - xim_get_status_area_height()
1050#endif
1051 );
1052 }
1053 gui_set_shellsize(FALSE, TRUE);
1054 ui_new_shellsize();
1055}
1056
1057#if defined(FEAT_BEVAL) || defined(PROTO)
1058 void
1059gui_mch_new_tooltip_font()
1060{
1061# ifdef FEAT_TOOLBAR
1062 vimmenu_T *menu;
1063
1064 if (toolBar == (Widget)0)
1065 return;
1066
1067 menu = gui_find_menu((char_u *)"ToolBar");
1068 if (menu != NULL)
1069 gui_mch_submenu_change(menu, FALSE);
1070# endif
1071}
1072
1073 void
1074gui_mch_new_tooltip_colors()
1075{
1076# ifdef FEAT_TOOLBAR
1077 vimmenu_T *toolbar;
1078
1079 if (toolBar == (Widget)0)
1080 return;
1081
1082 toolbar = gui_find_menu((char_u *)"ToolBar");
1083 if (toolbar != NULL)
1084 gui_mch_submenu_change(toolbar, TRUE);
1085# endif
1086}
1087#endif
1088
1089 static void
1090gui_mch_submenu_change(menu, colors)
1091 vimmenu_T *menu;
1092 int colors; /* TRUE for colors, FALSE for font */
1093{
1094 vimmenu_T *mp;
1095
1096 for (mp = menu; mp != NULL; mp = mp->next)
1097 {
1098 if (mp->id != (Widget)0)
1099 {
1100 if (colors)
1101 {
1102 gui_motif_menu_colors(mp->id);
1103#ifdef FEAT_TOOLBAR
1104 /* For a toolbar item: Free the pixmap and allocate a new one,
1105 * so that the background color is right. */
1106 if (mp->image != (Pixmap)0)
1107 {
1108 XFreePixmap(gui.dpy, mp->image);
1109 XFreePixmap(gui.dpy, mp->image_ins);
1110 get_toolbar_pixmap(mp, &mp->image, &mp->image_ins);
1111 if (mp->image != (Pixmap)0)
1112 XtVaSetValues(mp->id,
1113 XmNlabelPixmap, mp->image,
1114 XmNlabelInsensitivePixmap, mp->image_ins,
1115 NULL);
1116 }
1117# ifdef FEAT_BEVAL
1118 /* If we have a tooltip, then we need to change it's font */
1119 if (mp->tip != NULL)
1120 {
1121 Arg args[2];
1122
1123 args[0].name = XmNbackground;
1124 args[0].value = gui.tooltip_bg_pixel;
1125 args[1].name = XmNforeground;
1126 args[1].value = gui.tooltip_fg_pixel;
1127 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1128 }
1129# endif
1130#endif
1131 }
1132 else
1133 {
1134 gui_motif_menu_fontlist(mp->id);
1135#ifdef FEAT_BEVAL
1136 /* If we have a tooltip, then we need to change it's font */
1137 if (mp->tip != NULL)
1138 {
1139 Arg args[1];
1140
1141 args[0].name = XmNfontList;
1142 args[0].value = (XtArgVal)gui_motif_fontset2fontlist(
1143 &gui.tooltip_fontset);
1144 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1145 }
1146#endif
1147 }
1148 }
1149
1150 if (mp->children != NULL)
1151 {
1152#if (XmVersion >= 1002)
1153 /* Set the colors/font for the tear off widget */
1154 if (mp->submenu_id != (Widget)0)
1155 {
1156 if (colors)
1157 gui_motif_menu_colors(mp->submenu_id);
1158 else
1159 gui_motif_menu_fontlist(mp->submenu_id);
1160 toggle_tearoff(mp->submenu_id);
1161 }
1162#endif
1163 /* Set the colors for the children */
1164 gui_mch_submenu_change(mp->children, colors);
1165 }
1166 }
1167}
1168
1169/*
1170 * Destroy the machine specific menu widget.
1171 */
1172 void
1173gui_mch_destroy_menu(menu)
1174 vimmenu_T *menu;
1175{
1176 /* Please be sure to destroy the parent widget first (i.e. menu->id).
1177 * On the other hand, problems have been reported that the submenu must be
1178 * deleted first...
1179 *
1180 * This code should be basically identical to that in the file gui_athena.c
1181 * because they are both Xt based.
1182 */
1183 if (menu->submenu_id != (Widget)0)
1184 {
1185 XtDestroyWidget(menu->submenu_id);
1186 menu->submenu_id = (Widget)0;
1187 }
1188
1189 if (menu->id != (Widget)0)
1190 {
1191 Widget parent;
1192
1193 parent = XtParent(menu->id);
1194#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)
1195 if ((parent == toolBar) && (menu->tip != NULL))
1196 {
1197 /* We try to destroy this before the actual menu, because there are
1198 * callbacks, etc. that will be unregistered during the tooltip
1199 * destruction.
1200 *
1201 * If you call "gui_mch_destroy_beval_area()" after destroying
1202 * menu->id, then the tooltip's window will have already been
1203 * deallocated by Xt, and unknown behaviour will ensue (probably
1204 * a core dump).
1205 */
1206 gui_mch_destroy_beval_area(menu->tip);
1207 menu->tip = NULL;
1208 }
1209#endif
1210 XtDestroyWidget(menu->id);
1211 menu->id = (Widget)0;
1212 if (parent == menuBar)
1213 gui_mch_compute_menu_height((Widget)0);
1214#ifdef FEAT_TOOLBAR
1215 else if (parent == toolBar)
1216 {
1217 Cardinal num_children;
1218
1219 /* When removing last toolbar item, don't display the toolbar. */
1220 XtVaGetValues(toolBar, XmNnumChildren, &num_children, NULL);
1221 if (num_children == 0)
1222 gui_mch_show_toolbar(FALSE);
1223 else
1224 gui.toolbar_height = gui_mch_compute_toolbar_height();
1225 }
1226#endif
1227 }
1228}
1229
1230/* ARGSUSED */
1231 void
1232gui_mch_show_popupmenu(menu)
1233 vimmenu_T *menu;
1234{
1235#ifdef MOTIF_POPUP
1236 XmMenuPosition(menu->submenu_id, gui_x11_get_last_mouse_event());
1237 XtManageChild(menu->submenu_id);
1238#endif
1239}
1240
1241#endif /* FEAT_MENU */
1242
1243/*
1244 * Set the menu and scrollbar colors to their default values.
1245 */
1246 void
1247gui_mch_def_colors()
1248{
1249 if (gui.in_use)
1250 {
1251 /* Use the values saved when starting up. These should come from the
1252 * window manager or a resources file. */
1253 gui.menu_fg_pixel = gui.menu_def_fg_pixel;
1254 gui.menu_bg_pixel = gui.menu_def_bg_pixel;
1255 gui.scroll_fg_pixel = gui.scroll_def_fg_pixel;
1256 gui.scroll_bg_pixel = gui.scroll_def_bg_pixel;
1257#ifdef FEAT_BEVAL
1258 gui.tooltip_fg_pixel =
1259 gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
1260 gui.tooltip_bg_pixel =
1261 gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
1262#endif
1263 }
1264}
1265
1266
1267/*
1268 * Scrollbar stuff.
1269 */
1270
1271 void
1272gui_mch_set_scrollbar_thumb(sb, val, size, max)
1273 scrollbar_T *sb;
1274 long val;
1275 long size;
1276 long max;
1277{
1278 if (sb->id != (Widget)0)
1279 XtVaSetValues(sb->id,
1280 XmNvalue, val,
1281 XmNsliderSize, size,
1282 XmNpageIncrement, (size > 2 ? size - 2 : 1),
1283 XmNmaximum, max + 1, /* Motif has max one past the end */
1284 NULL);
1285}
1286
1287 void
1288gui_mch_set_scrollbar_pos(sb, x, y, w, h)
1289 scrollbar_T *sb;
1290 int x;
1291 int y;
1292 int w;
1293 int h;
1294{
1295 if (sb->id != (Widget)0)
1296 {
1297 if (sb->type == SBAR_LEFT || sb->type == SBAR_RIGHT)
1298 {
1299 if (y == 0)
1300 h -= gui.border_offset;
1301 else
1302 y -= gui.border_offset;
1303 XtVaSetValues(sb->id,
1304 XmNtopOffset, y,
1305 XmNbottomOffset, -y - h,
1306 XmNwidth, w,
1307 NULL);
1308 }
1309 else
1310 XtVaSetValues(sb->id,
1311 XmNtopOffset, y,
1312 XmNleftOffset, x,
1313 XmNrightOffset, gui.which_scrollbars[SBAR_RIGHT]
1314 ? gui.scrollbar_width : 0,
1315 XmNheight, h,
1316 NULL);
1317 XtManageChild(sb->id);
1318 }
1319}
1320
1321 void
1322gui_mch_enable_scrollbar(sb, flag)
1323 scrollbar_T *sb;
1324 int flag;
1325{
1326 Arg args[16];
1327 int n;
1328
1329 if (sb->id != (Widget)0)
1330 {
1331 n = 0;
1332 if (flag)
1333 {
1334 switch (sb->type)
1335 {
1336 case SBAR_LEFT:
1337 XtSetArg(args[n], XmNleftOffset, gui.scrollbar_width); n++;
1338 break;
1339
1340 case SBAR_RIGHT:
1341 XtSetArg(args[n], XmNrightOffset, gui.scrollbar_width); n++;
1342 break;
1343
1344 case SBAR_BOTTOM:
1345 XtSetArg(args[n], XmNbottomOffset, gui.scrollbar_height);n++;
1346 break;
1347 }
1348 XtSetValues(textArea, args, n);
1349 XtManageChild(sb->id);
1350 }
1351 else
1352 {
1353 if (!gui.which_scrollbars[sb->type])
1354 {
1355 /* The scrollbars of this type are all disabled, adjust the
1356 * textArea attachment offset. */
1357 switch (sb->type)
1358 {
1359 case SBAR_LEFT:
1360 XtSetArg(args[n], XmNleftOffset, 0); n++;
1361 break;
1362
1363 case SBAR_RIGHT:
1364 XtSetArg(args[n], XmNrightOffset, 0); n++;
1365 break;
1366
1367 case SBAR_BOTTOM:
1368 XtSetArg(args[n], XmNbottomOffset, 0);n++;
1369 break;
1370 }
1371 XtSetValues(textArea, args, n);
1372 }
1373 XtUnmanageChild(sb->id);
1374 }
1375 }
1376}
1377
1378 void
1379gui_mch_create_scrollbar(sb, orient)
1380 scrollbar_T *sb;
1381 int orient; /* SBAR_VERT or SBAR_HORIZ */
1382{
1383 Arg args[16];
1384 int n;
1385
1386 n = 0;
1387 XtSetArg(args[n], XmNshadowThickness, 1); n++;
1388 XtSetArg(args[n], XmNminimum, 0); n++;
1389 XtSetArg(args[n], XmNorientation,
1390 (orient == SBAR_VERT) ? XmVERTICAL : XmHORIZONTAL); n++;
1391
1392 switch (sb->type)
1393 {
1394 case SBAR_LEFT:
1395 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1396 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
1397 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1398 break;
1399
1400 case SBAR_RIGHT:
1401 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1402 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
1403 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1404 break;
1405
1406 case SBAR_BOTTOM:
1407 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1408 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1409 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1410 break;
1411 }
1412
1413 sb->id = XtCreateWidget("scrollBar",
1414 xmScrollBarWidgetClass, textAreaForm, args, n);
1415
1416 /* Remember the default colors, needed for ":hi clear". */
1417 if (gui.scroll_def_bg_pixel == (guicolor_T)0
1418 && gui.scroll_def_fg_pixel == (guicolor_T)0)
1419 XtVaGetValues(sb->id,
1420 XmNbackground, &gui.scroll_def_bg_pixel,
1421 XmNforeground, &gui.scroll_def_fg_pixel,
1422 NULL);
1423
1424 if (sb->id != (Widget)0)
1425 {
1426 gui_mch_set_scrollbar_colors(sb);
1427 XtAddCallback(sb->id, XmNvalueChangedCallback,
1428 scroll_cb, (XtPointer)sb->ident);
1429 XtAddCallback(sb->id, XmNdragCallback,
1430 scroll_cb, (XtPointer)sb->ident);
1431 XtAddEventHandler(sb->id, KeyPressMask, FALSE, gui_x11_key_hit_cb,
1432 (XtPointer)0);
1433 }
1434}
1435
1436#if defined(FEAT_WINDOWS) || defined(PROTO)
1437 void
1438gui_mch_destroy_scrollbar(sb)
1439 scrollbar_T *sb;
1440{
1441 if (sb->id != (Widget)0)
1442 XtDestroyWidget(sb->id);
1443}
1444#endif
1445
1446 void
1447gui_mch_set_scrollbar_colors(sb)
1448 scrollbar_T *sb;
1449{
1450 if (sb->id != (Widget)0)
1451 {
1452 if (gui.scroll_bg_pixel != INVALCOLOR)
1453 {
1454#if (XmVersion>=1002)
1455 XmChangeColor(sb->id, gui.scroll_bg_pixel);
1456#else
1457 XtVaSetValues(sb->id,
1458 XmNtroughColor, gui.scroll_bg_pixel,
1459 NULL);
1460#endif
1461 }
1462
1463 if (gui.scroll_fg_pixel != INVALCOLOR)
1464 XtVaSetValues(sb->id,
1465 XmNforeground, gui.scroll_fg_pixel,
1466#if (XmVersion<1002)
1467 XmNbackground, gui.scroll_fg_pixel,
1468#endif
1469 NULL);
1470 }
1471
1472 /* This is needed for the rectangle below the vertical scrollbars. */
1473 if (sb == &gui.bottom_sbar && textAreaForm != (Widget)0)
1474 gui_motif_scroll_colors(textAreaForm);
1475}
1476
1477/*
1478 * Miscellaneous stuff:
1479 */
1480
1481 Window
1482gui_x11_get_wid()
1483{
1484 return(XtWindow(textArea));
1485}
1486
1487
1488#if defined(FEAT_BROWSE) || defined(PROTO)
1489
1490/*
1491 * file selector related stuff
1492 */
1493
1494#include <Xm/FileSB.h>
1495#include <Xm/XmStrDefs.h>
1496
1497typedef struct dialog_callback_arg
1498{
1499 char * args; /* not used right now */
1500 int id;
1501} dcbarg_T;
1502
1503static Widget dialog_wgt;
1504static char *browse_fname = NULL;
1505static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;
1506 /* used to set up XmStrings */
1507
1508static void DialogCancelCB __ARGS((Widget, XtPointer, XtPointer));
1509static void DialogAcceptCB __ARGS((Widget, XtPointer, XtPointer));
1510
1511/*
1512 * This function is used to translate the predefined label text of the
1513 * precomposed dialogs. We do this explicitly to allow:
1514 *
1515 * - usage of gettext for translation, as in all the other places.
1516 *
1517 * - equalize the messages between different GUI implementations as far as
1518 * possible.
1519 */
1520static void set_predefined_label __ARGS((Widget parent, String name, char * new_label));
1521
1522static void
1523set_predefined_label(parent, name, new_label)
1524 Widget parent;
1525 String name;
1526 char * new_label;
1527{
1528 XmString str;
1529 Widget w;
1530
1531 w = XtNameToWidget(parent, name);
1532
1533 if (!w)
1534 return;
1535
1536 str = XmStringCreate(new_label, STRING_TAG);
1537
1538 if (str)
1539 {
1540 XtVaSetValues(w, XmNlabelString, str, NULL);
1541 XmStringFree(str);
1542 }
1543}
1544
1545/*
1546 * Put up a file requester.
1547 * Returns the selected name in allocated memory, or NULL for Cancel.
1548 */
1549/* ARGSUSED */
1550 char_u *
1551gui_mch_browse(saving, title, dflt, ext, initdir, filter)
1552 int saving; /* select file to write */
1553 char_u *title; /* title for the window */
1554 char_u *dflt; /* default name */
1555 char_u *ext; /* not used (extension added) */
1556 char_u *initdir; /* initial directory, NULL for current dir */
1557 char_u *filter; /* file name filter */
1558{
1559 char_u dirbuf[MAXPATHL];
1560 char_u dfltbuf[MAXPATHL];
1561 char_u *pattern;
1562 char_u *tofree = NULL;
1563
1564 dialog_wgt = XmCreateFileSelectionDialog(vimShell, (char *)title, NULL, 0);
1565
1566 if (initdir == NULL || *initdir == NUL)
1567 {
1568 mch_dirname(dirbuf, MAXPATHL);
1569 initdir = dirbuf;
1570 }
1571
1572 if (dflt == NULL)
1573 dflt = (char_u *)"";
1574 else if (STRLEN(initdir) + STRLEN(dflt) + 2 < MAXPATHL)
1575 {
1576 /* The default selection should be the full path, "dflt" is only the
1577 * file name. */
1578 STRCPY(dfltbuf, initdir);
1579 add_pathsep(dfltbuf);
1580 STRCAT(dfltbuf, dflt);
1581 dflt = dfltbuf;
1582 }
1583
1584 /* Can only use one pattern for a file name. Get the first pattern out of
1585 * the filter. An empty pattern means everything matches. */
1586 if (filter == NULL)
1587 pattern = (char_u *)"";
1588 else
1589 {
1590 char_u *s, *p;
1591
1592 s = filter;
1593 for (p = filter; *p != NUL; ++p)
1594 {
1595 if (*p == '\t') /* end of description, start of pattern */
1596 s = p + 1;
1597 if (*p == ';' || *p == '\n') /* end of (first) pattern */
1598 break;
1599 }
1600 pattern = vim_strnsave(s, p - s);
1601 tofree = pattern;
1602 if (pattern == NULL)
1603 pattern = (char_u *)"";
1604 }
1605
1606 XtVaSetValues(dialog_wgt,
1607 XtVaTypedArg,
1608 XmNdirectory, XmRString, (char *)initdir, STRLEN(initdir) + 1,
1609 XtVaTypedArg,
1610 XmNdirSpec, XmRString, (char *)dflt, STRLEN(dflt) + 1,
1611 XtVaTypedArg,
1612 XmNpattern, XmRString, (char *)pattern, STRLEN(pattern) + 1,
1613 XtVaTypedArg,
1614 XmNdialogTitle, XmRString, (char *)title, STRLEN(title) + 1,
1615 NULL);
1616
1617 set_predefined_label(dialog_wgt, "Apply", _("Filter"));
1618 set_predefined_label(dialog_wgt, "Cancel", _("Cancel"));
1619 set_predefined_label(dialog_wgt, "Dir", _("Directories"));
1620 set_predefined_label(dialog_wgt, "FilterLabel", _("Filter"));
1621 set_predefined_label(dialog_wgt, "Help", _("Help"));
1622 set_predefined_label(dialog_wgt, "Items", _("Files"));
1623 set_predefined_label(dialog_wgt, "OK", _("OK"));
1624 set_predefined_label(dialog_wgt, "Selection", _("Selection"));
1625
1626 gui_motif_menu_colors(dialog_wgt);
1627 if (gui.scroll_bg_pixel != INVALCOLOR)
1628 XtVaSetValues(dialog_wgt, XmNtroughColor, gui.scroll_bg_pixel, NULL);
1629
1630 XtAddCallback(dialog_wgt, XmNokCallback, DialogAcceptCB, (XtPointer)0);
1631 XtAddCallback(dialog_wgt, XmNcancelCallback, DialogCancelCB, (XtPointer)0);
1632 /* We have no help in this window, so hide help button */
1633 XtUnmanageChild(XmFileSelectionBoxGetChild(dialog_wgt,
1634 (unsigned char)XmDIALOG_HELP_BUTTON));
1635
1636 manage_centered(dialog_wgt);
1637
1638 /* sit in a loop until the dialog box has gone away */
1639 do
1640 {
1641 XtAppProcessEvent(XtWidgetToApplicationContext(dialog_wgt),
1642 (XtInputMask)XtIMAll);
1643 } while (XtIsManaged(dialog_wgt));
1644
1645 XtDestroyWidget(dialog_wgt);
1646 vim_free(tofree);
1647
1648 if (browse_fname == NULL)
1649 return NULL;
1650 return vim_strsave((char_u *)browse_fname);
1651}
1652
1653/*
1654 * The code below was originally taken from
1655 * /usr/examples/motif/xmsamplers/xmeditor.c
1656 * on Digital Unix 4.0d, but heavily modified.
1657 */
1658
1659/*
1660 * Process callback from Dialog cancel actions.
1661 */
1662/* ARGSUSED */
1663 static void
1664DialogCancelCB(w, client_data, call_data)
1665 Widget w; /* widget id */
1666 XtPointer client_data; /* data from application */
1667 XtPointer call_data; /* data from widget class */
1668{
1669 if (browse_fname != NULL)
1670 {
1671 XtFree(browse_fname);
1672 browse_fname = NULL;
1673 }
1674 XtUnmanageChild(dialog_wgt);
1675}
1676
1677/*
1678 * Process callback from Dialog actions.
1679 */
1680/* ARGSUSED */
1681 static void
1682DialogAcceptCB(w, client_data, call_data)
1683 Widget w; /* widget id */
1684 XtPointer client_data; /* data from application */
1685 XtPointer call_data; /* data from widget class */
1686{
1687 XmFileSelectionBoxCallbackStruct *fcb;
1688
1689 if (browse_fname != NULL)
1690 {
1691 XtFree(browse_fname);
1692 browse_fname = NULL;
1693 }
1694 fcb = (XmFileSelectionBoxCallbackStruct *)call_data;
1695
1696 /* get the filename from the file selection box */
1697 XmStringGetLtoR(fcb->value, charset, &browse_fname);
1698
1699 /* popdown the file selection box */
1700 XtUnmanageChild(dialog_wgt);
1701}
1702
1703#endif /* FEAT_BROWSE */
1704
1705#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
1706
1707static int dialogStatus;
1708
1709static void keyhit_callback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
1710static void butproc __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
1711
1712/*
1713 * Callback function for the textfield. When CR is hit this works like
1714 * hitting the "OK" button, ESC like "Cancel".
1715 */
1716/* ARGSUSED */
1717 static void
1718keyhit_callback(w, client_data, event, cont)
1719 Widget w;
1720 XtPointer client_data;
1721 XEvent *event;
1722 Boolean *cont;
1723{
1724 char buf[2];
1725 KeySym key_sym;
1726
1727 if (XLookupString(&(event->xkey), buf, 2, &key_sym, NULL) == 1)
1728 {
1729 if (*buf == CAR)
1730 dialogStatus = 1;
1731 else if (*buf == ESC)
1732 dialogStatus = 2;
1733 }
1734 if ((key_sym == XK_Left || key_sym == XK_Right)
1735 && !(event->xkey.state & ShiftMask))
1736 XmTextFieldClearSelection(w, XtLastTimestampProcessed(gui.dpy));
1737}
1738
1739/* ARGSUSED */
1740 static void
1741butproc(w, client_data, call_data)
1742 Widget w;
1743 XtPointer client_data;
1744 XtPointer call_data;
1745{
1746 dialogStatus = (int)(long)client_data + 1;
1747}
1748
1749static void gui_motif_set_fontlist __ARGS((Widget wg));
1750
1751/*
1752 * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget.
1753 */
1754 static void
1755gui_motif_set_fontlist(wg)
1756 Widget wg;
1757{
1758 XmFontList fl;
1759
1760 fl =
1761#ifdef FEAT_XFONTSET
1762 gui.fontset != NOFONTSET ?
1763 gui_motif_fontset2fontlist((XFontSet *)&gui.fontset)
1764 :
1765#endif
1766 gui_motif_create_fontlist((XFontStruct *)gui.norm_font);
1767 if (fl != NULL)
1768 {
1769 XtVaSetValues(wg, XmNfontList, fl, NULL);
1770 XmFontListFree(fl);
1771 }
1772}
1773
1774#ifdef HAVE_XPM
1775
1776static Widget create_pixmap_label(Widget parent, String name, char **data, ArgList args, Cardinal arg);
1777
1778 static Widget
1779create_pixmap_label(parent, name, data, args, arg)
1780 Widget parent;
1781 String name;
1782 char **data;
1783 ArgList args;
1784 Cardinal arg;
1785{
1786 Widget label;
1787 Display *dsp;
1788 Screen *scr;
1789 int depth;
1790 Pixmap pixmap = 0;
1791 XpmAttributes attr;
1792 Boolean rs;
1793 XpmColorSymbol color[5] =
1794 {
1795 {"none", NULL, 0},
1796 {"iconColor1", NULL, 0},
1797 {"bottomShadowColor", NULL, 0},
1798 {"topShadowColor", NULL, 0},
1799 {"selectColor", NULL, 0}
1800 };
1801
1802 label = XmCreateLabelGadget(parent, name, args, arg);
1803
1804 /*
1805 * We need to be carefull here, since in case of gadgets, there is
1806 * no way to get the background color directly from the widget itself.
1807 * In such cases we get it from The Core part of his parent instead.
1808 */
1809 dsp = XtDisplayOfObject(label);
1810 scr = XtScreenOfObject(label);
1811 XtVaGetValues(XtIsSubclass(label, coreWidgetClass)
1812 ? label : XtParent(label),
1813 XmNdepth, &depth,
1814 XmNbackground, &color[0].pixel,
1815 XmNforeground, &color[1].pixel,
1816 XmNbottomShadowColor, &color[2].pixel,
1817 XmNtopShadowColor, &color[3].pixel,
1818 XmNhighlight, &color[4].pixel,
1819 NULL);
1820
1821 attr.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth;
1822 attr.colorsymbols = color;
1823 attr.numsymbols = 5;
1824 attr.closeness = 65535;
1825 attr.depth = depth;
1826 XpmCreatePixmapFromData(dsp, RootWindowOfScreen(scr),
1827 data, &pixmap, NULL, &attr);
1828
1829 XtVaGetValues(label, XmNrecomputeSize, &rs, NULL);
1830 XtVaSetValues(label, XmNrecomputeSize, True, NULL);
1831 XtVaSetValues(label,
1832 XmNlabelType, XmPIXMAP,
1833 XmNlabelPixmap, pixmap,
1834 NULL);
1835 XtVaSetValues(label, XmNrecomputeSize, rs, NULL);
1836
1837 return label;
1838}
1839#endif
1840
1841/* ARGSUSED */
1842 int
1843gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield)
1844 int type;
1845 char_u *title;
1846 char_u *message;
1847 char_u *button_names;
1848 int dfltbutton;
1849 char_u *textfield; /* buffer of size IOSIZE */
1850{
1851 char_u *buts;
1852 char_u *p, *next;
1853 XtAppContext app;
1854 XmString label;
1855 int butcount;
1856 Widget dialogform = NULL;
1857 Widget form = NULL;
1858 Widget dialogtextfield = NULL;
1859 Widget *buttons;
1860 Widget sep_form = NULL;
1861 Boolean vertical;
1862 Widget separator = NULL;
1863 int n;
1864 Arg args[6];
1865#ifdef HAVE_XPM
1866 char **icon_data = NULL;
1867 Widget dialogpixmap = NULL;
1868#endif
1869
1870 if (title == NULL)
1871 title = (char_u *)_("Vim dialog");
1872
1873 /* if our pointer is currently hidden, then we should show it. */
1874 gui_mch_mousehide(FALSE);
1875
1876 dialogform = XmCreateFormDialog(vimShell, (char *)"dialog", NULL, 0);
1877
1878 /* Check 'v' flag in 'guioptions': vertical button placement. */
1879 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
1880
1881 /* Set the title of the Dialog window */
1882 label = XmStringCreateSimple((char *)title);
1883 if (label == NULL)
1884 return -1;
1885 XtVaSetValues(dialogform,
1886 XmNdialogTitle, label,
1887 XmNhorizontalSpacing, 4,
1888 XmNverticalSpacing, vertical ? 0 : 4,
1889 NULL);
1890 XmStringFree(label);
1891
1892 /* make a copy, so that we can insert NULs */
1893 buts = vim_strsave(button_names);
1894 if (buts == NULL)
1895 return -1;
1896
1897 /* Count the number of buttons and allocate buttons[]. */
1898 butcount = 1;
1899 for (p = buts; *p; ++p)
1900 if (*p == DLG_BUTTON_SEP)
1901 ++butcount;
1902 buttons = (Widget *)alloc((unsigned)(butcount * sizeof(Widget)));
1903 if (buttons == NULL)
1904 {
1905 vim_free(buts);
1906 return -1;
1907 }
1908
1909 /*
1910 * Create the buttons.
1911 */
1912 sep_form = (Widget) 0;
1913 p = buts;
1914 for (butcount = 0; *p; ++butcount)
1915 {
1916 for (next = p; *next; ++next)
1917 {
1918 if (*next == DLG_HOTKEY_CHAR)
1919 mch_memmove(next, next + 1, STRLEN(next));
1920 if (*next == DLG_BUTTON_SEP)
1921 {
1922 *next++ = NUL;
1923 break;
1924 }
1925 }
1926 label = XmStringCreate(_((char *)p), STRING_TAG);
1927 if (label == NULL)
1928 break;
1929
1930 buttons[butcount] = XtVaCreateManagedWidget("button",
1931 xmPushButtonWidgetClass, dialogform,
1932 XmNlabelString, label,
1933 XmNbottomAttachment, XmATTACH_FORM,
1934 XmNbottomOffset, 4,
1935 XmNshowAsDefault, butcount == dfltbutton - 1,
1936 XmNdefaultButtonShadowThickness, 1,
1937 NULL);
1938 XmStringFree(label);
1939
1940 /* Layout properly. */
1941
1942 if (butcount > 0)
1943 {
1944 if (vertical)
1945 XtVaSetValues(buttons[butcount],
1946 XmNtopWidget, buttons[butcount - 1],
1947 NULL);
1948 else
1949 {
1950 if (*next == NUL)
1951 {
1952 XtVaSetValues(buttons[butcount],
1953 XmNrightAttachment, XmATTACH_FORM,
1954 XmNrightOffset, 4,
1955 NULL);
1956
1957 /* fill in a form as invisible separator */
1958 sep_form = XtVaCreateWidget("separatorForm",
1959 xmFormWidgetClass, dialogform,
1960 XmNleftAttachment, XmATTACH_WIDGET,
1961 XmNleftWidget, buttons[butcount - 1],
1962 XmNrightAttachment, XmATTACH_WIDGET,
1963 XmNrightWidget, buttons[butcount],
1964 XmNbottomAttachment, XmATTACH_FORM,
1965 XmNbottomOffset, 4,
1966 NULL);
1967 XtManageChild(sep_form);
1968 }
1969 else
1970 {
1971 XtVaSetValues(buttons[butcount],
1972 XmNleftAttachment, XmATTACH_WIDGET,
1973 XmNleftWidget, buttons[butcount - 1],
1974 NULL);
1975 }
1976 }
1977 }
1978 else if (!vertical)
1979 {
1980 if (*next == NUL)
1981 {
1982 XtVaSetValues(buttons[0],
1983 XmNrightAttachment, XmATTACH_FORM,
1984 XmNrightOffset, 4,
1985 NULL);
1986
1987 /* fill in a form as invisible separator */
1988 sep_form = XtVaCreateWidget("separatorForm",
1989 xmFormWidgetClass, dialogform,
1990 XmNleftAttachment, XmATTACH_FORM,
1991 XmNleftOffset, 4,
1992 XmNrightAttachment, XmATTACH_WIDGET,
1993 XmNrightWidget, buttons[0],
1994 XmNbottomAttachment, XmATTACH_FORM,
1995 XmNbottomOffset, 4,
1996 NULL);
1997 XtManageChild(sep_form);
1998 }
1999 else
2000 XtVaSetValues(buttons[0],
2001 XmNleftAttachment, XmATTACH_FORM,
2002 XmNleftOffset, 4,
2003 NULL);
2004 }
2005
2006 XtAddCallback(buttons[butcount], XmNactivateCallback,
2007 (XtCallbackProc)butproc, (XtPointer)(long)butcount);
2008 p = next;
2009 }
2010 vim_free(buts);
2011
2012 separator = (Widget) 0;
2013 if (butcount > 0)
2014 {
2015 /* Create the separator for beauty. */
2016 n = 0;
2017 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2018 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2019 XtSetArg(args[n], XmNbottomWidget, buttons[0]); n++;
2020 XtSetArg(args[n], XmNbottomOffset, 4); n++;
2021 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2022 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2023 separator = XmCreateSeparatorGadget(dialogform, "separator", args, n);
2024 XtManageChild(separator);
2025 }
2026
2027 if (textfield != NULL)
2028 {
2029 dialogtextfield = XtVaCreateWidget("textField",
2030 xmTextFieldWidgetClass, dialogform,
2031 XmNleftAttachment, XmATTACH_FORM,
2032 XmNrightAttachment, XmATTACH_FORM,
2033 NULL);
2034 if (butcount > 0)
2035 XtVaSetValues(dialogtextfield,
2036 XmNbottomAttachment, XmATTACH_WIDGET,
2037 XmNbottomWidget, separator,
2038 NULL);
2039 else
2040 XtVaSetValues(dialogtextfield,
2041 XmNbottomAttachment, XmATTACH_FORM,
2042 NULL);
2043
2044 gui_motif_set_fontlist(dialogtextfield);
2045 XmTextFieldSetString(dialogtextfield, (char *)textfield);
2046 XtManageChild(dialogtextfield);
2047 XtAddEventHandler(dialogtextfield, KeyPressMask, False,
2048 (XtEventHandler)keyhit_callback, (XtPointer)NULL);
2049 }
2050
2051 /* Form holding both message and pixmap labels */
2052 form = XtVaCreateWidget("separatorForm",
2053 xmFormWidgetClass, dialogform,
2054 XmNleftAttachment, XmATTACH_FORM,
2055 XmNrightAttachment, XmATTACH_FORM,
2056 XmNtopAttachment, XmATTACH_FORM,
2057 NULL);
2058 XtManageChild(form);
2059
2060#ifdef HAVE_XPM
2061 /* Add a pixmap, left of the message. */
2062 switch (type)
2063 {
2064 case VIM_GENERIC:
2065 icon_data = generic_xpm;
2066 break;
2067 case VIM_ERROR:
2068 icon_data = error_xpm;
2069 break;
2070 case VIM_WARNING:
2071 icon_data = alert_xpm;
2072 break;
2073 case VIM_INFO:
2074 icon_data = info_xpm;
2075 break;
2076 case VIM_QUESTION:
2077 icon_data = quest_xpm;
2078 break;
2079 default:
2080 icon_data = generic_xpm;
2081 }
2082
2083 n = 0;
2084 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2085 XtSetArg(args[n], XmNtopOffset, 8); n++;
2086 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2087 XtSetArg(args[n], XmNbottomOffset, 8); n++;
2088 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2089 XtSetArg(args[n], XmNleftOffset, 8); n++;
2090
2091 dialogpixmap = create_pixmap_label(form, "dialogPixmap",
2092 icon_data, args, n);
2093 XtManageChild(dialogpixmap);
2094#endif
2095
2096 /* Create the dialog message. */
2097 label = XmStringLtoRCreate((char *)message, STRING_TAG);
2098 if (label == NULL)
2099 return -1;
2100 (void)XtVaCreateManagedWidget("dialogMessage",
2101 xmLabelGadgetClass, form,
2102 XmNlabelString, label,
2103 XmNtopAttachment, XmATTACH_FORM,
2104 XmNtopOffset, 8,
2105#ifdef HAVE_XPM
2106 XmNleftAttachment, XmATTACH_WIDGET,
2107 XmNleftWidget, dialogpixmap,
2108#else
2109 XmNleftAttachment, XmATTACH_FORM,
2110#endif
2111 XmNleftOffset, 8,
2112 XmNrightAttachment, XmATTACH_FORM,
2113 XmNrightOffset, 8,
2114 XmNbottomAttachment, XmATTACH_FORM,
2115 XmNbottomOffset, 8,
2116 NULL);
2117 XmStringFree(label);
2118
2119 if (textfield != NULL)
2120 {
2121 XtVaSetValues(form,
2122 XmNbottomAttachment, XmATTACH_WIDGET,
2123 XmNbottomWidget, dialogtextfield,
2124 NULL);
2125 }
2126 else
2127 {
2128 if (butcount > 0)
2129 XtVaSetValues(form,
2130 XmNbottomAttachment, XmATTACH_WIDGET,
2131 XmNbottomWidget, separator,
2132 NULL);
2133 else
2134 XtVaSetValues(form,
2135 XmNbottomAttachment, XmATTACH_FORM,
2136 NULL);
2137 }
2138
2139 if (dfltbutton < 1)
2140 dfltbutton = 1;
2141 if (dfltbutton > butcount)
2142 dfltbutton = butcount;
2143 XtVaSetValues(dialogform,
2144 XmNdefaultButton, buttons[dfltbutton - 1], NULL);
2145 if (textfield != NULL)
2146 XtVaSetValues(dialogform, XmNinitialFocus, dialogtextfield, NULL);
2147 else
2148 XtVaSetValues(dialogform, XmNinitialFocus, buttons[dfltbutton - 1],
2149 NULL);
2150
2151 manage_centered(dialogform);
2152
2153 if (textfield != NULL && *textfield != NUL)
2154 {
2155 /* This only works after the textfield has been realised. */
2156 XmTextFieldSetSelection(dialogtextfield,
2157 (XmTextPosition)0, (XmTextPosition)STRLEN(textfield),
2158 XtLastTimestampProcessed(gui.dpy));
2159 XmTextFieldSetCursorPosition(dialogtextfield,
2160 (XmTextPosition)STRLEN(textfield));
2161 }
2162
2163 app = XtWidgetToApplicationContext(dialogform);
2164
2165 /* Loop until a button is pressed or the dialog is killed somehow. */
2166 dialogStatus = -1;
2167 for (;;)
2168 {
2169 XtAppProcessEvent(app, (XtInputMask)XtIMAll);
2170 if (dialogStatus >= 0 || !XtIsManaged(dialogform))
2171 break;
2172 }
2173
2174 vim_free(buttons);
2175
2176 if (textfield != NULL)
2177 {
2178 p = (char_u *)XmTextGetString(dialogtextfield);
2179 if (p == NULL || dialogStatus < 0)
2180 *textfield = NUL;
2181 else
2182 {
2183 STRNCPY(textfield, p, IOSIZE);
2184 textfield[IOSIZE - 1] = NUL;
2185 }
2186 }
2187
2188 XtDestroyWidget(dialogform);
2189
2190 return dialogStatus;
2191}
2192#endif /* FEAT_GUI_DIALOG */
2193
2194#if defined(FEAT_FOOTER) || defined(PROTO)
2195
2196 static int
2197gui_mch_compute_footer_height()
2198{
2199 Dimension height; /* total Toolbar height */
2200 Dimension top; /* XmNmarginTop */
2201 Dimension bottom; /* XmNmarginBottom */
2202 Dimension shadow; /* XmNshadowThickness */
2203
2204 XtVaGetValues(footer,
2205 XmNheight, &height,
2206 XmNmarginTop, &top,
2207 XmNmarginBottom, &bottom,
2208 XmNshadowThickness, &shadow,
2209 NULL);
2210
2211 return (int) height + top + bottom + (shadow << 1);
2212}
2213
2214#if 0 /* not used */
2215 void
2216gui_mch_set_footer_pos(h)
2217 int h; /* textArea height */
2218{
2219 XtVaSetValues(footer,
2220 XmNtopOffset, h + 7,
2221 NULL);
2222}
2223#endif
2224
2225 void
2226gui_mch_enable_footer(showit)
2227 int showit;
2228{
2229 if (showit)
2230 {
2231 gui.footer_height = gui_mch_compute_footer_height();
2232 XtManageChild(footer);
2233 }
2234 else
2235 {
2236 gui.footer_height = 0;
2237 XtUnmanageChild(footer);
2238 }
2239 XtVaSetValues(textAreaForm, XmNbottomOffset, gui.footer_height, NULL);
2240}
2241
2242 void
2243gui_mch_set_footer(s)
2244 char_u *s;
2245{
2246 XmString xms;
2247
2248 xms = XmStringCreate((char *)s, STRING_TAG);
2249 XtVaSetValues(footer, XmNlabelString, xms, NULL);
2250 XmStringFree(xms);
2251}
2252
2253#endif
2254
2255
2256#if defined(FEAT_TOOLBAR) || defined(PROTO)
2257 void
2258gui_mch_show_toolbar(int showit)
2259{
2260 Cardinal numChildren; /* how many children toolBar has */
2261
2262 if (toolBar == (Widget)0)
2263 return;
2264 XtVaGetValues(toolBar, XmNnumChildren, &numChildren, NULL);
2265 if (showit && numChildren > 0)
2266 {
2267 /* Assume that we want to show the toolbar if p_toolbar contains
2268 * valid option settings, therefore p_toolbar must not be NULL.
2269 */
2270 WidgetList children;
2271
2272 XtVaGetValues(toolBar, XmNchildren, &children, NULL);
2273 {
2274 void (*action)(BalloonEval *);
2275 int text = 0;
2276
2277 if (strstr((const char *)p_toolbar, "tooltips"))
2278 action = &gui_mch_enable_beval_area;
2279 else
2280 action = &gui_mch_disable_beval_area;
2281 if (strstr((const char *)p_toolbar, "text"))
2282 text = 1;
2283 else if (strstr((const char *)p_toolbar, "icons"))
2284 text = -1;
2285 if (text != 0)
2286 {
2287 vimmenu_T *toolbar;
2288 vimmenu_T *cur;
2289
2290 for (toolbar = root_menu; toolbar; toolbar = toolbar->next)
2291 if (menu_is_toolbar(toolbar->dname))
2292 break;
2293 /* Assumption: toolbar is NULL if there is no toolbar,
2294 * otherwise it contains the toolbar menu structure.
2295 *
2296 * Assumption: "numChildren" == the number of items in the list
2297 * of items beginning with toolbar->children.
2298 */
2299 if (toolbar)
2300 {
2301 for (cur = toolbar->children; cur; cur = cur->next)
2302 {
2303 Arg args[1];
2304 int n = 0;
2305
2306 /* Enable/Disable tooltip (OK to enable while
2307 * currently enabled)
2308 */
2309 if (cur->tip != NULL)
2310 (*action)(cur->tip);
2311 if (!menu_is_separator(cur->name))
2312 {
2313 if (text == 1 || cur->image == 0)
2314 XtSetArg(args[n], XmNlabelType, XmSTRING);
2315 else
2316 XtSetArg(args[n], XmNlabelType, XmPIXMAP);
2317 n++;
2318 if (cur->id != NULL)
2319 {
2320 XtUnmanageChild(cur->id);
2321 XtSetValues(cur->id, args, n);
2322 XtManageChild(cur->id);
2323 }
2324 }
2325 }
2326 }
2327 }
2328 }
2329 gui.toolbar_height = gui_mch_compute_toolbar_height();
2330 XtManageChild(XtParent(toolBar));
2331 XtVaSetValues(textAreaForm,
2332 XmNtopAttachment, XmATTACH_WIDGET,
2333 XmNtopWidget, XtParent(toolBar),
2334 NULL);
2335 if (XtIsManaged(menuBar))
2336 XtVaSetValues(XtParent(toolBar),
2337 XmNtopAttachment, XmATTACH_WIDGET,
2338 XmNtopWidget, menuBar,
2339 NULL);
2340 else
2341 XtVaSetValues(XtParent(toolBar),
2342 XmNtopAttachment, XmATTACH_FORM,
2343 NULL);
2344 }
2345 else
2346 {
2347 gui.toolbar_height = 0;
2348 if (XtIsManaged(menuBar))
2349 XtVaSetValues(textAreaForm,
2350 XmNtopAttachment, XmATTACH_WIDGET,
2351 XmNtopWidget, menuBar,
2352 NULL);
2353 else
2354 XtVaSetValues(textAreaForm,
2355 XmNtopAttachment, XmATTACH_FORM,
2356 NULL);
2357
2358 XtUnmanageChild(XtParent(toolBar));
2359 }
2360 gui_set_shellsize(FALSE, FALSE);
2361}
2362
2363/*
2364 * A toolbar button has been pushed; now reset the input focus
2365 * such that the user can type page up/down etc. and have the
2366 * input go to the editor window, not the button
2367 */
2368 static void
2369gui_mch_reset_focus()
2370{
2371 if (textArea != NULL)
2372 XmProcessTraversal(textArea, XmTRAVERSE_CURRENT);
2373}
2374
2375 int
2376gui_mch_compute_toolbar_height()
2377{
2378 Dimension height; /* total Toolbar height */
2379 Dimension whgt; /* height of each widget */
2380 Dimension marginHeight; /* XmNmarginHeight of toolBar */
2381 Dimension shadowThickness; /* thickness of Xtparent(toolBar) */
2382 WidgetList children; /* list of toolBar's children */
2383 Cardinal numChildren; /* how many children toolBar has */
2384 int i;
2385
2386 height = 0;
2387 shadowThickness = 0;
2388 marginHeight = 0;
2389 if (toolBar != (Widget)0 && toolBarFrame != (Widget)0)
2390 { /* get height of XmFrame parent */
2391 XtVaGetValues(toolBarFrame,
2392 XmNshadowThickness, &shadowThickness,
2393 NULL);
2394 XtVaGetValues(toolBar,
2395 XmNmarginHeight, &marginHeight,
2396 XmNchildren, &children,
2397 XmNnumChildren, &numChildren, NULL);
2398 for (i = 0; i < numChildren; i++)
2399 {
2400 whgt = 0;
2401 XtVaGetValues(children[i], XmNheight, &whgt, NULL);
2402 if (height < whgt)
2403 height = whgt;
2404 }
2405 }
2406
2407 return (int)(height + (marginHeight << 1) + (shadowThickness << 1));
2408}
2409
2410#if 0 /* these are never called. */
2411/*
2412 * The next toolbar enter/leave callbacks make sure the text area gets the
2413 * keyboard focus when the pointer is not in the toolbar.
2414 */
2415/*ARGSUSED*/
2416 static void
2417toolbar_enter_cb(w, client_data, event, cont)
2418 Widget w;
2419 XtPointer client_data;
2420 XEvent *event;
2421 Boolean *cont;
2422{
2423 XmProcessTraversal(toolBar, XmTRAVERSE_CURRENT);
2424}
2425
2426/*ARGSUSED*/
2427 static void
2428toolbar_leave_cb(w, client_data, event, cont)
2429 Widget w;
2430 XtPointer client_data;
2431 XEvent *event;
2432 Boolean *cont;
2433{
2434 XmProcessTraversal(textArea, XmTRAVERSE_CURRENT);
2435}
2436#endif
2437
2438# ifdef FEAT_FOOTER
2439/*
2440 * The next toolbar enter/leave callbacks should really do balloon help. But
2441 * I have to use footer help for backwards compatability. Hopefully both will
2442 * get implemented and the user will have a choice.
2443 */
2444/*ARGSUSED*/
2445 static void
2446toolbarbutton_enter_cb(w, client_data, event, cont)
2447 Widget w;
2448 XtPointer client_data;
2449 XEvent *event;
2450 Boolean *cont;
2451{
2452 vimmenu_T *menu = (vimmenu_T *) client_data;
2453
2454 if (menu->strings[MENU_INDEX_TIP] != NULL)
2455 {
2456 if (vim_strchr(p_go, GO_FOOTER) != NULL)
2457 gui_mch_set_footer(menu->strings[MENU_INDEX_TIP]);
2458 }
2459}
2460
2461/*ARGSUSED*/
2462 static void
2463toolbarbutton_leave_cb(w, client_data, event, cont)
2464 Widget w;
2465 XtPointer client_data;
2466 XEvent *event;
2467 Boolean *cont;
2468{
2469 gui_mch_set_footer((char_u *) "");
2470}
2471# endif
2472
2473 void
2474gui_mch_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp)
2475 Pixel *bgp;
2476 Pixel *fgp;
2477 Pixel *bsp;
2478 Pixel *tsp;
2479 Pixel *hsp;
2480{
2481 XtVaGetValues(toolBar,
2482 XmNbackground, bgp,
2483 XmNforeground, fgp,
2484 XmNbottomShadowColor, bsp,
2485 XmNtopShadowColor, tsp,
2486 XmNhighlightColor, hsp,
2487 NULL);
2488}
2489#endif
2490
2491/*
2492 * Set the colors of Widget "id" to the menu colors.
2493 */
2494 static void
2495gui_motif_menu_colors(id)
2496 Widget id;
2497{
2498 if (gui.menu_bg_pixel != INVALCOLOR)
2499#if (XmVersion >= 1002)
2500 XmChangeColor(id, gui.menu_bg_pixel);
2501#else
2502 XtVaSetValues(id, XmNbackground, gui.menu_bg_pixel, NULL);
2503#endif
2504 if (gui.menu_fg_pixel != INVALCOLOR)
2505 XtVaSetValues(id, XmNforeground, gui.menu_fg_pixel, NULL);
2506}
2507
2508/*
2509 * Set the colors of Widget "id" to the scrollbar colors.
2510 */
2511 static void
2512gui_motif_scroll_colors(id)
2513 Widget id;
2514{
2515 if (gui.scroll_bg_pixel != INVALCOLOR)
2516#if (XmVersion >= 1002)
2517 XmChangeColor(id, gui.scroll_bg_pixel);
2518#else
2519 XtVaSetValues(id, XmNbackground, gui.scroll_bg_pixel, NULL);
2520#endif
2521 if (gui.scroll_fg_pixel != INVALCOLOR)
2522 XtVaSetValues(id, XmNforeground, gui.scroll_fg_pixel, NULL);
2523}
2524
2525#ifdef FEAT_MENU
2526/*
2527 * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font.
2528 */
2529 static void
2530gui_motif_menu_fontlist(id)
2531 Widget id;
2532{
2533#ifdef FONTSET_ALWAYS
2534 if (gui.menu_fontset != NOFONTSET)
2535 {
2536 XmFontList fl;
2537
2538 fl = gui_motif_fontset2fontlist((XFontSet *)&gui.menu_fontset);
2539 if (fl != NULL)
2540 {
2541 if (XtIsManaged(id))
2542 {
2543 XtUnmanageChild(id);
2544 XtVaSetValues(id, XmNfontList, fl, NULL);
2545 /* We should force the widget to recalculate it's
2546 * geometry now. */
2547 XtManageChild(id);
2548 }
2549 else
2550 XtVaSetValues(id, XmNfontList, fl, NULL);
2551 XmFontListFree(fl);
2552 }
2553 }
2554#else
2555 if (gui.menu_font != NOFONT)
2556 {
2557 XmFontList fl;
2558
2559 fl = gui_motif_create_fontlist((XFontStruct *)gui.menu_font);
2560 if (fl != NULL)
2561 {
2562 if (XtIsManaged(id))
2563 {
2564 XtUnmanageChild(id);
2565 XtVaSetValues(id, XmNfontList, fl, NULL);
2566 /* We should force the widget to recalculate it's
2567 * geometry now. */
2568 XtManageChild(id);
2569 }
2570 else
2571 XtVaSetValues(id, XmNfontList, fl, NULL);
2572 XmFontListFree(fl);
2573 }
2574 }
2575#endif
2576}
2577
2578#endif
2579
2580/*
2581 * We don't create it twice for the sake of speed.
2582 */
2583
2584typedef struct _SharedFindReplace
2585{
2586 Widget dialog; /* the main dialog widget */
2587 Widget wword; /* 'Exact match' check button */
2588 Widget mcase; /* 'match case' check button */
2589 Widget up; /* search direction 'Up' radio button */
2590 Widget down; /* search direction 'Down' radio button */
2591 Widget what; /* 'Find what' entry text widget */
2592 Widget with; /* 'Replace with' entry text widget */
2593 Widget find; /* 'Find Next' action button */
2594 Widget replace; /* 'Replace With' action button */
2595 Widget all; /* 'Replace All' action button */
2596 Widget undo; /* 'Undo' action button */
2597
2598 Widget cancel;
2599} SharedFindReplace;
2600
2601static SharedFindReplace find_widgets = { NULL };
2602static SharedFindReplace repl_widgets = { NULL };
2603
2604static void find_replace_destroy_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
2605static void find_replace_dismiss_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
2606static void entry_activate_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
2607static void find_replace_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
2608static void find_replace_keypress __ARGS((Widget w, SharedFindReplace * frdp, XKeyEvent * event));
2609static void find_replace_dialog_create __ARGS((char_u *entry_text, int do_replace));
2610
2611/*ARGSUSED*/
2612 static void
2613find_replace_destroy_callback(w, client_data, call_data)
2614 Widget w;
2615 XtPointer client_data;
2616 XtPointer call_data;
2617{
2618 SharedFindReplace *cd = (SharedFindReplace *)client_data;
2619
2620 if (cd != NULL)
2621 cd->dialog = (Widget)0;
2622}
2623
2624/*ARGSUSED*/
2625 static void
2626find_replace_dismiss_callback(w, client_data, call_data)
2627 Widget w;
2628 XtPointer client_data;
2629 XtPointer call_data;
2630{
2631 SharedFindReplace *cd = (SharedFindReplace *)client_data;
2632
2633 if (cd != NULL)
2634 XtUnmanageChild(cd->dialog);
2635}
2636
2637/*ARGSUSED*/
2638 static void
2639entry_activate_callback(w, client_data, call_data)
2640 Widget w;
2641 XtPointer client_data;
2642 XtPointer call_data;
2643{
2644 XmProcessTraversal((Widget)client_data, XmTRAVERSE_CURRENT);
2645}
2646
2647/*ARGSUSED*/
2648 static void
2649find_replace_callback(w, client_data, call_data)
2650 Widget w;
2651 XtPointer client_data;
2652 XtPointer call_data;
2653{
2654 long_u flags = (long_u)client_data;
2655 char *find_text, *repl_text;
2656 Boolean direction_down = TRUE;
2657 Boolean wword;
2658 Boolean mcase;
2659 SharedFindReplace *sfr;
2660
2661 if (flags == FRD_UNDO)
2662 {
2663 char_u *save_cpo = p_cpo;
2664
2665 /* No need to be Vi compatible here. */
2666 p_cpo = (char_u *)"";
2667 u_undo(1);
2668 p_cpo = save_cpo;
2669 gui_update_screen();
2670 return;
2671 }
2672
2673 /* Get the search/replace strings from the dialog */
2674 if (flags == FRD_FINDNEXT)
2675 {
2676 repl_text = NULL;
2677 sfr = &find_widgets;
2678 }
2679 else
2680 {
2681 repl_text = XmTextFieldGetString(repl_widgets.with);
2682 sfr = &repl_widgets;
2683 }
2684 find_text = XmTextFieldGetString(sfr->what);
2685 XtVaGetValues(sfr->down, XmNset, &direction_down, NULL);
2686 XtVaGetValues(sfr->wword, XmNset, &wword, NULL);
2687 XtVaGetValues(sfr->mcase, XmNset, &mcase, NULL);
2688 if (wword)
2689 flags |= FRD_WHOLE_WORD;
2690 if (mcase)
2691 flags |= FRD_MATCH_CASE;
2692
2693 (void)gui_do_findrepl((int)flags, (char_u *)find_text, (char_u *)repl_text,
2694 direction_down);
2695
2696 if (find_text != NULL)
2697 XtFree(find_text);
2698 if (repl_text != NULL)
2699 XtFree(repl_text);
2700}
2701
2702/*ARGSUSED*/
2703 static void
2704find_replace_keypress(w, frdp, event)
2705 Widget w;
2706 SharedFindReplace *frdp;
2707 XKeyEvent *event;
2708{
2709 KeySym keysym;
2710
2711 if (frdp == NULL)
2712 return;
2713
2714 keysym = XLookupKeysym(event, 0);
2715
2716 /* the scape key pops the whole dialog down */
2717 if (keysym == XK_Escape)
2718 XtUnmanageChild(frdp->dialog);
2719}
2720
2721 static void
2722find_replace_dialog_create(arg, do_replace)
2723 char_u *arg;
2724 int do_replace;
2725{
2726 SharedFindReplace *frdp;
2727 Widget separator;
2728 Widget input_form;
2729 Widget button_form;
2730 Widget toggle_form;
2731 Widget frame;
2732 XmString str;
2733 int n;
2734 Arg args[6];
2735 int wword = FALSE;
2736 int mcase = !p_ic;
2737 Dimension width;
2738 Dimension widest;
2739 char_u *entry_text;
2740
2741 frdp = do_replace ? &repl_widgets : &find_widgets;
2742
2743 /* Get the search string to use. */
2744 entry_text = get_find_dialog_text(arg, &wword, &mcase);
2745
2746 /* If the dialog already exists, just raise it. */
2747 if (frdp->dialog)
2748 {
2749 /* If the window is already up, just pop it to the top */
2750 if (XtIsManaged(frdp->dialog))
2751 XMapRaised(XtDisplay(frdp->dialog),
2752 XtWindow(XtParent(frdp->dialog)));
2753 else
2754 XtManageChild(frdp->dialog);
2755 XtPopup(XtParent(frdp->dialog), XtGrabNone);
2756 XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);
2757
2758 if (entry_text != NULL)
2759 XmTextFieldSetString(frdp->what, (char *)entry_text);
2760 vim_free(entry_text);
2761
2762 XtVaSetValues(frdp->wword, XmNset, wword, NULL);
2763 return;
2764 }
2765
2766 /* Create a fresh new dialog window */
2767 if (do_replace)
2768 str = XmStringCreateSimple(_("VIM - Search and Replace..."));
2769 else
2770 str = XmStringCreateSimple(_("VIM - Search..."));
2771
2772 n = 0;
2773 XtSetArg(args[n], XmNautoUnmanage, False); n++;
2774 XtSetArg(args[n], XmNnoResize, True); n++;
2775 XtSetArg(args[n], XmNdialogTitle, str); n++;
2776
2777 frdp->dialog = XmCreateFormDialog(vimShell, "findReplaceDialog", args, n);
2778 XmStringFree(str);
2779 XtAddCallback(frdp->dialog, XmNdestroyCallback,
2780 find_replace_destroy_callback, frdp);
2781
2782 button_form = XtVaCreateWidget("buttonForm",
2783 xmFormWidgetClass, frdp->dialog,
2784 XmNrightAttachment, XmATTACH_FORM,
2785 XmNrightOffset, 4,
2786 XmNtopAttachment, XmATTACH_FORM,
2787 XmNtopOffset, 4,
2788 XmNbottomAttachment, XmATTACH_FORM,
2789 XmNbottomOffset, 4,
2790 NULL);
2791
2792 str = XmStringCreateSimple(_("Find Next"));
2793 frdp->find = XtVaCreateManagedWidget("findButton",
2794 xmPushButtonWidgetClass, button_form,
2795 XmNlabelString, str,
2796 XmNsensitive, True,
2797 XmNtopAttachment, XmATTACH_FORM,
2798 XmNleftAttachment, XmATTACH_FORM,
2799 XmNrightAttachment, XmATTACH_FORM,
2800 NULL);
2801 XmStringFree(str);
2802
2803 XtAddCallback(frdp->find, XmNactivateCallback,
2804 find_replace_callback,
2805 (XtPointer) (do_replace ? FRD_R_FINDNEXT : FRD_FINDNEXT));
2806
2807 if (do_replace)
2808 {
2809 str = XmStringCreateSimple(_("Replace"));
2810 frdp->replace = XtVaCreateManagedWidget("replaceButton",
2811 xmPushButtonWidgetClass, button_form,
2812 XmNlabelString, str,
2813 XmNtopAttachment, XmATTACH_WIDGET,
2814 XmNtopWidget, frdp->find,
2815 XmNleftAttachment, XmATTACH_FORM,
2816 XmNrightAttachment, XmATTACH_FORM,
2817 NULL);
2818 XmStringFree(str);
2819 XtAddCallback(frdp->replace, XmNactivateCallback,
2820 find_replace_callback, (XtPointer)FRD_REPLACE);
2821
2822 str = XmStringCreateSimple(_("Replace All"));
2823 frdp->all = XtVaCreateManagedWidget("replaceAllButton",
2824 xmPushButtonWidgetClass, button_form,
2825 XmNlabelString, str,
2826 XmNtopAttachment, XmATTACH_WIDGET,
2827 XmNtopWidget, frdp->replace,
2828 XmNleftAttachment, XmATTACH_FORM,
2829 XmNrightAttachment, XmATTACH_FORM,
2830 NULL);
2831 XmStringFree(str);
2832 XtAddCallback(frdp->all, XmNactivateCallback,
2833 find_replace_callback, (XtPointer)FRD_REPLACEALL);
2834
2835 str = XmStringCreateSimple(_("Undo"));
2836 frdp->undo = XtVaCreateManagedWidget("undoButton",
2837 xmPushButtonWidgetClass, button_form,
2838 XmNlabelString, str,
2839 XmNtopAttachment, XmATTACH_WIDGET,
2840 XmNtopWidget, frdp->all,
2841 XmNleftAttachment, XmATTACH_FORM,
2842 XmNrightAttachment, XmATTACH_FORM,
2843 NULL);
2844 XmStringFree(str);
2845 XtAddCallback(frdp->undo, XmNactivateCallback,
2846 find_replace_callback, (XtPointer)FRD_UNDO);
2847 }
2848
2849 str = XmStringCreateSimple(_("Cancel"));
2850 frdp->cancel = XtVaCreateManagedWidget("closeButton",
2851 xmPushButtonWidgetClass, button_form,
2852 XmNlabelString, str,
2853 XmNleftAttachment, XmATTACH_FORM,
2854 XmNrightAttachment, XmATTACH_FORM,
2855 XmNbottomAttachment, XmATTACH_FORM,
2856 NULL);
2857 XmStringFree(str);
2858 XtAddCallback(frdp->cancel, XmNactivateCallback,
2859 find_replace_dismiss_callback, frdp);
2860
2861 XtManageChild(button_form);
2862
2863 n = 0;
2864 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
2865 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
2866 XtSetArg(args[n], XmNrightWidget, button_form); n++;
2867 XtSetArg(args[n], XmNrightOffset, 4); n++;
2868 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2869 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2870 separator = XmCreateSeparatorGadget(frdp->dialog, "separator", args, n);
2871 XtManageChild(separator);
2872
2873 input_form = XtVaCreateWidget("inputForm",
2874 xmFormWidgetClass, frdp->dialog,
2875 XmNleftAttachment, XmATTACH_FORM,
2876 XmNleftOffset, 4,
2877 XmNrightAttachment, XmATTACH_WIDGET,
2878 XmNrightWidget, separator,
2879 XmNrightOffset, 4,
2880 XmNtopAttachment, XmATTACH_FORM,
2881 XmNtopOffset, 4,
2882 NULL);
2883
2884 {
2885 Widget label_what;
2886 Widget label_with = (Widget)0;
2887
2888 str = XmStringCreateSimple(_("Find what:"));
2889 label_what = XtVaCreateManagedWidget("whatLabel",
2890 xmLabelGadgetClass, input_form,
2891 XmNlabelString, str,
2892 XmNleftAttachment, XmATTACH_FORM,
2893 XmNtopAttachment, XmATTACH_FORM,
2894 XmNtopOffset, 4,
2895 NULL);
2896 XmStringFree(str);
2897
2898 frdp->what = XtVaCreateManagedWidget("whatText",
2899 xmTextFieldWidgetClass, input_form,
2900 XmNtopAttachment, XmATTACH_FORM,
2901 XmNrightAttachment, XmATTACH_FORM,
2902 XmNleftAttachment, XmATTACH_FORM,
2903 NULL);
2904
2905 if (do_replace)
2906 {
2907 frdp->with = XtVaCreateManagedWidget("withText",
2908 xmTextFieldWidgetClass, input_form,
2909 XmNtopAttachment, XmATTACH_WIDGET,
2910 XmNtopWidget, frdp->what,
2911 XmNtopOffset, 4,
2912 XmNleftAttachment, XmATTACH_FORM,
2913 XmNrightAttachment, XmATTACH_FORM,
2914 XmNbottomAttachment, XmATTACH_FORM,
2915 NULL);
2916
2917 XtAddCallback(frdp->with, XmNactivateCallback,
2918 find_replace_callback, (XtPointer) FRD_R_FINDNEXT);
2919
2920 str = XmStringCreateSimple(_("Replace with:"));
2921 label_with = XtVaCreateManagedWidget("withLabel",
2922 xmLabelGadgetClass, input_form,
2923 XmNlabelString, str,
2924 XmNleftAttachment, XmATTACH_FORM,
2925 XmNtopAttachment, XmATTACH_WIDGET,
2926 XmNtopWidget, frdp->what,
2927 XmNtopOffset, 4,
2928 XmNbottomAttachment, XmATTACH_FORM,
2929 NULL);
2930 XmStringFree(str);
2931
2932 /*
2933 * Make the entry activation only change the input focus onto the
2934 * with item.
2935 */
2936 XtAddCallback(frdp->what, XmNactivateCallback,
2937 entry_activate_callback, frdp->with);
2938 XtAddEventHandler(frdp->with, KeyPressMask, False,
2939 (XtEventHandler)find_replace_keypress,
2940 (XtPointer) frdp);
2941
2942 }
2943 else
2944 {
2945 /*
2946 * Make the entry activation do the search.
2947 */
2948 XtAddCallback(frdp->what, XmNactivateCallback,
2949 find_replace_callback, (XtPointer)FRD_FINDNEXT);
2950 }
2951 XtAddEventHandler(frdp->what, KeyPressMask, False,
2952 (XtEventHandler)find_replace_keypress,
2953 (XtPointer)frdp);
2954
2955 /* Get the maximum width between the label widgets and line them up.
2956 */
2957 n = 0;
2958 XtSetArg(args[n], XmNwidth, &width); n++;
2959 XtGetValues(label_what, args, n);
2960 widest = width;
2961 if (do_replace)
2962 {
2963 XtGetValues(label_with, args, n);
2964 if (width > widest)
2965 widest = width;
2966 }
2967
2968 XtVaSetValues(frdp->what, XmNleftOffset, widest, NULL);
2969 if (do_replace)
2970 XtVaSetValues(frdp->with, XmNleftOffset, widest, NULL);
2971
2972 }
2973
2974 XtManageChild(input_form);
2975
2976 {
2977 Widget radio_box;
2978
2979 frame = XtVaCreateWidget("directionFrame",
2980 xmFrameWidgetClass, frdp->dialog,
2981 XmNtopAttachment, XmATTACH_WIDGET,
2982 XmNtopWidget, input_form,
2983 XmNtopOffset, 4,
2984 XmNbottomAttachment, XmATTACH_FORM,
2985 XmNbottomOffset, 4,
2986 XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
2987 XmNrightWidget, input_form,
2988 NULL);
2989
2990 str = XmStringCreateSimple(_("Direction"));
2991 (void)XtVaCreateManagedWidget("directionFrameLabel",
2992 xmLabelGadgetClass, frame,
2993 XmNlabelString, str,
2994 XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
2995 XmNchildType, XmFRAME_TITLE_CHILD,
2996 NULL);
2997 XmStringFree(str);
2998
2999 radio_box = XmCreateRadioBox(frame, "radioBox",
3000 (ArgList)NULL, 0);
3001
3002 str = XmStringCreateSimple( _("Up"));
3003 frdp->up = XtVaCreateManagedWidget("upRadioButton",
3004 xmToggleButtonGadgetClass, radio_box,
3005 XmNlabelString, str,
3006 XmNset, False,
3007 NULL);
3008 XmStringFree(str);
3009
3010 str = XmStringCreateSimple(_("Down"));
3011 frdp->down = XtVaCreateManagedWidget("downRadioButton",
3012 xmToggleButtonGadgetClass, radio_box,
3013 XmNlabelString, str,
3014 XmNset, True,
3015 NULL);
3016 XmStringFree(str);
3017
3018 XtManageChild(radio_box);
3019 XtManageChild(frame);
3020 }
3021
3022 toggle_form = XtVaCreateWidget("toggleForm",
3023 xmFormWidgetClass, frdp->dialog,
3024 XmNleftAttachment, XmATTACH_FORM,
3025 XmNleftOffset, 4,
3026 XmNrightAttachment, XmATTACH_WIDGET,
3027 XmNrightWidget, frame,
3028 XmNrightOffset, 4,
3029 XmNtopAttachment, XmATTACH_WIDGET,
3030 XmNtopWidget, input_form,
3031 XmNtopOffset, 4,
3032 XmNbottomAttachment, XmATTACH_FORM,
3033 XmNbottomOffset, 4,
3034 NULL);
3035
3036 str = XmStringCreateSimple(_("Match whole word only"));
3037 frdp->wword = XtVaCreateManagedWidget("wordToggle",
3038 xmToggleButtonGadgetClass, toggle_form,
3039 XmNlabelString, str,
3040 XmNtopAttachment, XmATTACH_FORM,
3041 XmNtopOffset, 4,
3042 XmNleftAttachment, XmATTACH_FORM,
3043 XmNleftOffset, 4,
3044 XmNset, wword,
3045 NULL);
3046 XmStringFree(str);
3047
3048 str = XmStringCreateSimple(_("Match case"));
3049 frdp->mcase = XtVaCreateManagedWidget("caseToggle",
3050 xmToggleButtonGadgetClass, toggle_form,
3051 XmNlabelString, str,
3052 XmNleftAttachment, XmATTACH_FORM,
3053 XmNleftOffset, 4,
3054 XmNtopAttachment, XmATTACH_WIDGET,
3055 XmNtopWidget, frdp->wword,
3056 XmNtopOffset, 4,
3057 XmNset, mcase,
3058 NULL);
3059 XmStringFree(str);
3060
3061 XtManageChild(toggle_form);
3062
3063 if (entry_text != NULL)
3064 XmTextFieldSetString(frdp->what, (char *)entry_text);
3065 vim_free(entry_text);
3066
3067 XtManageChild(frdp->dialog);
3068 XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);
3069}
3070
3071 void
3072gui_mch_find_dialog(eap)
3073 exarg_T *eap;
3074{
3075 if (!gui.in_use)
3076 return;
3077
3078 find_replace_dialog_create(eap->arg, FALSE);
3079}
3080
3081
3082 void
3083gui_mch_replace_dialog(eap)
3084 exarg_T *eap;
3085{
3086 if (!gui.in_use)
3087 return;
3088
3089 find_replace_dialog_create(eap->arg, TRUE);
3090}