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