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