blob: 4c5ced5415f3481ca3673f38d894d73bbc6a9b42 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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
Bram Moolenaarf7506ca2017-02-25 16:01:49 +010011#include "vim.h"
12
Bram Moolenaar071d4272004-06-13 20:20:40 +000013#include <Xm/Form.h>
14#include <Xm/RowColumn.h>
15#include <Xm/PushB.h>
16#include <Xm/Text.h>
17#include <Xm/TextF.h>
18#include <Xm/Separator.h>
19#include <Xm/Label.h>
20#include <Xm/CascadeB.h>
21#include <Xm/ScrollBar.h>
22#include <Xm/MenuShell.h>
23#include <Xm/DrawingA.h>
24#if (XmVersion >= 1002)
25# include <Xm/RepType.h>
26#endif
27#include <Xm/Frame.h>
28#include <Xm/LabelG.h>
29#include <Xm/ToggleBG.h>
30#include <Xm/SeparatoG.h>
Bram Moolenaarc6fe9192006-04-09 21:54:49 +000031#include <Xm/XmP.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000032
33#include <X11/keysym.h>
34#include <X11/Xatom.h>
35#include <X11/StringDefs.h>
36#include <X11/Intrinsic.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000037#ifdef HAVE_X11_XPM_H
Bram Moolenaar88c86eb2019-01-17 17:13:30 +010038# if defined(VMS)
39# include <xpm.h>
40# else
41# include <X11/xpm.h>
42# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000043#else
44# ifdef HAVE_XM_XPMP_H
45# include <Xm/XpmP.h>
46# endif
47#endif
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000048#ifdef HAVE_XM_NOTEBOOK_H
49# include <Xm/Notebook.h>
50#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000051
Bram Moolenaar734a8672019-12-02 22:49:38 +010052#include "gui_xmebw.h" // for our Enhanced Button Widget
Bram Moolenaarb7fcef52005-01-02 11:31:05 +000053
Bram Moolenaar071d4272004-06-13 20:20:40 +000054#if defined(FEAT_GUI_DIALOG) && defined(HAVE_XPM)
55# include "../pixmaps/alert.xpm"
56# include "../pixmaps/error.xpm"
57# include "../pixmaps/generic.xpm"
58# include "../pixmaps/info.xpm"
59# include "../pixmaps/quest.xpm"
60#endif
61
62#define MOTIF_POPUP
63
64extern Widget vimShell;
65
66static Widget vimForm;
67static Widget textAreaForm;
68Widget textArea;
69#ifdef FEAT_TOOLBAR
70static Widget toolBarFrame;
71static Widget toolBar;
72#endif
Bram Moolenaar910f66f2006-04-05 20:41:53 +000073#ifdef FEAT_GUI_TABLINE
74static Widget tabLine;
75static Widget tabLine_menu = 0;
76static int showing_tabline = 0;
77#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000078#ifdef FEAT_MENU
79# if (XmVersion >= 1002)
Bram Moolenaar734a8672019-12-02 22:49:38 +010080// remember the last set value for the tearoff item
Bram Moolenaar071d4272004-06-13 20:20:40 +000081static int tearoff_val = (int)XmTEAR_OFF_ENABLED;
82# endif
83static Widget menuBar;
84#endif
85
Bram Moolenaar071d4272004-06-13 20:20:40 +000086#ifdef FEAT_TOOLBAR
Bram Moolenaard25c16e2016-01-29 22:13:30 +010087static void reset_focus(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000088#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000089
Bram Moolenaard25c16e2016-01-29 22:13:30 +010090static void gui_motif_menu_colors(Widget id);
91static void gui_motif_scroll_colors(Widget id);
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
93#if (XmVersion >= 1002)
94# define STRING_TAG XmFONTLIST_DEFAULT_TAG
95#else
96# define STRING_TAG XmSTRING_DEFAULT_CHARSET
97#endif
98
99/*
100 * Call-back routines.
101 */
102
Bram Moolenaar071d4272004-06-13 20:20:40 +0000103 static void
Bram Moolenaarc1ab6762016-01-30 19:45:49 +0100104scroll_cb(Widget w UNUSED, XtPointer client_data, XtPointer call_data)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105{
106 scrollbar_T *sb;
107 long value;
108 int dragging;
109
110 sb = gui_find_scrollbar((long)client_data);
111
112 value = ((XmScrollBarCallbackStruct *)call_data)->value;
113 dragging = (((XmScrollBarCallbackStruct *)call_data)->reason ==
114 (int)XmCR_DRAG);
115 gui_drag_scrollbar(sb, value, dragging);
116}
117
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000118#ifdef FEAT_GUI_TABLINE
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000119 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100120tabline_cb(
121 Widget w UNUSED,
122 XtPointer client_data UNUSED,
123 XtPointer call_data)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000124{
125 XmNotebookCallbackStruct *nptr;
126
127 nptr = (XmNotebookCallbackStruct *)call_data;
128 if (nptr->reason != (int)XmCR_NONE)
129 send_tabline_event(nptr->page_number);
130}
131
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000132 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100133tabline_button_cb(
134 Widget w,
135 XtPointer client_data UNUSED,
136 XtPointer call_data UNUSED)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000137{
Bram Moolenaar9dd42a62022-03-24 18:04:49 +0000138 XtPointer cmd, tab_idx;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000139
140 XtVaGetValues(w, XmNuserData, &cmd, NULL);
141 XtVaGetValues(tabLine_menu, XmNuserData, &tab_idx, NULL);
142
Bram Moolenaar9dd42a62022-03-24 18:04:49 +0000143 send_tabline_menu_event((int)(long)tab_idx, (int)(long)cmd);
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000144}
145
146/*
147 * Tabline single mouse click timeout handler
148 */
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000149 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100150motif_tabline_timer_cb (
151 XtPointer timed_out,
152 XtIntervalId *interval_id UNUSED)
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000153{
154 *((int *)timed_out) = TRUE;
155}
156
157/*
158 * check if the tabline tab scroller is clicked
159 */
160 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100161tabline_scroller_clicked(
162 char *scroller_name,
163 XButtonPressedEvent *event)
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000164{
165 Widget tab_scroll_w;
166 Position pos_x, pos_y;
167 Dimension width, height;
168
169 tab_scroll_w = XtNameToWidget(tabLine, scroller_name);
170 if (tab_scroll_w != (Widget)0) {
171 XtVaGetValues(tab_scroll_w, XmNx, &pos_x, XmNy, &pos_y, XmNwidth,
172 &width, XmNheight, &height, NULL);
173 if (pos_x >= 0) {
Bram Moolenaar734a8672019-12-02 22:49:38 +0100174 // Tab scroller (next) is visible
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000175 if ((event->x >= pos_x) && (event->x <= pos_x + width) &&
176 (event->y >= pos_y) && (event->y <= pos_y + height)) {
Bram Moolenaar734a8672019-12-02 22:49:38 +0100177 // Clicked on the scroller
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000178 return TRUE;
179 }
180 }
181 }
182 return FALSE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000183}
184
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000185 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100186tabline_menu_cb(
187 Widget w,
188 XtPointer closure UNUSED,
189 XEvent *e,
190 Boolean *continue_dispatch UNUSED)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000191{
192 Widget tab_w;
193 XButtonPressedEvent *event;
194 int tab_idx = 0;
195 WidgetList children;
196 Cardinal numChildren;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000197 static XtIntervalId timer = (XtIntervalId)0;
198 static int timed_out = TRUE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000199
200 event = (XButtonPressedEvent *)e;
201
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000202 if (event->button == Button1)
203 {
204 if (tabline_scroller_clicked("MajorTabScrollerNext", event)
205 || tabline_scroller_clicked("MajorTabScrollerPrevious", event))
206 return;
207
208 if (!timed_out)
209 {
210 XtRemoveTimeOut(timer);
211 timed_out = TRUE;
212
213 /*
214 * Double click on the tabline gutter, add a new tab
215 */
216 send_tabline_menu_event(0, TABLINE_MENU_NEW);
217 }
218 else
219 {
220 /*
221 * Single click on the tabline gutter, start a timer to check
222 * for double clicks
223 */
224 timer = XtAppAddTimeOut(app_context, (long_u)p_mouset,
225 motif_tabline_timer_cb, &timed_out);
226 timed_out = FALSE;
227 }
228 return;
229 }
230
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000231 if (event->button != Button3)
232 return;
233
Bram Moolenaar734a8672019-12-02 22:49:38 +0100234 // When ignoring events don't show the menu.
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000235 if (hold_gui_events
236# ifdef FEAT_CMDWIN
237 || cmdwin_type != 0
238# endif
239 )
240 return;
241
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000242 if (event->subwindow != None)
243 {
244 tab_w = XtWindowToWidget(XtDisplay(w), event->subwindow);
Bram Moolenaar734a8672019-12-02 22:49:38 +0100245 // LINTED: avoid warning: dubious operation on enum
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000246 if (tab_w != (Widget)0 && XmIsPushButton(tab_w))
247 XtVaGetValues(tab_w, XmNpageNumber, &tab_idx, NULL);
248 }
249
Bram Moolenaar9dd42a62022-03-24 18:04:49 +0000250 XtVaSetValues(tabLine_menu, XmNuserData, (XtPointer)(long)tab_idx, NULL);
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000251 XtVaGetValues(tabLine_menu, XmNchildren, &children, XmNnumChildren,
252 &numChildren, NULL);
253 XtManageChildren(children, numChildren);
254 XmMenuPosition(tabLine_menu, (XButtonPressedEvent *)e) ;
255 XtManageChild(tabLine_menu);
256}
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000257
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000258 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100259tabline_balloon_cb(BalloonEval *beval, int state UNUSED)
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000260{
261 int nr;
262 tabpage_T *tp;
263
264 if (beval->target == (Widget)0)
265 return;
266
267 XtVaGetValues(beval->target, XmNpageNumber, &nr, NULL);
268 tp = find_tabpage(nr);
269 if (tp == NULL)
270 return;
271
272 get_tabline_label(tp, TRUE);
273 gui_mch_post_balloon(beval, NameBuff);
274}
275
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000276#endif
277
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278/*
279 * End of call-back routines
280 */
281
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000282/*
283 * Implement three dimensional shading of insensitive labels.
Bram Moolenaara0a83be2005-01-04 21:26:43 +0000284 * By Marcin Dalecki.
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000285 */
286
287#include <Xm/XmP.h>
288#include <Xm/LabelP.h>
289
290static XtExposeProc old_label_expose = NULL;
291
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000292 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100293label_expose(Widget _w, XEvent *_event, Region _region)
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000294{
295 GC insensitiveGC;
296 XmLabelWidget lw = (XmLabelWidget)_w;
Bram Moolenaarb7fcef52005-01-02 11:31:05 +0000297 unsigned char label_type = (int)XmSTRING;
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000298
299 XtVaGetValues(_w, XmNlabelType, &label_type, (XtPointer)0);
300
Bram Moolenaarb7fcef52005-01-02 11:31:05 +0000301 if (XtIsSensitive(_w) || label_type != (int)XmSTRING)
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000302 (*old_label_expose)(_w, _event, _region);
303 else
304 {
305 XGCValues values;
306 XtGCMask mask;
307 XtGCMask dynamic;
308 XFontStruct *fs;
309
310 _XmFontListGetDefaultFont(lw->label.font, &fs);
311
Bram Moolenaar734a8672019-12-02 22:49:38 +0100312 // FIXME: we should be doing the whole drawing ourself here.
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000313 insensitiveGC = lw->label.insensitive_GC;
314
315 mask = GCForeground | GCBackground | GCGraphicsExposures;
316 dynamic = GCClipMask | GCClipXOrigin | GCClipYOrigin;
317 values.graphics_exposures = False;
318
319 if (fs != 0)
320 {
321 mask |= GCFont;
322 values.font = fs->fid;
323 }
324
325 if (lw->primitive.top_shadow_pixmap != None
326 && lw->primitive.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
327 {
328 mask |= GCFillStyle | GCTile;
329 values.fill_style = FillTiled;
330 values.tile = lw->primitive.top_shadow_pixmap;
331 }
332
333 lw->label.TextRect.x += 1;
334 lw->label.TextRect.y += 1;
335 if (lw->label._acc_text != 0)
336 {
337 lw->label.acc_TextRect.x += 1;
338 lw->label.acc_TextRect.y += 1;
339 }
340
341 values.foreground = lw->primitive.top_shadow_color;
342 values.background = lw->core.background_pixel;
343
Bram Moolenaarb7fcef52005-01-02 11:31:05 +0000344 lw->label.insensitive_GC = XtAllocateGC((Widget)lw, 0, mask,
345 &values, dynamic, (XtGCMask)0);
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000346 (*old_label_expose)(_w, _event, _region);
347 XtReleaseGC(_w, lw->label.insensitive_GC);
348
349 lw->label.TextRect.x -= 1;
350 lw->label.TextRect.y -= 1;
351 if (lw->label._acc_text != 0)
352 {
353 lw->label.acc_TextRect.x -= 1;
354 lw->label.acc_TextRect.y -= 1;
355 }
356
357 values.foreground = lw->primitive.bottom_shadow_color;
358 values.background = lw->core.background_pixel;
359
Bram Moolenaarb7fcef52005-01-02 11:31:05 +0000360 lw->label.insensitive_GC = XtAllocateGC((Widget) lw, 0, mask,
361 &values, dynamic, (XtGCMask)0);
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000362 (*old_label_expose)(_w, _event, _region);
363 XtReleaseGC(_w, lw->label.insensitive_GC);
364
365 lw->label.insensitive_GC = insensitiveGC;
366 }
367}
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000368
Bram Moolenaar071d4272004-06-13 20:20:40 +0000369/*
370 * Create all the motif widgets necessary.
371 */
372 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100373gui_x11_create_widgets(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374{
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000375#ifdef FEAT_GUI_TABLINE
Bram Moolenaar18144c82006-04-12 21:52:12 +0000376 Widget button, scroller;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000377 Arg args[10];
378 int n;
379 XmString xms;
380#endif
381
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000382 /*
383 * Install the 3D shade effect drawing routines.
384 */
385 if (old_label_expose == NULL)
386 {
387 old_label_expose = xmLabelWidgetClass->core_class.expose;
388 xmLabelWidgetClass->core_class.expose = label_expose;
389 }
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000390
Bram Moolenaar071d4272004-06-13 20:20:40 +0000391 /*
392 * Start out by adding the configured border width into the border offset
393 */
394 gui.border_offset = gui.border_width;
395
396 /*
397 * Install the tearOffModel resource converter.
398 */
399#if (XmVersion >= 1002)
400 XmRepTypeInstallTearOffModelConverter();
401#endif
402
Bram Moolenaar734a8672019-12-02 22:49:38 +0100403 // Make sure the "Quit" menu entry of the window manager is ignored
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404 XtVaSetValues(vimShell, XmNdeleteResponse, XmDO_NOTHING, NULL);
405
406 vimForm = XtVaCreateManagedWidget("vimForm",
407 xmFormWidgetClass, vimShell,
408 XmNborderWidth, 0,
409 XmNhighlightThickness, 0,
410 XmNshadowThickness, 0,
411 XmNmarginWidth, 0,
412 XmNmarginHeight, 0,
413 XmNresizePolicy, XmRESIZE_ANY,
414 NULL);
415 gui_motif_menu_colors(vimForm);
416
417#ifdef FEAT_MENU
418 {
Bram Moolenaar734a8672019-12-02 22:49:38 +0100419 Arg al[7]; // Make sure there is enough room for arguments!
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420 int ac = 0;
421
422# if (XmVersion >= 1002)
423 XtSetArg(al[ac], XmNtearOffModel, tearoff_val); ac++;
424# endif
425 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
426 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
427 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
428# ifndef FEAT_TOOLBAR
Bram Moolenaar734a8672019-12-02 22:49:38 +0100429 // Always stick to right hand side.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
431# endif
Bram Moolenaarb7fcef52005-01-02 11:31:05 +0000432 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000433 menuBar = XmCreateMenuBar(vimForm, "menuBar", al, ac);
434 XtManageChild(menuBar);
435
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436 gui_motif_menu_colors(menuBar);
437 }
438#endif
439
440#ifdef FEAT_TOOLBAR
441 /*
442 * Create an empty ToolBar. We should get buttons defined from menu.vim.
443 */
444 toolBarFrame = XtVaCreateWidget("toolBarFrame",
445 xmFrameWidgetClass, vimForm,
446 XmNshadowThickness, 0,
447 XmNmarginHeight, 0,
448 XmNmarginWidth, 0,
449 XmNleftAttachment, XmATTACH_FORM,
450 XmNrightAttachment, XmATTACH_FORM,
451 NULL);
452 gui_motif_menu_colors(toolBarFrame);
453
454 toolBar = XtVaCreateManagedWidget("toolBar",
455 xmRowColumnWidgetClass, toolBarFrame,
456 XmNchildType, XmFRAME_WORKAREA_CHILD,
457 XmNrowColumnType, XmWORK_AREA,
458 XmNorientation, XmHORIZONTAL,
459 XmNtraversalOn, False,
460 XmNisHomogeneous, False,
461 XmNpacking, XmPACK_TIGHT,
462 XmNspacing, 0,
463 XmNshadowThickness, 0,
464 XmNhighlightThickness, 0,
465 XmNmarginHeight, 0,
466 XmNmarginWidth, 0,
467 XmNadjustLast, True,
468 NULL);
469 gui_motif_menu_colors(toolBar);
470
Bram Moolenaar071d4272004-06-13 20:20:40 +0000471#endif
472
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000473#ifdef FEAT_GUI_TABLINE
Bram Moolenaar734a8672019-12-02 22:49:38 +0100474 // Create the Vim GUI tabline
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000475 n = 0;
476 XtSetArg(args[n], XmNbindingType, XmNONE); n++;
477 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
478 XtSetArg(args[n], XmNbackPageSize, XmNONE); n++;
479 XtSetArg(args[n], XmNbackPageNumber, 0); n++;
480 XtSetArg(args[n], XmNbackPagePlacement, XmTOP_RIGHT); n++;
481 XtSetArg(args[n], XmNmajorTabSpacing, 0); n++;
482 XtSetArg(args[n], XmNshadowThickness, 0); n++;
483 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
484 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
485 tabLine = XmCreateNotebook(vimForm, "Vim tabline", args, n);
486
487 XtAddCallback(tabLine, XmNpageChangedCallback, (XtCallbackProc)tabline_cb,
488 NULL);
489 XtAddEventHandler(tabLine, ButtonPressMask, False,
490 (XtEventHandler)tabline_menu_cb, NULL);
491
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000492 gui.tabline_height = TABLINE_HEIGHT;
493
Bram Moolenaar18144c82006-04-12 21:52:12 +0000494 /*
495 * Set the size of the minor next/prev scrollers to zero, so
496 * that they are not displayed. Due to a bug in OpenMotif 2.3,
497 * even if these children widget are unmanaged, they are again
498 * managed by the Notebook widget and the notebook widget geometry
499 * is adjusted to account for the minor scroller widgets.
500 */
501 scroller = XtNameToWidget(tabLine, "MinorTabScrollerNext");
502 XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False,
503 XmNtraversalOn, False, NULL);
504 scroller = XtNameToWidget(tabLine, "MinorTabScrollerPrevious");
505 XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False,
506 XmNtraversalOn, False, NULL);
507
Bram Moolenaar29547192018-12-11 20:39:19 +0100508 // Create the tabline popup menu
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000509 tabLine_menu = XmCreatePopupMenu(tabLine, "tabline popup", NULL, 0);
510
Bram Moolenaar29547192018-12-11 20:39:19 +0100511 // Add the buttons to the tabline popup menu
512 n = 0;
Bram Moolenaar9dd42a62022-03-24 18:04:49 +0000513 XtSetArg(args[n], XmNuserData, (XtPointer)TABLINE_MENU_CLOSE); n++;
Bram Moolenaar29547192018-12-11 20:39:19 +0100514 xms = XmStringCreate((char *)"Close tab", STRING_TAG);
515 XtSetArg(args[n], XmNlabelString, xms); n++;
516 button = XmCreatePushButton(tabLine_menu, "Close", args, n);
517 XtAddCallback(button, XmNactivateCallback,
518 (XtCallbackProc)tabline_button_cb, NULL);
519 XmStringFree(xms);
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000520
521 n = 0;
Bram Moolenaar9dd42a62022-03-24 18:04:49 +0000522 XtSetArg(args[n], XmNuserData, (XtPointer)TABLINE_MENU_NEW); n++;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000523 xms = XmStringCreate((char *)"New Tab", STRING_TAG);
524 XtSetArg(args[n], XmNlabelString, xms); n++;
525 button = XmCreatePushButton(tabLine_menu, "New Tab", args, n);
526 XtAddCallback(button, XmNactivateCallback,
527 (XtCallbackProc)tabline_button_cb, NULL);
528 XmStringFree(xms);
529
530 n = 0;
Bram Moolenaar9dd42a62022-03-24 18:04:49 +0000531 XtSetArg(args[n], XmNuserData, (XtPointer)TABLINE_MENU_OPEN); n++;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000532 xms = XmStringCreate((char *)"Open tab...", STRING_TAG);
533 XtSetArg(args[n], XmNlabelString, xms); n++;
534 button = XmCreatePushButton(tabLine_menu, "Open tab...", args, n);
535 XtAddCallback(button, XmNactivateCallback,
536 (XtCallbackProc)tabline_button_cb, NULL);
537 XmStringFree(xms);
538#endif
539
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 textAreaForm = XtVaCreateManagedWidget("textAreaForm",
541 xmFormWidgetClass, vimForm,
542 XmNleftAttachment, XmATTACH_FORM,
543 XmNrightAttachment, XmATTACH_FORM,
544 XmNbottomAttachment, XmATTACH_FORM,
545 XmNtopAttachment, XmATTACH_FORM,
546 XmNmarginWidth, 0,
547 XmNmarginHeight, 0,
548 XmNresizePolicy, XmRESIZE_ANY,
549 NULL);
550 gui_motif_scroll_colors(textAreaForm);
551
552 textArea = XtVaCreateManagedWidget("textArea",
553 xmDrawingAreaWidgetClass, textAreaForm,
554 XmNforeground, gui.norm_pixel,
555 XmNbackground, gui.back_pixel,
556 XmNleftAttachment, XmATTACH_FORM,
557 XmNtopAttachment, XmATTACH_FORM,
558 XmNrightAttachment, XmATTACH_FORM,
559 XmNbottomAttachment, XmATTACH_FORM,
560
561 /*
562 * These take some control away from the user, but avoids making them
563 * add resources to get a decent looking setup.
564 */
565 XmNborderWidth, 0,
566 XmNhighlightThickness, 0,
567 XmNshadowThickness, 0,
568 NULL);
569
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 /*
571 * Install the callbacks.
572 */
573 gui_x11_callbacks(textArea, vimForm);
574
Bram Moolenaar734a8672019-12-02 22:49:38 +0100575 // Pretend we don't have input focus, we will get an event if we do.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 gui.in_focus = FALSE;
577}
578
579/*
580 * Called when the GUI is not going to start after all.
581 */
582 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100583gui_x11_destroy_widgets(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584{
585 textArea = NULL;
586#ifdef FEAT_MENU
587 menuBar = NULL;
588#endif
589}
590
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100592gui_mch_set_text_area_pos(
593 int x UNUSED,
594 int y UNUSED,
595 int w UNUSED,
596 int h UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597{
598#ifdef FEAT_TOOLBAR
Bram Moolenaar734a8672019-12-02 22:49:38 +0100599 // Give keyboard focus to the textArea instead of the toolbar.
Bram Moolenaarf9980f12005-01-03 20:58:59 +0000600 reset_focus();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601#endif
602}
603
604 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100605gui_x11_set_back_color(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606{
607 if (textArea != NULL)
608#if (XmVersion >= 1002)
609 XmChangeColor(textArea, gui.back_pixel);
610#else
611 XtVaSetValues(textArea,
612 XmNbackground, gui.back_pixel,
613 NULL);
614#endif
615}
616
617/*
Bram Moolenaar0b962e52022-04-03 18:02:37 +0100618 * Manage dialog centered on pointer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619 */
Bram Moolenaardfccaf02004-12-31 20:56:11 +0000620 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100621manage_centered(Widget dialog_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622{
623 Widget shell = XtParent(dialog_child);
624 Window root, child;
625 unsigned int mask;
626 unsigned int width, height, border_width, depth;
627 int x, y, win_x, win_y, maxX, maxY;
628 Boolean mappedWhenManaged;
629
Bram Moolenaar734a8672019-12-02 22:49:38 +0100630 // Temporarily set value of XmNmappedWhenManaged
631 // to stop the dialog from popping up right away
Bram Moolenaar46784652008-06-20 09:40:11 +0000632 XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, NULL);
633 XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634
635 XtManageChild(dialog_child);
636
Bram Moolenaar734a8672019-12-02 22:49:38 +0100637 // Get the pointer position (x, y)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child,
639 &x, &y, &win_x, &win_y, &mask);
640
Bram Moolenaar734a8672019-12-02 22:49:38 +0100641 // Translate the pointer position (x, y) into a position for the new
642 // window that will place the pointer at its center
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &win_x, &win_y,
644 &width, &height, &border_width, &depth);
645 width += 2 * border_width;
646 height += 2 * border_width;
647 x -= width / 2;
648 y -= height / 2;
649
Bram Moolenaar734a8672019-12-02 22:49:38 +0100650 // Ensure that the dialog remains on screen
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 maxX = XtScreen(shell)->width - width;
652 maxY = XtScreen(shell)->height - height;
653 if (x < 0)
654 x = 0;
655 if (x > maxX)
656 x = maxX;
657 if (y < 0)
658 y = 0;
659 if (y > maxY)
660 y = maxY;
661
Bram Moolenaar734a8672019-12-02 22:49:38 +0100662 // Set desired window position in the DialogShell
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663 XtVaSetValues(shell, XmNx, x, XmNy, y, NULL);
664
Bram Moolenaar734a8672019-12-02 22:49:38 +0100665 // Map the widget
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 XtMapWidget(shell);
667
Bram Moolenaar734a8672019-12-02 22:49:38 +0100668 // Restore the value of XmNmappedWhenManaged
Bram Moolenaar46784652008-06-20 09:40:11 +0000669 XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670}
671
Bram Moolenaarbb1969b2019-01-17 15:45:25 +0100672#if defined(FEAT_MENU) || defined(FEAT_GUI_DIALOG) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673
674/*
675 * Encapsulate the way an XmFontList is created.
676 */
677 XmFontList
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100678gui_motif_create_fontlist(XFontStruct *font)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679{
680 XmFontList font_list;
681
682# if (XmVersion <= 1001)
Bram Moolenaar734a8672019-12-02 22:49:38 +0100683 // Motif 1.1 method
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 font_list = XmFontListCreate(font, STRING_TAG);
685# else
Bram Moolenaar734a8672019-12-02 22:49:38 +0100686 // Motif 1.2 method
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 XmFontListEntry font_list_entry;
688
689 font_list_entry = XmFontListEntryCreate(STRING_TAG, XmFONT_IS_FONT,
690 (XtPointer)font);
691 font_list = XmFontListAppendEntry(NULL, font_list_entry);
692 XmFontListEntryFree(&font_list_entry);
693# endif
694 return font_list;
695}
696
697# if ((XmVersion > 1001) && defined(FEAT_XFONTSET)) || defined(PROTO)
698 XmFontList
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100699gui_motif_fontset2fontlist(XFontSet *fontset)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700{
701 XmFontList font_list;
702
Bram Moolenaar734a8672019-12-02 22:49:38 +0100703 // Motif 1.2 method
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 XmFontListEntry font_list_entry;
705
706 font_list_entry = XmFontListEntryCreate(STRING_TAG,
707 XmFONT_IS_FONTSET,
708 (XtPointer)*fontset);
709 font_list = XmFontListAppendEntry(NULL, font_list_entry);
710 XmFontListEntryFree(&font_list_entry);
711 return font_list;
712}
713# endif
714
715#endif
716
717#if defined(FEAT_MENU) || defined(PROTO)
718/*
719 * Menu stuff.
720 */
721
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100722static void gui_motif_add_actext(vimmenu_T *menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723#if (XmVersion >= 1002)
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100724static void toggle_tearoff(Widget wid);
725static void gui_mch_recurse_tearoffs(vimmenu_T *menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726#endif
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100727static void submenu_change(vimmenu_T *mp, int colors);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000728
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100729static void do_set_mnemonics(int enable);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000730static int menu_enabled = TRUE;
731
732 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100733gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734{
735 if (flag)
736 {
737 XtManageChild(menuBar);
738#ifdef FEAT_TOOLBAR
739 if (XtIsManaged(XtParent(toolBar)))
740 {
Bram Moolenaar734a8672019-12-02 22:49:38 +0100741 // toolBar is attached to top form
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 XtVaSetValues(XtParent(toolBar),
743 XmNtopAttachment, XmATTACH_WIDGET,
744 XmNtopWidget, menuBar,
745 NULL);
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000746#ifdef FEAT_GUI_TABLINE
747 if (showing_tabline)
748 {
749 XtVaSetValues(tabLine,
750 XmNtopAttachment, XmATTACH_WIDGET,
751 XmNtopWidget, XtParent(toolBar),
752 NULL);
753 XtVaSetValues(textAreaForm,
754 XmNtopAttachment, XmATTACH_WIDGET,
755 XmNtopWidget, tabLine,
756 NULL);
757 }
758 else
759#endif
760 XtVaSetValues(textAreaForm,
761 XmNtopAttachment, XmATTACH_WIDGET,
762 XmNtopWidget, XtParent(toolBar),
763 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 }
765 else
766#endif
767 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000768#ifdef FEAT_GUI_TABLINE
769 if (showing_tabline)
770 {
771 XtVaSetValues(tabLine,
772 XmNtopAttachment, XmATTACH_WIDGET,
773 XmNtopWidget, menuBar,
774 NULL);
775 XtVaSetValues(textAreaForm,
776 XmNtopAttachment, XmATTACH_WIDGET,
777 XmNtopWidget, tabLine,
778 NULL);
779 }
780 else
781#endif
782 XtVaSetValues(textAreaForm,
783 XmNtopAttachment, XmATTACH_WIDGET,
784 XmNtopWidget, menuBar,
785 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 }
787 }
788 else
789 {
790 XtUnmanageChild(menuBar);
791#ifdef FEAT_TOOLBAR
792 if (XtIsManaged(XtParent(toolBar)))
793 {
794 XtVaSetValues(XtParent(toolBar),
795 XmNtopAttachment, XmATTACH_FORM,
796 NULL);
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000797#ifdef FEAT_GUI_TABLINE
798 if (showing_tabline)
799 {
800 XtVaSetValues(tabLine,
801 XmNtopAttachment, XmATTACH_WIDGET,
802 XmNtopWidget, XtParent(toolBar),
803 NULL);
804 XtVaSetValues(textAreaForm,
805 XmNtopAttachment, XmATTACH_WIDGET,
806 XmNtopWidget, tabLine,
807 NULL);
808 }
809 else
810#endif
811 XtVaSetValues(textAreaForm,
812 XmNtopAttachment, XmATTACH_WIDGET,
813 XmNtopWidget, XtParent(toolBar),
814 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 }
816 else
817#endif
818 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000819#ifdef FEAT_GUI_TABLINE
820 if (showing_tabline)
821 {
822 XtVaSetValues(tabLine,
823 XmNtopAttachment, XmATTACH_FORM,
824 NULL);
825 XtVaSetValues(textAreaForm,
826 XmNtopAttachment, XmATTACH_WIDGET,
827 XmNtopWidget, tabLine,
828 NULL);
829 }
830 else
831#endif
832 XtVaSetValues(textAreaForm,
833 XmNtopAttachment, XmATTACH_FORM,
834 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 }
836 }
837
838}
839
840/*
841 * Enable or disable mnemonics for the toplevel menus.
842 */
843 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100844gui_motif_set_mnemonics(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845{
846 /*
847 * Don't enable menu mnemonics when the menu bar is disabled, LessTif
848 * crashes when using a mnemonic then.
849 */
850 if (!menu_enabled)
851 enable = FALSE;
852 do_set_mnemonics(enable);
853}
854
855 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100856do_set_mnemonics(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857{
858 vimmenu_T *menu;
859
Bram Moolenaar00d253e2020-04-06 22:13:01 +0200860 FOR_ALL_MENUS(menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 if (menu->id != (Widget)0)
862 XtVaSetValues(menu->id,
863 XmNmnemonic, enable ? menu->mnemonic : NUL,
864 NULL);
865}
866
867 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100868gui_mch_add_menu(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869{
870 XmString label;
871 Widget shell;
872 vimmenu_T *parent = menu->parent;
873
874#ifdef MOTIF_POPUP
875 if (menu_is_popup(menu->name))
876 {
877 Arg arg[2];
878 int n = 0;
879
Bram Moolenaar734a8672019-12-02 22:49:38 +0100880 // Only create the popup menu when it's actually used, otherwise there
881 // is a delay when using the right mouse button.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882# if (XmVersion <= 1002)
883 if (mouse_model_popup())
884# endif
885 {
886 if (gui.menu_bg_pixel != INVALCOLOR)
Bram Moolenaar7795bfe2020-09-20 19:57:15 +0200887 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 XtSetArg(arg[0], XmNbackground, gui.menu_bg_pixel); n++;
Bram Moolenaar7795bfe2020-09-20 19:57:15 +0200889 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 if (gui.menu_fg_pixel != INVALCOLOR)
Bram Moolenaar7795bfe2020-09-20 19:57:15 +0200891 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000892 XtSetArg(arg[1], XmNforeground, gui.menu_fg_pixel); n++;
Bram Moolenaar7795bfe2020-09-20 19:57:15 +0200893 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 menu->submenu_id = XmCreatePopupMenu(textArea, "contextMenu",
895 arg, n);
896 menu->id = (Widget)0;
897 }
898 return;
899 }
900#endif
901
902 if (!menu_is_menubar(menu->name)
903 || (parent != NULL && parent->submenu_id == (Widget)0))
904 return;
905
906 label = XmStringCreate((char *)menu->dname, STRING_TAG);
907 if (label == NULL)
908 return;
909 menu->id = XtVaCreateWidget("subMenu",
910 xmCascadeButtonWidgetClass,
911 (parent == NULL) ? menuBar : parent->submenu_id,
912 XmNlabelString, label,
913 XmNmnemonic, p_wak[0] == 'n' ? NUL : menu->mnemonic,
914#if (XmVersion >= 1002)
Bram Moolenaar734a8672019-12-02 22:49:38 +0100915 // submenu: count the tearoff item (needed for LessTif)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 XmNpositionIndex, idx + (parent != NULL
917 && tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0),
918#endif
919 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920 XmStringFree(label);
921
Bram Moolenaar734a8672019-12-02 22:49:38 +0100922 if (menu->id == (Widget)0) // failed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923 return;
924
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +0100925 // The "Help" menu is a special case, and should be placed at the far
926 // right hand side of the menu-bar. It's recognized by its high priority.
927 if (parent == NULL && menu->priority >= 9999)
928 XtVaSetValues(menuBar,
929 XmNmenuHelpWidget, menu->id,
930 NULL);
931
932 gui_motif_menu_colors(menu->id);
933 gui_motif_menu_fontlist(menu->id);
934
Bram Moolenaar734a8672019-12-02 22:49:38 +0100935 // add accelerator text
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 gui_motif_add_actext(menu);
937
938 shell = XtVaCreateWidget("subMenuShell",
939 xmMenuShellWidgetClass, menu->id,
940 XmNwidth, 1,
941 XmNheight, 1,
942 NULL);
943 gui_motif_menu_colors(shell);
944 menu->submenu_id = XtVaCreateWidget("rowColumnMenu",
945 xmRowColumnWidgetClass, shell,
946 XmNrowColumnType, XmMENU_PULLDOWN,
947 NULL);
948 gui_motif_menu_colors(menu->submenu_id);
949
Bram Moolenaar734a8672019-12-02 22:49:38 +0100950 if (menu->submenu_id == (Widget)0) // failed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000951 return;
952
953#if (XmVersion >= 1002)
Bram Moolenaar734a8672019-12-02 22:49:38 +0100954 // Set the colors for the tear off widget
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955 toggle_tearoff(menu->submenu_id);
956#endif
957
958 XtVaSetValues(menu->id,
959 XmNsubMenuId, menu->submenu_id,
960 NULL);
961
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +0100962 // When we add a top-level item to the menu bar, we can figure out how
963 // high the menu bar should be.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 if (parent == NULL)
965 gui_mch_compute_menu_height(menu->id);
966}
967
968
969/*
970 * Add mnemonic and accelerator text to a menu button.
971 */
972 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100973gui_motif_add_actext(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974{
975 XmString label;
976
Bram Moolenaar734a8672019-12-02 22:49:38 +0100977 // Add accelerator text, if there is one
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978 if (menu->actext != NULL && menu->id != (Widget)0)
979 {
980 label = XmStringCreate((char *)menu->actext, STRING_TAG);
981 if (label == NULL)
982 return;
983 XtVaSetValues(menu->id, XmNacceleratorText, label, NULL);
984 XmStringFree(label);
985 }
986}
987
988 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100989gui_mch_toggle_tearoffs(int enable)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990{
991#if (XmVersion >= 1002)
992 if (enable)
993 tearoff_val = (int)XmTEAR_OFF_ENABLED;
994 else
995 tearoff_val = (int)XmTEAR_OFF_DISABLED;
996 toggle_tearoff(menuBar);
997 gui_mch_recurse_tearoffs(root_menu);
998#endif
999}
1000
1001#if (XmVersion >= 1002)
1002/*
1003 * Set the tearoff for one menu widget on or off, and set the color of the
1004 * tearoff widget.
1005 */
1006 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001007toggle_tearoff(Widget wid)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008{
1009 Widget w;
1010
1011 XtVaSetValues(wid, XmNtearOffModel, tearoff_val, NULL);
1012 if (tearoff_val == (int)XmTEAR_OFF_ENABLED
1013 && (w = XmGetTearOffControl(wid)) != (Widget)0)
1014 gui_motif_menu_colors(w);
1015}
1016
1017 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001018gui_mch_recurse_tearoffs(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019{
1020 while (menu != NULL)
1021 {
1022 if (!menu_is_popup(menu->name))
1023 {
1024 if (menu->submenu_id != (Widget)0)
1025 toggle_tearoff(menu->submenu_id);
1026 gui_mch_recurse_tearoffs(menu->children);
1027 }
1028 menu = menu->next;
1029 }
1030}
1031#endif
1032
1033 int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001034gui_mch_text_area_extra_height(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035{
1036 Dimension shadowHeight;
1037
1038 XtVaGetValues(textAreaForm, XmNshadowThickness, &shadowHeight, NULL);
1039 return shadowHeight;
1040}
1041
1042/*
1043 * Compute the height of the menu bar.
1044 * We need to check all the items for their position and height, for the case
1045 * there are several rows, and/or some characters extend higher or lower.
1046 */
1047 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001048gui_mch_compute_menu_height(
Bram Moolenaar734a8672019-12-02 22:49:38 +01001049 Widget id) // can be NULL when deleting menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050{
1051 Dimension y, maxy;
1052 Dimension margin, shadow;
1053 vimmenu_T *mp;
Bram Moolenaar734a8672019-12-02 22:49:38 +01001054 static Dimension height = 21; // normal height of a menu item
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055
1056 /*
1057 * Get the height of the new item, before managing it, because it will
1058 * still reflect the font size. After managing it depends on the menu
1059 * height, which is what we just wanted to get!.
1060 */
1061 if (id != (Widget)0)
1062 XtVaGetValues(id, XmNheight, &height, NULL);
1063
Bram Moolenaar734a8672019-12-02 22:49:38 +01001064 // Find any menu Widget, to be able to call XtManageChild()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065 else
Bram Moolenaar00d253e2020-04-06 22:13:01 +02001066 FOR_ALL_MENUS(mp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067 if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
1068 {
1069 id = mp->id;
1070 break;
1071 }
1072
1073 /*
1074 * Now manage the menu item, to make them all be positioned (makes an
1075 * extra row when needed, removes it when not needed).
1076 */
1077 if (id != (Widget)0)
1078 XtManageChild(id);
1079
1080 /*
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01001081 * Now find the menu item that is the furthest down, and get its position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 */
1083 maxy = 0;
Bram Moolenaar00d253e2020-04-06 22:13:01 +02001084 FOR_ALL_MENUS(mp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085 {
1086 if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
1087 {
1088 XtVaGetValues(mp->id, XmNy, &y, NULL);
1089 if (y > maxy)
1090 maxy = y;
1091 }
1092 }
1093
1094 XtVaGetValues(menuBar,
1095 XmNmarginHeight, &margin,
1096 XmNshadowThickness, &shadow,
1097 NULL);
1098
1099 /*
1100 * This computation is the result of trial-and-error:
1101 * maxy = The maximum position of an item; required for when there are
1102 * two or more rows
1103 * height = height of an item, before managing it; Hopefully this will
1104 * change with the font height. Includes shadow-border.
1105 * shadow = shadow-border; must be subtracted from the height.
1106 * margin = margin around the menu buttons; Must be added.
1107 * Add 4 for the underlining of shortcut keys.
1108 */
1109 gui.menu_height = maxy + height - 2 * shadow + 2 * margin + 4;
1110
Bram Moolenaar734a8672019-12-02 22:49:38 +01001111 // Somehow the menu bar doesn't resize automatically. Set it here,
1112 // even though this is a catch 22. Don't do this when starting up,
1113 // somehow the menu gets very high then.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114 if (gui.shell_created)
1115 XtVaSetValues(menuBar, XmNheight, gui.menu_height, NULL);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001116}
1117
Bram Moolenaarb23c3382005-01-31 19:09:12 +00001118#ifdef FEAT_TOOLBAR
1119
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001120/*
1121 * Icons used by the toolbar code.
1122 */
1123#include "gui_x11_pm.h"
1124
Bram Moolenaard25c16e2016-01-29 22:13:30 +01001125static char **get_toolbar_pixmap(vimmenu_T *menu, char **fname);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001126
1127/*
1128 * Read an Xpm file. Return OK or FAIL.
1129 */
1130 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001131check_xpm(char_u *path)
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001132{
1133 XpmAttributes attrs;
1134 int status;
1135 Pixmap mask;
1136 Pixmap map;
1137
1138 attrs.valuemask = 0;
1139
Bram Moolenaar734a8672019-12-02 22:49:38 +01001140 // Create the "sensitive" pixmap
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001141 status = XpmReadFileToPixmap(gui.dpy,
1142 RootWindow(gui.dpy, DefaultScreen(gui.dpy)),
1143 (char *)path, &map, &mask, &attrs);
1144 XpmFreeAttributes(&attrs);
1145
1146 if (status == XpmSuccess)
1147 return OK;
1148 return FAIL;
1149}
1150
1151
1152/*
1153 * Allocated a pixmap for toolbar menu "menu".
Bram Moolenaar7c626922005-02-07 22:01:03 +00001154 * When it's to be read from a file, "fname" is set to the file name
1155 * (in allocated memory).
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001156 * Return a blank pixmap if it fails.
1157 */
1158 static char **
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001159get_toolbar_pixmap(vimmenu_T *menu, char **fname)
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001160{
Bram Moolenaar734a8672019-12-02 22:49:38 +01001161 char_u buf[MAXPATHL]; // buffer storing expanded pathname
1162 char **xpm = NULL; // xpm array
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001163 int res;
1164
Bram Moolenaar7c626922005-02-07 22:01:03 +00001165 *fname = NULL;
Bram Moolenaar734a8672019-12-02 22:49:38 +01001166 buf[0] = NUL; // start with NULL path
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001167
1168 if (menu->iconfile != NULL)
1169 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01001170 // Use the "icon=" argument.
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001171 gui_find_iconfile(menu->iconfile, buf, "xpm");
1172 res = check_xpm(buf);
1173
Bram Moolenaar734a8672019-12-02 22:49:38 +01001174 // If it failed, try using the menu name.
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001175 if (res == FAIL && gui_find_bitmap(menu->name, buf, "xpm") == OK)
1176 res = check_xpm(buf);
1177 if (res == OK)
Bram Moolenaar7c626922005-02-07 22:01:03 +00001178 {
1179 *fname = (char *)vim_strsave(buf);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001180 return tb_blank_xpm;
Bram Moolenaar7c626922005-02-07 22:01:03 +00001181 }
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001182 }
1183
1184 if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL)
1185 {
1186 if (menu->iconidx >= 0 && menu->iconidx
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00001187 < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0])))
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001188 xpm = built_in_pixmaps[menu->iconidx];
1189 else
1190 xpm = tb_blank_xpm;
1191 }
1192
1193 return xpm;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001194}
Bram Moolenaar7c626922005-02-07 22:01:03 +00001195
1196/*
1197 * Add arguments for the toolbar pixmap to a menu item.
1198 */
1199 static int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001200add_pixmap_args(vimmenu_T *menu, Arg *args, int n)
Bram Moolenaar7c626922005-02-07 22:01:03 +00001201{
1202 vim_free(menu->xpm_fname);
1203 menu->xpm = get_toolbar_pixmap(menu, &menu->xpm_fname);
1204 if (menu->xpm == NULL)
1205 {
1206 XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
1207 }
1208 else
1209 {
1210 if (menu->xpm_fname != NULL)
Bram Moolenaar26cd3062020-09-20 21:13:27 +02001211 {
Bram Moolenaar7c626922005-02-07 22:01:03 +00001212 XtSetArg(args[n], XmNpixmapFile, menu->xpm_fname); n++;
Bram Moolenaar26cd3062020-09-20 21:13:27 +02001213 }
Bram Moolenaar7c626922005-02-07 22:01:03 +00001214 XtSetArg(args[n], XmNpixmapData, menu->xpm); n++;
1215 XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++;
1216 }
1217 return n;
1218}
Bram Moolenaar734a8672019-12-02 22:49:38 +01001219#endif // FEAT_TOOLBAR
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220
1221 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001222gui_mch_add_menu_item(vimmenu_T *menu, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223{
1224 XmString label;
1225 vimmenu_T *parent = menu->parent;
1226
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227# if (XmVersion <= 1002)
Bram Moolenaar734a8672019-12-02 22:49:38 +01001228 // Don't add Popup menu items when the popup menu isn't used.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 if (menu_is_child_of_popup(menu) && !mouse_model_popup())
1230 return;
1231# endif
1232
1233# ifdef FEAT_TOOLBAR
1234 if (menu_is_toolbar(parent->name))
1235 {
1236 WidgetClass type;
Bram Moolenaar734a8672019-12-02 22:49:38 +01001237 XmString xms = NULL; // fallback label if pixmap not found
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 int n;
1239 Arg args[18];
1240
1241 n = 0;
1242 if (menu_is_separator(menu->name))
1243 {
1244 char *cp;
1245 Dimension wid;
1246
1247 /*
1248 * A separator has the format "-sep%d[:%d]-". The optional :%d is
1249 * a width specifier. If no width is specified then we choose one.
1250 */
1251 cp = (char *)vim_strchr(menu->name, ':');
1252 if (cp != NULL)
1253 wid = (Dimension)atoi(++cp);
1254 else
1255 wid = 4;
1256
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 type = xmSeparatorWidgetClass;
1258 XtSetArg(args[n], XmNwidth, wid); n++;
1259 XtSetArg(args[n], XmNminWidth, wid); n++;
1260 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001261 XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 }
1263 else
1264 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01001265 // Without shadows one can't sense whatever the button has been
1266 // pressed or not! However we want to save a bit of space...
1267 // Need the highlightThickness to see the focus.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001268 XtSetArg(args[n], XmNhighlightThickness, 1); n++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 XtSetArg(args[n], XmNhighlightOnEnter, True); n++;
1270 XtSetArg(args[n], XmNmarginWidth, 0); n++;
1271 XtSetArg(args[n], XmNmarginHeight, 0); n++;
Bram Moolenaarf9980f12005-01-03 20:58:59 +00001272 XtSetArg(args[n], XmNtraversalOn, False); n++;
Bram Moolenaar734a8672019-12-02 22:49:38 +01001273 // Set the label here, so that we can switch between icons/text
1274 // by changing the XmNlabelType resource.
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001275 xms = XmStringCreate((char *)menu->dname, STRING_TAG);
1276 XtSetArg(args[n], XmNlabelString, xms); n++;
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001277
Bram Moolenaar7c626922005-02-07 22:01:03 +00001278 n = add_pixmap_args(menu, args, n);
1279
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001280 type = xmEnhancedButtonWidgetClass;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281 }
1282
1283 XtSetArg(args[n], XmNpositionIndex, idx); n++;
1284 if (menu->id == NULL)
1285 {
1286 menu->id = XtCreateManagedWidget((char *)menu->dname,
1287 type, toolBar, args, n);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001288 if (menu->id != NULL && type == xmEnhancedButtonWidgetClass)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289 {
1290 XtAddCallback(menu->id,
1291 XmNactivateCallback, gui_x11_menu_cb, menu);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292 }
1293 }
1294 else
1295 XtSetValues(menu->id, args, n);
1296 if (xms != NULL)
1297 XmStringFree(xms);
1298
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001299# ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 gui_mch_menu_set_tip(menu);
Bram Moolenaarf193fff2006-04-27 00:02:13 +00001301# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302
1303 menu->parent = parent;
1304 menu->submenu_id = NULL;
Bram Moolenaar734a8672019-12-02 22:49:38 +01001305 // When adding first item to toolbar it might have to be enabled .
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306 if (!XtIsManaged(XtParent(toolBar))
1307 && vim_strchr(p_go, GO_TOOLBAR) != NULL)
1308 gui_mch_show_toolbar(TRUE);
1309 gui.toolbar_height = gui_mch_compute_toolbar_height();
1310 return;
Bram Moolenaar734a8672019-12-02 22:49:38 +01001311 } // toolbar menu item
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312# endif
1313
Bram Moolenaar734a8672019-12-02 22:49:38 +01001314 // No parent, must be a non-menubar menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 if (parent->submenu_id == (Widget)0)
1316 return;
1317
1318 menu->submenu_id = (Widget)0;
1319
Bram Moolenaar734a8672019-12-02 22:49:38 +01001320 // Add menu separator
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321 if (menu_is_separator(menu->name))
1322 {
1323 menu->id = XtVaCreateWidget("subMenu",
1324 xmSeparatorGadgetClass, parent->submenu_id,
1325#if (XmVersion >= 1002)
Bram Moolenaar734a8672019-12-02 22:49:38 +01001326 // count the tearoff item (needed for LessTif)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327 XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
1328 ? 1 : 0),
1329#endif
1330 NULL);
1331 gui_motif_menu_colors(menu->id);
1332 return;
1333 }
1334
1335 label = XmStringCreate((char *)menu->dname, STRING_TAG);
1336 if (label == NULL)
1337 return;
1338 menu->id = XtVaCreateWidget("subMenu",
1339 xmPushButtonWidgetClass, parent->submenu_id,
1340 XmNlabelString, label,
1341 XmNmnemonic, menu->mnemonic,
1342#if (XmVersion >= 1002)
Bram Moolenaar734a8672019-12-02 22:49:38 +01001343 // count the tearoff item (needed for LessTif)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001344 XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
1345 ? 1 : 0),
1346#endif
1347 NULL);
1348 gui_motif_menu_colors(menu->id);
1349 gui_motif_menu_fontlist(menu->id);
1350 XmStringFree(label);
1351
1352 if (menu->id != (Widget)0)
1353 {
1354 XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb,
1355 (XtPointer)menu);
Bram Moolenaar734a8672019-12-02 22:49:38 +01001356 // add accelerator text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001357 gui_motif_add_actext(menu);
1358 }
1359}
1360
1361#if (XmVersion <= 1002) || defined(PROTO)
1362/*
1363 * This function will destroy/create the popup menus dynamically,
1364 * according to the value of 'mousemodel'.
1365 * This will fix the "right mouse button freeze" that occurs when
1366 * there exists a popup menu but it isn't managed.
1367 */
1368 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001369gui_motif_update_mousemodel(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001370{
1371 int idx = 0;
1372
Bram Moolenaar734a8672019-12-02 22:49:38 +01001373 // When GUI hasn't started the menus have not been created.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001374 if (!gui.in_use)
1375 return;
1376
1377 while (menu)
1378 {
1379 if (menu->children != NULL)
1380 {
1381 if (menu_is_popup(menu->name))
1382 {
1383 if (mouse_model_popup())
1384 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01001385 // Popup menu will be used. Create the popup menus.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001386 gui_mch_add_menu(menu, idx);
1387 gui_motif_update_mousemodel(menu->children);
1388 }
1389 else
1390 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01001391 // Popup menu will not be used. Destroy the popup menus.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001392 gui_motif_update_mousemodel(menu->children);
1393 gui_mch_destroy_menu(menu);
1394 }
1395 }
1396 }
1397 else if (menu_is_child_of_popup(menu))
1398 {
1399 if (mouse_model_popup())
1400 gui_mch_add_menu_item(menu, idx);
1401 else
1402 gui_mch_destroy_menu(menu);
1403 }
1404 menu = menu->next;
1405 ++idx;
1406 }
1407}
1408#endif
1409
1410 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001411gui_mch_new_menu_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001412{
1413 if (menuBar == (Widget)0)
1414 return;
1415 gui_motif_menu_colors(menuBar);
1416#ifdef FEAT_TOOLBAR
1417 gui_motif_menu_colors(toolBarFrame);
1418 gui_motif_menu_colors(toolBar);
1419#endif
1420
Bram Moolenaarf9980f12005-01-03 20:58:59 +00001421 submenu_change(root_menu, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001422}
1423
1424 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001425gui_mch_new_menu_font(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426{
1427 if (menuBar == (Widget)0)
1428 return;
Bram Moolenaarf9980f12005-01-03 20:58:59 +00001429 submenu_change(root_menu, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001430 {
1431 Dimension height;
1432 Position w, h;
1433
1434 XtVaGetValues(menuBar, XmNheight, &height, NULL);
1435 gui.menu_height = height;
1436
1437 XtVaGetValues(vimShell, XtNwidth, &w, XtNheight, &h, NULL);
1438 gui_resize_shell(w, h
1439#ifdef FEAT_XIM
1440 - xim_get_status_area_height()
1441#endif
1442 );
1443 }
Bram Moolenaar2e2a2812006-03-27 20:55:21 +00001444 gui_set_shellsize(FALSE, TRUE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001445 ui_new_shellsize();
1446}
1447
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001448#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001449 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001450gui_mch_new_tooltip_font(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001451{
1452# ifdef FEAT_TOOLBAR
1453 vimmenu_T *menu;
1454
1455 if (toolBar == (Widget)0)
1456 return;
1457
1458 menu = gui_find_menu((char_u *)"ToolBar");
1459 if (menu != NULL)
Bram Moolenaarf9980f12005-01-03 20:58:59 +00001460 submenu_change(menu, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001461# endif
1462}
1463
1464 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001465gui_mch_new_tooltip_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466{
1467# ifdef FEAT_TOOLBAR
1468 vimmenu_T *toolbar;
1469
1470 if (toolBar == (Widget)0)
1471 return;
1472
1473 toolbar = gui_find_menu((char_u *)"ToolBar");
1474 if (toolbar != NULL)
Bram Moolenaarf9980f12005-01-03 20:58:59 +00001475 submenu_change(toolbar, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476# endif
1477}
1478#endif
1479
1480 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001481submenu_change(
1482 vimmenu_T *menu,
Bram Moolenaar734a8672019-12-02 22:49:38 +01001483 int colors) // TRUE for colors, FALSE for font
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484{
1485 vimmenu_T *mp;
1486
1487 for (mp = menu; mp != NULL; mp = mp->next)
1488 {
1489 if (mp->id != (Widget)0)
1490 {
1491 if (colors)
1492 {
1493 gui_motif_menu_colors(mp->id);
1494#ifdef FEAT_TOOLBAR
Bram Moolenaar734a8672019-12-02 22:49:38 +01001495 // For a toolbar item: Free the pixmap and allocate a new one,
1496 // so that the background color is right.
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001497 if (mp->xpm != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498 {
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001499 int n = 0;
1500 Arg args[18];
1501
Bram Moolenaar7c626922005-02-07 22:01:03 +00001502 n = add_pixmap_args(mp, args, n);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00001503 XtSetValues(mp->id, args, n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 }
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001505# ifdef FEAT_BEVAL_GUI
Bram Moolenaar734a8672019-12-02 22:49:38 +01001506 // If we have a tooltip, then we need to change its font
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507 if (mp->tip != NULL)
1508 {
1509 Arg args[2];
1510
1511 args[0].name = XmNbackground;
1512 args[0].value = gui.tooltip_bg_pixel;
1513 args[1].name = XmNforeground;
1514 args[1].value = gui.tooltip_fg_pixel;
1515 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1516 }
1517# endif
1518#endif
1519 }
1520 else
1521 {
1522 gui_motif_menu_fontlist(mp->id);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001523#ifdef FEAT_BEVAL_GUI
Bram Moolenaar734a8672019-12-02 22:49:38 +01001524 // If we have a tooltip, then we need to change its font
Bram Moolenaar071d4272004-06-13 20:20:40 +00001525 if (mp->tip != NULL)
1526 {
1527 Arg args[1];
1528
1529 args[0].name = XmNfontList;
1530 args[0].value = (XtArgVal)gui_motif_fontset2fontlist(
1531 &gui.tooltip_fontset);
1532 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1533 }
1534#endif
1535 }
1536 }
1537
1538 if (mp->children != NULL)
1539 {
1540#if (XmVersion >= 1002)
Bram Moolenaar734a8672019-12-02 22:49:38 +01001541 // Set the colors/font for the tear off widget
Bram Moolenaar071d4272004-06-13 20:20:40 +00001542 if (mp->submenu_id != (Widget)0)
1543 {
1544 if (colors)
1545 gui_motif_menu_colors(mp->submenu_id);
1546 else
1547 gui_motif_menu_fontlist(mp->submenu_id);
1548 toggle_tearoff(mp->submenu_id);
1549 }
1550#endif
Bram Moolenaar734a8672019-12-02 22:49:38 +01001551 // Set the colors for the children
Bram Moolenaarf9980f12005-01-03 20:58:59 +00001552 submenu_change(mp->children, colors);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553 }
1554 }
1555}
1556
1557/*
1558 * Destroy the machine specific menu widget.
1559 */
1560 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001561gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001562{
Bram Moolenaar734a8672019-12-02 22:49:38 +01001563 // Please be sure to destroy the parent widget first (i.e. menu->id).
1564 // On the other hand, problems have been reported that the submenu must be
1565 // deleted first...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566 if (menu->submenu_id != (Widget)0)
1567 {
1568 XtDestroyWidget(menu->submenu_id);
1569 menu->submenu_id = (Widget)0;
1570 }
1571
1572 if (menu->id != (Widget)0)
1573 {
1574 Widget parent;
1575
1576 parent = XtParent(menu->id);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001577#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL_GUI)
Bram Moolenaar4317d9b2005-03-18 20:25:31 +00001578 if (parent == toolBar && menu->tip != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01001580 // We try to destroy this before the actual menu, because there are
1581 // callbacks, etc. that will be unregistered during the tooltip
1582 // destruction.
1583 //
1584 // If you call "gui_mch_destroy_beval_area()" after destroying
1585 // menu->id, then the tooltip's window will have already been
1586 // deallocated by Xt, and unknown behaviour will ensue (probably
1587 // a core dump).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588 gui_mch_destroy_beval_area(menu->tip);
1589 menu->tip = NULL;
1590 }
1591#endif
1592 XtDestroyWidget(menu->id);
1593 menu->id = (Widget)0;
1594 if (parent == menuBar)
1595 gui_mch_compute_menu_height((Widget)0);
1596#ifdef FEAT_TOOLBAR
1597 else if (parent == toolBar)
1598 {
1599 Cardinal num_children;
1600
Bram Moolenaar734a8672019-12-02 22:49:38 +01001601 // When removing last toolbar item, don't display the toolbar.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 XtVaGetValues(toolBar, XmNnumChildren, &num_children, NULL);
1603 if (num_children == 0)
1604 gui_mch_show_toolbar(FALSE);
1605 else
1606 gui.toolbar_height = gui_mch_compute_toolbar_height();
1607 }
1608#endif
1609 }
1610}
1611
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001613gui_mch_show_popupmenu(vimmenu_T *menu UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614{
1615#ifdef MOTIF_POPUP
1616 XmMenuPosition(menu->submenu_id, gui_x11_get_last_mouse_event());
1617 XtManageChild(menu->submenu_id);
1618#endif
1619}
1620
Bram Moolenaar734a8672019-12-02 22:49:38 +01001621#endif // FEAT_MENU
Bram Moolenaar071d4272004-06-13 20:20:40 +00001622
1623/*
1624 * Set the menu and scrollbar colors to their default values.
1625 */
1626 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001627gui_mch_def_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001628{
1629 if (gui.in_use)
1630 {
Bram Moolenaare8504392022-03-13 14:45:03 +00001631 gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
1632 gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
1633 gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
1634 gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001635#ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 gui.tooltip_fg_pixel =
1637 gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
1638 gui.tooltip_bg_pixel =
1639 gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
1640#endif
1641 }
1642}
1643
1644
1645/*
1646 * Scrollbar stuff.
1647 */
1648
1649 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001650gui_mch_set_scrollbar_thumb(
1651 scrollbar_T *sb,
1652 long val,
1653 long size,
1654 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001655{
1656 if (sb->id != (Widget)0)
1657 XtVaSetValues(sb->id,
1658 XmNvalue, val,
1659 XmNsliderSize, size,
1660 XmNpageIncrement, (size > 2 ? size - 2 : 1),
Bram Moolenaar734a8672019-12-02 22:49:38 +01001661 XmNmaximum, max + 1, // Motif has max one past the end
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662 NULL);
1663}
1664
1665 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001666gui_mch_set_scrollbar_pos(
1667 scrollbar_T *sb,
1668 int x,
1669 int y,
1670 int w,
1671 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672{
1673 if (sb->id != (Widget)0)
1674 {
1675 if (sb->type == SBAR_LEFT || sb->type == SBAR_RIGHT)
1676 {
1677 if (y == 0)
1678 h -= gui.border_offset;
1679 else
1680 y -= gui.border_offset;
1681 XtVaSetValues(sb->id,
1682 XmNtopOffset, y,
1683 XmNbottomOffset, -y - h,
1684 XmNwidth, w,
1685 NULL);
1686 }
1687 else
1688 XtVaSetValues(sb->id,
1689 XmNtopOffset, y,
1690 XmNleftOffset, x,
1691 XmNrightOffset, gui.which_scrollbars[SBAR_RIGHT]
1692 ? gui.scrollbar_width : 0,
1693 XmNheight, h,
1694 NULL);
1695 XtManageChild(sb->id);
1696 }
1697}
1698
Bram Moolenaar203ec772020-07-17 20:43:43 +02001699 int
1700gui_mch_get_scrollbar_xpadding(void)
1701{
qsmodo28f1a512022-02-07 15:57:50 +00001702 int xpad;
1703 Dimension tw, ww;
1704 Position tx;
1705
1706 XtVaGetValues(textArea, XtNwidth, &tw, XtNx, &tx, NULL);
1707 XtVaGetValues(vimShell, XtNwidth, &ww, NULL);
1708 xpad = ww - tw - tx - gui.scrollbar_width;
1709 return (xpad < 0) ? 0 : xpad;
Bram Moolenaar203ec772020-07-17 20:43:43 +02001710}
1711
1712 int
1713gui_mch_get_scrollbar_ypadding(void)
1714{
qsmodo28f1a512022-02-07 15:57:50 +00001715 int ypad;
1716 Dimension th, wh;
1717 Position ty;
1718
1719 XtVaGetValues(textArea, XtNheight, &th, XtNy, &ty, NULL);
1720 XtVaGetValues(vimShell, XtNheight, &wh, NULL);
1721 ypad = wh - th - ty - gui.scrollbar_height;
1722 return (ypad < 0) ? 0 : ypad;
Bram Moolenaar203ec772020-07-17 20:43:43 +02001723}
1724
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001726gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727{
1728 Arg args[16];
1729 int n;
1730
1731 if (sb->id != (Widget)0)
1732 {
1733 n = 0;
1734 if (flag)
1735 {
1736 switch (sb->type)
1737 {
1738 case SBAR_LEFT:
1739 XtSetArg(args[n], XmNleftOffset, gui.scrollbar_width); n++;
1740 break;
1741
1742 case SBAR_RIGHT:
1743 XtSetArg(args[n], XmNrightOffset, gui.scrollbar_width); n++;
1744 break;
1745
1746 case SBAR_BOTTOM:
1747 XtSetArg(args[n], XmNbottomOffset, gui.scrollbar_height);n++;
1748 break;
1749 }
1750 XtSetValues(textArea, args, n);
1751 XtManageChild(sb->id);
1752 }
1753 else
1754 {
1755 if (!gui.which_scrollbars[sb->type])
1756 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01001757 // The scrollbars of this type are all disabled, adjust the
1758 // textArea attachment offset.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 switch (sb->type)
1760 {
1761 case SBAR_LEFT:
1762 XtSetArg(args[n], XmNleftOffset, 0); n++;
1763 break;
1764
1765 case SBAR_RIGHT:
1766 XtSetArg(args[n], XmNrightOffset, 0); n++;
1767 break;
1768
1769 case SBAR_BOTTOM:
1770 XtSetArg(args[n], XmNbottomOffset, 0);n++;
1771 break;
1772 }
1773 XtSetValues(textArea, args, n);
1774 }
1775 XtUnmanageChild(sb->id);
1776 }
1777 }
1778}
1779
1780 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001781gui_mch_create_scrollbar(
1782 scrollbar_T *sb,
Bram Moolenaar734a8672019-12-02 22:49:38 +01001783 int orient) // SBAR_VERT or SBAR_HORIZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784{
1785 Arg args[16];
1786 int n;
1787
1788 n = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 XtSetArg(args[n], XmNminimum, 0); n++;
1790 XtSetArg(args[n], XmNorientation,
1791 (orient == SBAR_VERT) ? XmVERTICAL : XmHORIZONTAL); n++;
1792
1793 switch (sb->type)
1794 {
1795 case SBAR_LEFT:
1796 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1797 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
1798 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1799 break;
1800
1801 case SBAR_RIGHT:
1802 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1803 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
1804 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1805 break;
1806
1807 case SBAR_BOTTOM:
1808 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1809 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1810 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1811 break;
1812 }
1813
1814 sb->id = XtCreateWidget("scrollBar",
1815 xmScrollBarWidgetClass, textAreaForm, args, n);
1816
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 if (sb->id != (Widget)0)
1818 {
1819 gui_mch_set_scrollbar_colors(sb);
1820 XtAddCallback(sb->id, XmNvalueChangedCallback,
1821 scroll_cb, (XtPointer)sb->ident);
1822 XtAddCallback(sb->id, XmNdragCallback,
1823 scroll_cb, (XtPointer)sb->ident);
1824 XtAddEventHandler(sb->id, KeyPressMask, FALSE, gui_x11_key_hit_cb,
1825 (XtPointer)0);
1826 }
1827}
1828
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001830gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831{
1832 if (sb->id != (Widget)0)
1833 XtDestroyWidget(sb->id);
1834}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835
1836 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001837gui_mch_set_scrollbar_colors(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838{
1839 if (sb->id != (Widget)0)
1840 {
1841 if (gui.scroll_bg_pixel != INVALCOLOR)
1842 {
1843#if (XmVersion>=1002)
Bram Moolenaare8504392022-03-13 14:45:03 +00001844 // This should not only set the through color but also adjust
1845 // related colors, such as shadows.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846 XmChangeColor(sb->id, gui.scroll_bg_pixel);
Bram Moolenaare8504392022-03-13 14:45:03 +00001847#endif
1848
1849 // Set the through color directly, in case XmChangeColor() decided
1850 // to change it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851 XtVaSetValues(sb->id,
1852 XmNtroughColor, gui.scroll_bg_pixel,
1853 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854 }
1855
1856 if (gui.scroll_fg_pixel != INVALCOLOR)
1857 XtVaSetValues(sb->id,
1858 XmNforeground, gui.scroll_fg_pixel,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 XmNbackground, gui.scroll_fg_pixel,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 NULL);
1861 }
1862
Bram Moolenaar734a8672019-12-02 22:49:38 +01001863 // This is needed for the rectangle below the vertical scrollbars.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 if (sb == &gui.bottom_sbar && textAreaForm != (Widget)0)
1865 gui_motif_scroll_colors(textAreaForm);
1866}
1867
1868/*
1869 * Miscellaneous stuff:
1870 */
1871
1872 Window
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001873gui_x11_get_wid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874{
1875 return(XtWindow(textArea));
1876}
1877
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001878/*
1879 * Look for a widget in the widget tree w, with a mnemonic matching keycode.
1880 * When one is found, simulate a button press on that widget and give it the
1881 * keyboard focus. If the mnemonic is on a label, look in the userData field
1882 * of the label to see if it points to another widget, and give that the focus.
1883 */
1884 static void
1885do_mnemonic(Widget w, unsigned int keycode)
1886{
1887 WidgetList children;
1888 int numChildren, i;
1889 Boolean isMenu;
1890 KeySym mnemonic = '\0';
1891 char mneString[2];
1892 Widget userData;
1893 unsigned char rowColType;
1894
1895 if (XtIsComposite(w))
1896 {
1897 if (XtClass(w) == xmRowColumnWidgetClass)
1898 {
Bram Moolenaar46784652008-06-20 09:40:11 +00001899 XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001900 isMenu = (rowColType != (unsigned char)XmWORK_AREA);
1901 }
1902 else
1903 isMenu = False;
1904 if (!isMenu)
1905 {
1906 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
Bram Moolenaar46784652008-06-20 09:40:11 +00001907 &numChildren, NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001908 for (i = 0; i < numChildren; i++)
1909 do_mnemonic(children[i], keycode);
1910 }
1911 }
1912 else
1913 {
Bram Moolenaar46784652008-06-20 09:40:11 +00001914 XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001915 if (mnemonic != '\0')
1916 {
1917 mneString[0] = mnemonic;
1918 mneString[1] = '\0';
1919 if (XKeysymToKeycode(XtDisplay(XtParent(w)),
1920 XStringToKeysym(mneString)) == keycode)
1921 {
1922 if (XtClass(w) == xmLabelWidgetClass
1923 || XtClass(w) == xmLabelGadgetClass)
1924 {
Bram Moolenaar46784652008-06-20 09:40:11 +00001925 XtVaGetValues(w, XmNuserData, &userData, NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001926 if (userData != NULL && XtIsWidget(userData))
1927 XmProcessTraversal(userData, XmTRAVERSE_CURRENT);
1928 }
1929 else
1930 {
1931 XKeyPressedEvent keyEvent;
1932
1933 XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1934
Bram Moolenaara80faa82020-04-12 19:37:17 +02001935 CLEAR_FIELD(keyEvent);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001936 keyEvent.type = KeyPress;
1937 keyEvent.serial = 1;
1938 keyEvent.send_event = True;
1939 keyEvent.display = XtDisplay(w);
1940 keyEvent.window = XtWindow(w);
1941 XtCallActionProc(w, "Activate", (XEvent *) & keyEvent,
1942 NULL, 0);
1943 }
1944 }
1945 }
1946 }
1947}
1948
1949/*
1950 * Callback routine for dialog mnemonic processing.
1951 */
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001952 static void
Bram Moolenaar9dbe7012021-03-29 20:10:26 +02001953mnemonic_event(
1954 Widget w,
1955 XtPointer call_data UNUSED,
1956 XKeyEvent *event,
1957 Boolean *b UNUSED)
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001958{
1959 do_mnemonic(w, event->keycode);
1960}
1961
1962
1963/*
1964 * Search the widget tree under w for widgets with mnemonics. When found, add
1965 * a passive grab to the dialog widget for the mnemonic character, thus
1966 * directing mnemonic events to the dialog widget.
1967 */
1968 static void
1969add_mnemonic_grabs(Widget dialog, Widget w)
1970{
1971 char mneString[2];
1972 WidgetList children;
1973 int numChildren, i;
1974 Boolean isMenu;
1975 KeySym mnemonic = '\0';
1976 unsigned char rowColType;
1977
1978 if (XtIsComposite(w))
1979 {
1980 if (XtClass(w) == xmRowColumnWidgetClass)
1981 {
Bram Moolenaar46784652008-06-20 09:40:11 +00001982 XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001983 isMenu = (rowColType != (unsigned char)XmWORK_AREA);
1984 }
1985 else
1986 isMenu = False;
1987 if (!isMenu)
1988 {
1989 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
Bram Moolenaar46784652008-06-20 09:40:11 +00001990 &numChildren, NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001991 for (i = 0; i < numChildren; i++)
1992 add_mnemonic_grabs(dialog, children[i]);
1993 }
1994 }
1995 else
1996 {
Bram Moolenaar46784652008-06-20 09:40:11 +00001997 XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00001998 if (mnemonic != '\0')
1999 {
2000 mneString[0] = mnemonic;
2001 mneString[1] = '\0';
2002 XtGrabKey(dialog, XKeysymToKeycode(XtDisplay(dialog),
2003 XStringToKeysym(mneString)),
2004 Mod1Mask, True, GrabModeAsync, GrabModeAsync);
2005 }
2006 }
2007}
2008
2009/*
2010 * Add a handler for mnemonics in a dialog. Motif itself only handles
2011 * mnemonics in menus. Mnemonics added or changed after this call will be
2012 * ignored.
2013 *
2014 * To add a mnemonic to a text field or list, set the XmNmnemonic resource on
2015 * the appropriate label and set the XmNuserData resource of the label to the
2016 * widget to get the focus when the mnemonic is typed.
2017 */
2018 static void
2019activate_dialog_mnemonics(Widget dialog)
2020{
2021 if (!dialog)
2022 return;
2023
2024 XtAddEventHandler(dialog, KeyPressMask, False,
2025 (XtEventHandler) mnemonic_event, (XtPointer) NULL);
2026 add_mnemonic_grabs(dialog, dialog);
2027}
2028
2029/*
2030 * Removes the event handler and key-grabs for dialog mnemonic handling.
2031 */
2032 static void
2033suppress_dialog_mnemonics(Widget dialog)
2034{
2035 if (!dialog)
2036 return;
2037
2038 XtUngrabKey(dialog, AnyKey, Mod1Mask);
2039 XtRemoveEventHandler(dialog, KeyPressMask, False,
2040 (XtEventHandler) mnemonic_event, (XtPointer) NULL);
2041}
2042
2043#if defined(FEAT_BROWSE) || defined(FEAT_GUI_DIALOG)
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002044/*
2045 * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget.
2046 */
2047 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002048set_fontlist(Widget id)
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002049{
2050 XmFontList fl;
2051
2052#ifdef FONTSET_ALWAYS
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00002053 if (gui.fontset != NOFONTSET)
2054 {
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002055 fl = gui_motif_fontset2fontlist((XFontSet *)&gui.fontset);
2056 if (fl != NULL)
2057 {
2058 if (XtIsManaged(id))
2059 {
2060 XtUnmanageChild(id);
2061 XtVaSetValues(id, XmNfontList, fl, NULL);
Bram Moolenaar734a8672019-12-02 22:49:38 +01002062 // We should force the widget to recalculate its
2063 // geometry now.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002064 XtManageChild(id);
2065 }
2066 else
2067 XtVaSetValues(id, XmNfontList, fl, NULL);
2068 XmFontListFree(fl);
2069 }
2070 }
2071#else
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00002072 if (gui.norm_font != NOFONT)
2073 {
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002074 fl = gui_motif_create_fontlist((XFontStruct *)gui.norm_font);
2075 if (fl != NULL)
2076 {
2077 if (XtIsManaged(id))
2078 {
2079 XtUnmanageChild(id);
2080 XtVaSetValues(id, XmNfontList, fl, NULL);
Bram Moolenaar734a8672019-12-02 22:49:38 +01002081 // We should force the widget to recalculate its
2082 // geometry now.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002083 XtManageChild(id);
2084 }
2085 else
2086 XtVaSetValues(id, XmNfontList, fl, NULL);
2087 XmFontListFree(fl);
2088 }
2089 }
2090#endif
2091}
2092#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093
2094#if defined(FEAT_BROWSE) || defined(PROTO)
2095
2096/*
2097 * file selector related stuff
2098 */
2099
2100#include <Xm/FileSB.h>
2101#include <Xm/XmStrDefs.h>
2102
2103typedef struct dialog_callback_arg
2104{
Bram Moolenaar734a8672019-12-02 22:49:38 +01002105 char * args; // not used right now
Bram Moolenaar071d4272004-06-13 20:20:40 +00002106 int id;
2107} dcbarg_T;
2108
2109static Widget dialog_wgt;
2110static char *browse_fname = NULL;
2111static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;
Bram Moolenaar734a8672019-12-02 22:49:38 +01002112 // used to set up XmStrings
Bram Moolenaar071d4272004-06-13 20:20:40 +00002113
Bram Moolenaard25c16e2016-01-29 22:13:30 +01002114static void DialogCancelCB(Widget, XtPointer, XtPointer);
2115static void DialogAcceptCB(Widget, XtPointer, XtPointer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116
2117/*
2118 * This function is used to translate the predefined label text of the
2119 * precomposed dialogs. We do this explicitly to allow:
2120 *
2121 * - usage of gettext for translation, as in all the other places.
2122 *
2123 * - equalize the messages between different GUI implementations as far as
2124 * possible.
2125 */
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002126 static void
2127set_predefined_label(Widget parent, String name, char *new_label)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002128{
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002129 XmString str;
2130 Widget w;
2131 char_u *p, *next;
2132 KeySym mnemonic = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133
2134 w = XtNameToWidget(parent, name);
2135
2136 if (!w)
2137 return;
2138
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002139 p = vim_strsave((char_u *)new_label);
2140 if (p == NULL)
2141 return;
2142 for (next = p; *next; ++next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143 {
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002144 if (*next == DLG_HOTKEY_CHAR)
2145 {
2146 int len = STRLEN(next);
2147
2148 if (len > 0)
2149 {
2150 mch_memmove(next, next + 1, len);
2151 mnemonic = next[0];
2152 }
2153 }
2154 }
2155
2156 str = XmStringCreate((char *)p, STRING_TAG);
2157 vim_free(p);
2158
2159 if (str != NULL)
2160 {
2161 XtVaSetValues(w,
2162 XmNlabelString, str,
2163 XmNmnemonic, mnemonic,
2164 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 XmStringFree(str);
2166 }
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002167 gui_motif_menu_fontlist(w);
2168}
2169
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002170 static void
2171set_predefined_fontlist(Widget parent, String name)
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002172{
2173 Widget w;
2174 w = XtNameToWidget(parent, name);
2175
2176 if (!w)
2177 return;
2178
2179 set_fontlist(w);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180}
2181
2182/*
2183 * Put up a file requester.
2184 * Returns the selected name in allocated memory, or NULL for Cancel.
2185 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002186 char_u *
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002187gui_mch_browse(
Bram Moolenaar734a8672019-12-02 22:49:38 +01002188 int saving UNUSED, // select file to write
2189 char_u *title, // title for the window
2190 char_u *dflt, // default name
2191 char_u *ext UNUSED, // not used (extension added)
2192 char_u *initdir, // initial directory, NULL for current dir
2193 char_u *filter) // file name filter
Bram Moolenaar071d4272004-06-13 20:20:40 +00002194{
2195 char_u dirbuf[MAXPATHL];
2196 char_u dfltbuf[MAXPATHL];
2197 char_u *pattern;
2198 char_u *tofree = NULL;
2199
Bram Moolenaar734a8672019-12-02 22:49:38 +01002200 // There a difference between the resource name and value, Therefore, we
2201 // avoid to (ab-)use the (maybe internationalized!) dialog title as a
2202 // dialog name.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002203
2204 dialog_wgt = XmCreateFileSelectionDialog(vimShell, "browseDialog", NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205
2206 if (initdir == NULL || *initdir == NUL)
2207 {
2208 mch_dirname(dirbuf, MAXPATHL);
2209 initdir = dirbuf;
2210 }
2211
2212 if (dflt == NULL)
2213 dflt = (char_u *)"";
2214 else if (STRLEN(initdir) + STRLEN(dflt) + 2 < MAXPATHL)
2215 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01002216 // The default selection should be the full path, "dflt" is only the
2217 // file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002218 STRCPY(dfltbuf, initdir);
2219 add_pathsep(dfltbuf);
2220 STRCAT(dfltbuf, dflt);
2221 dflt = dfltbuf;
2222 }
2223
Bram Moolenaar734a8672019-12-02 22:49:38 +01002224 // Can only use one pattern for a file name. Get the first pattern out of
2225 // the filter. An empty pattern means everything matches.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 if (filter == NULL)
2227 pattern = (char_u *)"";
2228 else
2229 {
2230 char_u *s, *p;
2231
2232 s = filter;
2233 for (p = filter; *p != NUL; ++p)
2234 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01002235 if (*p == '\t') // end of description, start of pattern
Bram Moolenaar071d4272004-06-13 20:20:40 +00002236 s = p + 1;
Bram Moolenaar734a8672019-12-02 22:49:38 +01002237 if (*p == ';' || *p == '\n') // end of (first) pattern
Bram Moolenaar071d4272004-06-13 20:20:40 +00002238 break;
2239 }
2240 pattern = vim_strnsave(s, p - s);
2241 tofree = pattern;
2242 if (pattern == NULL)
2243 pattern = (char_u *)"";
2244 }
2245
2246 XtVaSetValues(dialog_wgt,
2247 XtVaTypedArg,
2248 XmNdirectory, XmRString, (char *)initdir, STRLEN(initdir) + 1,
2249 XtVaTypedArg,
2250 XmNdirSpec, XmRString, (char *)dflt, STRLEN(dflt) + 1,
2251 XtVaTypedArg,
2252 XmNpattern, XmRString, (char *)pattern, STRLEN(pattern) + 1,
2253 XtVaTypedArg,
2254 XmNdialogTitle, XmRString, (char *)title, STRLEN(title) + 1,
2255 NULL);
2256
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002257 set_predefined_label(dialog_wgt, "Apply", _("&Filter"));
2258 set_predefined_label(dialog_wgt, "Cancel", _("&Cancel"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002259 set_predefined_label(dialog_wgt, "Dir", _("Directories"));
2260 set_predefined_label(dialog_wgt, "FilterLabel", _("Filter"));
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002261 set_predefined_label(dialog_wgt, "Help", _("&Help"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 set_predefined_label(dialog_wgt, "Items", _("Files"));
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002263 set_predefined_label(dialog_wgt, "OK", _("&OK"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264 set_predefined_label(dialog_wgt, "Selection", _("Selection"));
2265
Bram Moolenaar734a8672019-12-02 22:49:38 +01002266 // This is to save us from silly external settings using not fixed with
2267 // fonts for file selection.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002268 set_predefined_fontlist(dialog_wgt, "DirListSW.DirList");
2269 set_predefined_fontlist(dialog_wgt, "ItemsListSW.ItemsList");
2270
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 gui_motif_menu_colors(dialog_wgt);
2272 if (gui.scroll_bg_pixel != INVALCOLOR)
2273 XtVaSetValues(dialog_wgt, XmNtroughColor, gui.scroll_bg_pixel, NULL);
2274
2275 XtAddCallback(dialog_wgt, XmNokCallback, DialogAcceptCB, (XtPointer)0);
2276 XtAddCallback(dialog_wgt, XmNcancelCallback, DialogCancelCB, (XtPointer)0);
Bram Moolenaar734a8672019-12-02 22:49:38 +01002277 // We have no help in this window, so hide help button
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 XtUnmanageChild(XmFileSelectionBoxGetChild(dialog_wgt,
2279 (unsigned char)XmDIALOG_HELP_BUTTON));
2280
2281 manage_centered(dialog_wgt);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002282 activate_dialog_mnemonics(dialog_wgt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283
Bram Moolenaar734a8672019-12-02 22:49:38 +01002284 // sit in a loop until the dialog box has gone away
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 do
2286 {
2287 XtAppProcessEvent(XtWidgetToApplicationContext(dialog_wgt),
2288 (XtInputMask)XtIMAll);
2289 } while (XtIsManaged(dialog_wgt));
2290
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002291 suppress_dialog_mnemonics(dialog_wgt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 XtDestroyWidget(dialog_wgt);
2293 vim_free(tofree);
2294
2295 if (browse_fname == NULL)
2296 return NULL;
2297 return vim_strsave((char_u *)browse_fname);
2298}
2299
2300/*
2301 * The code below was originally taken from
2302 * /usr/examples/motif/xmsamplers/xmeditor.c
2303 * on Digital Unix 4.0d, but heavily modified.
2304 */
2305
2306/*
2307 * Process callback from Dialog cancel actions.
2308 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002310DialogCancelCB(
Bram Moolenaar734a8672019-12-02 22:49:38 +01002311 Widget w UNUSED, // widget id
2312 XtPointer client_data UNUSED, // data from application
2313 XtPointer call_data UNUSED) // data from widget class
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314{
2315 if (browse_fname != NULL)
2316 {
2317 XtFree(browse_fname);
2318 browse_fname = NULL;
2319 }
2320 XtUnmanageChild(dialog_wgt);
2321}
2322
2323/*
2324 * Process callback from Dialog actions.
2325 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002327DialogAcceptCB(
Bram Moolenaar734a8672019-12-02 22:49:38 +01002328 Widget w UNUSED, // widget id
2329 XtPointer client_data UNUSED, // data from application
2330 XtPointer call_data) // data from widget class
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331{
2332 XmFileSelectionBoxCallbackStruct *fcb;
2333
2334 if (browse_fname != NULL)
2335 {
2336 XtFree(browse_fname);
2337 browse_fname = NULL;
2338 }
2339 fcb = (XmFileSelectionBoxCallbackStruct *)call_data;
2340
Bram Moolenaar734a8672019-12-02 22:49:38 +01002341 // get the filename from the file selection box
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342 XmStringGetLtoR(fcb->value, charset, &browse_fname);
2343
Bram Moolenaar734a8672019-12-02 22:49:38 +01002344 // popdown the file selection box
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 XtUnmanageChild(dialog_wgt);
2346}
2347
Bram Moolenaar734a8672019-12-02 22:49:38 +01002348#endif // FEAT_BROWSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349
2350#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2351
2352static int dialogStatus;
2353
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354/*
2355 * Callback function for the textfield. When CR is hit this works like
2356 * hitting the "OK" button, ESC like "Cancel".
2357 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002359keyhit_callback(
2360 Widget w,
2361 XtPointer client_data UNUSED,
2362 XEvent *event,
2363 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364{
2365 char buf[2];
2366 KeySym key_sym;
2367
2368 if (XLookupString(&(event->xkey), buf, 2, &key_sym, NULL) == 1)
2369 {
2370 if (*buf == CAR)
2371 dialogStatus = 1;
2372 else if (*buf == ESC)
2373 dialogStatus = 2;
2374 }
2375 if ((key_sym == XK_Left || key_sym == XK_Right)
2376 && !(event->xkey.state & ShiftMask))
2377 XmTextFieldClearSelection(w, XtLastTimestampProcessed(gui.dpy));
2378}
2379
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002381butproc(
2382 Widget w UNUSED,
2383 XtPointer client_data,
2384 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385{
2386 dialogStatus = (int)(long)client_data + 1;
2387}
2388
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389#ifdef HAVE_XPM
2390
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 static Widget
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002392create_pixmap_label(
2393 Widget parent,
2394 String name,
2395 char **data,
2396 ArgList args,
2397 Cardinal arg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398{
2399 Widget label;
2400 Display *dsp;
2401 Screen *scr;
2402 int depth;
2403 Pixmap pixmap = 0;
2404 XpmAttributes attr;
2405 Boolean rs;
2406 XpmColorSymbol color[5] =
2407 {
2408 {"none", NULL, 0},
2409 {"iconColor1", NULL, 0},
2410 {"bottomShadowColor", NULL, 0},
2411 {"topShadowColor", NULL, 0},
2412 {"selectColor", NULL, 0}
2413 };
2414
2415 label = XmCreateLabelGadget(parent, name, args, arg);
2416
2417 /*
Bram Moolenaar933eb392007-05-10 17:52:45 +00002418 * We need to be careful here, since in case of gadgets, there is
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 * no way to get the background color directly from the widget itself.
2420 * In such cases we get it from The Core part of his parent instead.
2421 */
2422 dsp = XtDisplayOfObject(label);
2423 scr = XtScreenOfObject(label);
2424 XtVaGetValues(XtIsSubclass(label, coreWidgetClass)
2425 ? label : XtParent(label),
2426 XmNdepth, &depth,
2427 XmNbackground, &color[0].pixel,
2428 XmNforeground, &color[1].pixel,
2429 XmNbottomShadowColor, &color[2].pixel,
2430 XmNtopShadowColor, &color[3].pixel,
2431 XmNhighlight, &color[4].pixel,
2432 NULL);
2433
2434 attr.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth;
2435 attr.colorsymbols = color;
2436 attr.numsymbols = 5;
2437 attr.closeness = 65535;
2438 attr.depth = depth;
2439 XpmCreatePixmapFromData(dsp, RootWindowOfScreen(scr),
2440 data, &pixmap, NULL, &attr);
2441
2442 XtVaGetValues(label, XmNrecomputeSize, &rs, NULL);
2443 XtVaSetValues(label, XmNrecomputeSize, True, NULL);
2444 XtVaSetValues(label,
2445 XmNlabelType, XmPIXMAP,
2446 XmNlabelPixmap, pixmap,
2447 NULL);
2448 XtVaSetValues(label, XmNrecomputeSize, rs, NULL);
2449
2450 return label;
2451}
2452#endif
2453
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002455gui_mch_dialog(
2456 int type UNUSED,
2457 char_u *title,
2458 char_u *message,
2459 char_u *button_names,
2460 int dfltbutton,
Bram Moolenaar734a8672019-12-02 22:49:38 +01002461 char_u *textfield, // buffer of size IOSIZE
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002462 int ex_cmd UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463{
2464 char_u *buts;
2465 char_u *p, *next;
2466 XtAppContext app;
2467 XmString label;
2468 int butcount;
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002469 Widget w;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 Widget dialogform = NULL;
2471 Widget form = NULL;
2472 Widget dialogtextfield = NULL;
2473 Widget *buttons;
2474 Widget sep_form = NULL;
2475 Boolean vertical;
2476 Widget separator = NULL;
2477 int n;
2478 Arg args[6];
2479#ifdef HAVE_XPM
2480 char **icon_data = NULL;
2481 Widget dialogpixmap = NULL;
2482#endif
2483
2484 if (title == NULL)
2485 title = (char_u *)_("Vim dialog");
2486
Bram Moolenaar734a8672019-12-02 22:49:38 +01002487 // if our pointer is currently hidden, then we should show it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 gui_mch_mousehide(FALSE);
2489
2490 dialogform = XmCreateFormDialog(vimShell, (char *)"dialog", NULL, 0);
2491
Bram Moolenaar734a8672019-12-02 22:49:38 +01002492 // Check 'v' flag in 'guioptions': vertical button placement.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
2494
Bram Moolenaar734a8672019-12-02 22:49:38 +01002495 // Set the title of the Dialog window
Bram Moolenaar071d4272004-06-13 20:20:40 +00002496 label = XmStringCreateSimple((char *)title);
2497 if (label == NULL)
2498 return -1;
2499 XtVaSetValues(dialogform,
2500 XmNdialogTitle, label,
2501 XmNhorizontalSpacing, 4,
2502 XmNverticalSpacing, vertical ? 0 : 4,
2503 NULL);
2504 XmStringFree(label);
2505
Bram Moolenaar734a8672019-12-02 22:49:38 +01002506 // make a copy, so that we can insert NULs
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 buts = vim_strsave(button_names);
2508 if (buts == NULL)
2509 return -1;
2510
Bram Moolenaar734a8672019-12-02 22:49:38 +01002511 // Count the number of buttons and allocate buttons[].
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512 butcount = 1;
2513 for (p = buts; *p; ++p)
2514 if (*p == DLG_BUTTON_SEP)
2515 ++butcount;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002516 buttons = ALLOC_MULT(Widget, butcount);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 if (buttons == NULL)
2518 {
2519 vim_free(buts);
2520 return -1;
2521 }
2522
2523 /*
2524 * Create the buttons.
2525 */
2526 sep_form = (Widget) 0;
2527 p = buts;
2528 for (butcount = 0; *p; ++butcount)
2529 {
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002530 KeySym mnemonic = NUL;
2531
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 for (next = p; *next; ++next)
2533 {
2534 if (*next == DLG_HOTKEY_CHAR)
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002535 {
2536 int len = STRLEN(next);
2537
2538 if (len > 0)
2539 {
2540 mch_memmove(next, next + 1, len);
2541 mnemonic = next[0];
2542 }
2543 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 if (*next == DLG_BUTTON_SEP)
2545 {
2546 *next++ = NUL;
2547 break;
2548 }
2549 }
2550 label = XmStringCreate(_((char *)p), STRING_TAG);
2551 if (label == NULL)
2552 break;
2553
2554 buttons[butcount] = XtVaCreateManagedWidget("button",
2555 xmPushButtonWidgetClass, dialogform,
2556 XmNlabelString, label,
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002557 XmNmnemonic, mnemonic,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 XmNbottomAttachment, XmATTACH_FORM,
2559 XmNbottomOffset, 4,
2560 XmNshowAsDefault, butcount == dfltbutton - 1,
2561 XmNdefaultButtonShadowThickness, 1,
2562 NULL);
2563 XmStringFree(label);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002564 gui_motif_menu_fontlist(buttons[butcount]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565
Bram Moolenaar734a8672019-12-02 22:49:38 +01002566 // Layout properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567
2568 if (butcount > 0)
2569 {
2570 if (vertical)
2571 XtVaSetValues(buttons[butcount],
2572 XmNtopWidget, buttons[butcount - 1],
2573 NULL);
2574 else
2575 {
2576 if (*next == NUL)
2577 {
2578 XtVaSetValues(buttons[butcount],
2579 XmNrightAttachment, XmATTACH_FORM,
2580 XmNrightOffset, 4,
2581 NULL);
2582
Bram Moolenaar734a8672019-12-02 22:49:38 +01002583 // fill in a form as invisible separator
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 sep_form = XtVaCreateWidget("separatorForm",
2585 xmFormWidgetClass, dialogform,
2586 XmNleftAttachment, XmATTACH_WIDGET,
2587 XmNleftWidget, buttons[butcount - 1],
2588 XmNrightAttachment, XmATTACH_WIDGET,
2589 XmNrightWidget, buttons[butcount],
2590 XmNbottomAttachment, XmATTACH_FORM,
2591 XmNbottomOffset, 4,
2592 NULL);
2593 XtManageChild(sep_form);
2594 }
2595 else
2596 {
2597 XtVaSetValues(buttons[butcount],
2598 XmNleftAttachment, XmATTACH_WIDGET,
2599 XmNleftWidget, buttons[butcount - 1],
2600 NULL);
2601 }
2602 }
2603 }
2604 else if (!vertical)
2605 {
2606 if (*next == NUL)
2607 {
2608 XtVaSetValues(buttons[0],
2609 XmNrightAttachment, XmATTACH_FORM,
2610 XmNrightOffset, 4,
2611 NULL);
2612
Bram Moolenaar734a8672019-12-02 22:49:38 +01002613 // fill in a form as invisible separator
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 sep_form = XtVaCreateWidget("separatorForm",
2615 xmFormWidgetClass, dialogform,
2616 XmNleftAttachment, XmATTACH_FORM,
2617 XmNleftOffset, 4,
2618 XmNrightAttachment, XmATTACH_WIDGET,
2619 XmNrightWidget, buttons[0],
2620 XmNbottomAttachment, XmATTACH_FORM,
2621 XmNbottomOffset, 4,
2622 NULL);
2623 XtManageChild(sep_form);
2624 }
2625 else
2626 XtVaSetValues(buttons[0],
2627 XmNleftAttachment, XmATTACH_FORM,
2628 XmNleftOffset, 4,
2629 NULL);
2630 }
2631
2632 XtAddCallback(buttons[butcount], XmNactivateCallback,
2633 (XtCallbackProc)butproc, (XtPointer)(long)butcount);
2634 p = next;
2635 }
2636 vim_free(buts);
2637
2638 separator = (Widget) 0;
2639 if (butcount > 0)
2640 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01002641 // Create the separator for beauty.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642 n = 0;
2643 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2644 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2645 XtSetArg(args[n], XmNbottomWidget, buttons[0]); n++;
2646 XtSetArg(args[n], XmNbottomOffset, 4); n++;
2647 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2648 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2649 separator = XmCreateSeparatorGadget(dialogform, "separator", args, n);
2650 XtManageChild(separator);
2651 }
2652
2653 if (textfield != NULL)
2654 {
2655 dialogtextfield = XtVaCreateWidget("textField",
2656 xmTextFieldWidgetClass, dialogform,
2657 XmNleftAttachment, XmATTACH_FORM,
2658 XmNrightAttachment, XmATTACH_FORM,
2659 NULL);
2660 if (butcount > 0)
2661 XtVaSetValues(dialogtextfield,
2662 XmNbottomAttachment, XmATTACH_WIDGET,
2663 XmNbottomWidget, separator,
2664 NULL);
2665 else
2666 XtVaSetValues(dialogtextfield,
2667 XmNbottomAttachment, XmATTACH_FORM,
2668 NULL);
2669
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002670 set_fontlist(dialogtextfield);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671 XmTextFieldSetString(dialogtextfield, (char *)textfield);
2672 XtManageChild(dialogtextfield);
2673 XtAddEventHandler(dialogtextfield, KeyPressMask, False,
2674 (XtEventHandler)keyhit_callback, (XtPointer)NULL);
2675 }
2676
Bram Moolenaar734a8672019-12-02 22:49:38 +01002677 // Form holding both message and pixmap labels
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678 form = XtVaCreateWidget("separatorForm",
2679 xmFormWidgetClass, dialogform,
2680 XmNleftAttachment, XmATTACH_FORM,
2681 XmNrightAttachment, XmATTACH_FORM,
2682 XmNtopAttachment, XmATTACH_FORM,
2683 NULL);
2684 XtManageChild(form);
2685
2686#ifdef HAVE_XPM
Bram Moolenaar734a8672019-12-02 22:49:38 +01002687 // Add a pixmap, left of the message.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 switch (type)
2689 {
2690 case VIM_GENERIC:
2691 icon_data = generic_xpm;
2692 break;
2693 case VIM_ERROR:
2694 icon_data = error_xpm;
2695 break;
2696 case VIM_WARNING:
2697 icon_data = alert_xpm;
2698 break;
2699 case VIM_INFO:
2700 icon_data = info_xpm;
2701 break;
2702 case VIM_QUESTION:
2703 icon_data = quest_xpm;
2704 break;
2705 default:
2706 icon_data = generic_xpm;
2707 }
2708
2709 n = 0;
2710 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2711 XtSetArg(args[n], XmNtopOffset, 8); n++;
2712 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2713 XtSetArg(args[n], XmNbottomOffset, 8); n++;
2714 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2715 XtSetArg(args[n], XmNleftOffset, 8); n++;
2716
2717 dialogpixmap = create_pixmap_label(form, "dialogPixmap",
2718 icon_data, args, n);
2719 XtManageChild(dialogpixmap);
2720#endif
2721
Bram Moolenaar734a8672019-12-02 22:49:38 +01002722 // Create the dialog message.
2723 // Since LessTif is apparently having problems with the creation of
2724 // properly localized string, we use LtoR here. The symptom is that the
Dominique Pelleaf4a61a2021-12-27 17:21:41 +00002725 // string is not shown properly in multiple lines as it does in native
Bram Moolenaar734a8672019-12-02 22:49:38 +01002726 // Motif.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002727 label = XmStringCreateLtoR((char *)message, STRING_TAG);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002728 if (label == NULL)
2729 return -1;
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002730 w = XtVaCreateManagedWidget("dialogMessage",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731 xmLabelGadgetClass, form,
2732 XmNlabelString, label,
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002733 XmNalignment, XmALIGNMENT_BEGINNING,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734 XmNtopAttachment, XmATTACH_FORM,
2735 XmNtopOffset, 8,
2736#ifdef HAVE_XPM
2737 XmNleftAttachment, XmATTACH_WIDGET,
2738 XmNleftWidget, dialogpixmap,
2739#else
2740 XmNleftAttachment, XmATTACH_FORM,
2741#endif
2742 XmNleftOffset, 8,
2743 XmNrightAttachment, XmATTACH_FORM,
2744 XmNrightOffset, 8,
2745 XmNbottomAttachment, XmATTACH_FORM,
2746 XmNbottomOffset, 8,
2747 NULL);
2748 XmStringFree(label);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002749 set_fontlist(w);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002750
2751 if (textfield != NULL)
2752 {
2753 XtVaSetValues(form,
2754 XmNbottomAttachment, XmATTACH_WIDGET,
2755 XmNbottomWidget, dialogtextfield,
2756 NULL);
2757 }
2758 else
2759 {
2760 if (butcount > 0)
2761 XtVaSetValues(form,
2762 XmNbottomAttachment, XmATTACH_WIDGET,
2763 XmNbottomWidget, separator,
2764 NULL);
2765 else
2766 XtVaSetValues(form,
2767 XmNbottomAttachment, XmATTACH_FORM,
2768 NULL);
2769 }
2770
2771 if (dfltbutton < 1)
2772 dfltbutton = 1;
2773 if (dfltbutton > butcount)
2774 dfltbutton = butcount;
2775 XtVaSetValues(dialogform,
2776 XmNdefaultButton, buttons[dfltbutton - 1], NULL);
2777 if (textfield != NULL)
2778 XtVaSetValues(dialogform, XmNinitialFocus, dialogtextfield, NULL);
2779 else
2780 XtVaSetValues(dialogform, XmNinitialFocus, buttons[dfltbutton - 1],
2781 NULL);
2782
2783 manage_centered(dialogform);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002784 activate_dialog_mnemonics(dialogform);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785
2786 if (textfield != NULL && *textfield != NUL)
2787 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01002788 // This only works after the textfield has been realised.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002789 XmTextFieldSetSelection(dialogtextfield,
2790 (XmTextPosition)0, (XmTextPosition)STRLEN(textfield),
2791 XtLastTimestampProcessed(gui.dpy));
2792 XmTextFieldSetCursorPosition(dialogtextfield,
2793 (XmTextPosition)STRLEN(textfield));
2794 }
2795
2796 app = XtWidgetToApplicationContext(dialogform);
2797
Bram Moolenaar734a8672019-12-02 22:49:38 +01002798 // Loop until a button is pressed or the dialog is killed somehow.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 dialogStatus = -1;
2800 for (;;)
2801 {
2802 XtAppProcessEvent(app, (XtInputMask)XtIMAll);
2803 if (dialogStatus >= 0 || !XtIsManaged(dialogform))
2804 break;
2805 }
2806
2807 vim_free(buttons);
2808
2809 if (textfield != NULL)
2810 {
2811 p = (char_u *)XmTextGetString(dialogtextfield);
2812 if (p == NULL || dialogStatus < 0)
2813 *textfield = NUL;
2814 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002815 vim_strncpy(textfield, p, IOSIZE - 1);
Bram Moolenaar103e6ef2010-05-13 16:31:25 +02002816 XtFree((char *)p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 }
2818
Bram Moolenaardfccaf02004-12-31 20:56:11 +00002819 suppress_dialog_mnemonics(dialogform);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820 XtDestroyWidget(dialogform);
2821
2822 return dialogStatus;
2823}
Bram Moolenaar734a8672019-12-02 22:49:38 +01002824#endif // FEAT_GUI_DIALOG
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826#if defined(FEAT_TOOLBAR) || defined(PROTO)
2827 void
2828gui_mch_show_toolbar(int showit)
2829{
Bram Moolenaar734a8672019-12-02 22:49:38 +01002830 Cardinal numChildren; // how many children toolBar has
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831
2832 if (toolBar == (Widget)0)
2833 return;
2834 XtVaGetValues(toolBar, XmNnumChildren, &numChildren, NULL);
2835 if (showit && numChildren > 0)
2836 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01002837 // Assume that we want to show the toolbar if p_toolbar contains
2838 // valid option settings, therefore p_toolbar must not be NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002839 WidgetList children;
2840
2841 XtVaGetValues(toolBar, XmNchildren, &children, NULL);
2842 {
2843 void (*action)(BalloonEval *);
2844 int text = 0;
2845
2846 if (strstr((const char *)p_toolbar, "tooltips"))
2847 action = &gui_mch_enable_beval_area;
2848 else
2849 action = &gui_mch_disable_beval_area;
2850 if (strstr((const char *)p_toolbar, "text"))
2851 text = 1;
2852 else if (strstr((const char *)p_toolbar, "icons"))
2853 text = -1;
2854 if (text != 0)
2855 {
2856 vimmenu_T *toolbar;
2857 vimmenu_T *cur;
2858
Bram Moolenaar00d253e2020-04-06 22:13:01 +02002859 FOR_ALL_MENUS(toolbar)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860 if (menu_is_toolbar(toolbar->dname))
2861 break;
Bram Moolenaar734a8672019-12-02 22:49:38 +01002862 // Assumption: toolbar is NULL if there is no toolbar,
2863 // otherwise it contains the toolbar menu structure.
2864 //
2865 // Assumption: "numChildren" == the number of items in the list
2866 // of items beginning with toolbar->children.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867 if (toolbar)
2868 {
2869 for (cur = toolbar->children; cur; cur = cur->next)
2870 {
2871 Arg args[1];
2872 int n = 0;
2873
Bram Moolenaar734a8672019-12-02 22:49:38 +01002874 // Enable/Disable tooltip (OK to enable while
2875 // currently enabled).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 if (cur->tip != NULL)
2877 (*action)(cur->tip);
2878 if (!menu_is_separator(cur->name))
2879 {
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00002880 if (text == 1 || cur->xpm == NULL)
2881 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882 XtSetArg(args[n], XmNlabelType, XmSTRING);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00002883 ++n;
2884 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002885 if (cur->id != NULL)
2886 {
2887 XtUnmanageChild(cur->id);
2888 XtSetValues(cur->id, args, n);
2889 XtManageChild(cur->id);
2890 }
2891 }
2892 }
2893 }
2894 }
2895 }
2896 gui.toolbar_height = gui_mch_compute_toolbar_height();
2897 XtManageChild(XtParent(toolBar));
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002898#ifdef FEAT_GUI_TABLINE
2899 if (showing_tabline)
2900 {
2901 XtVaSetValues(tabLine,
2902 XmNtopAttachment, XmATTACH_WIDGET,
2903 XmNtopWidget, XtParent(toolBar),
2904 NULL);
2905 XtVaSetValues(textAreaForm,
2906 XmNtopAttachment, XmATTACH_WIDGET,
2907 XmNtopWidget, tabLine,
2908 NULL);
2909 }
2910 else
2911#endif
2912 XtVaSetValues(textAreaForm,
2913 XmNtopAttachment, XmATTACH_WIDGET,
2914 XmNtopWidget, XtParent(toolBar),
2915 NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916 if (XtIsManaged(menuBar))
2917 XtVaSetValues(XtParent(toolBar),
2918 XmNtopAttachment, XmATTACH_WIDGET,
2919 XmNtopWidget, menuBar,
2920 NULL);
2921 else
2922 XtVaSetValues(XtParent(toolBar),
2923 XmNtopAttachment, XmATTACH_FORM,
2924 NULL);
2925 }
2926 else
2927 {
2928 gui.toolbar_height = 0;
2929 if (XtIsManaged(menuBar))
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002930 {
2931#ifdef FEAT_GUI_TABLINE
2932 if (showing_tabline)
2933 {
2934 XtVaSetValues(tabLine,
2935 XmNtopAttachment, XmATTACH_WIDGET,
2936 XmNtopWidget, menuBar,
2937 NULL);
2938 XtVaSetValues(textAreaForm,
2939 XmNtopAttachment, XmATTACH_WIDGET,
2940 XmNtopWidget, tabLine,
2941 NULL);
2942 }
2943 else
2944#endif
2945 XtVaSetValues(textAreaForm,
2946 XmNtopAttachment, XmATTACH_WIDGET,
2947 XmNtopWidget, menuBar,
2948 NULL);
2949 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 else
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002951 {
2952#ifdef FEAT_GUI_TABLINE
2953 if (showing_tabline)
2954 {
2955 XtVaSetValues(tabLine,
2956 XmNtopAttachment, XmATTACH_FORM,
2957 NULL);
2958 XtVaSetValues(textAreaForm,
2959 XmNtopAttachment, XmATTACH_WIDGET,
2960 XmNtopWidget, tabLine,
2961 NULL);
2962 }
2963 else
2964#endif
2965 XtVaSetValues(textAreaForm,
2966 XmNtopAttachment, XmATTACH_FORM,
2967 NULL);
2968 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969
2970 XtUnmanageChild(XtParent(toolBar));
2971 }
Bram Moolenaar2e2a2812006-03-27 20:55:21 +00002972 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973}
2974
2975/*
2976 * A toolbar button has been pushed; now reset the input focus
2977 * such that the user can type page up/down etc. and have the
2978 * input go to the editor window, not the button
2979 */
2980 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002981reset_focus(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002982{
2983 if (textArea != NULL)
2984 XmProcessTraversal(textArea, XmTRAVERSE_CURRENT);
2985}
2986
2987 int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002988gui_mch_compute_toolbar_height(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002989{
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00002990 Dimension borders;
Bram Moolenaar734a8672019-12-02 22:49:38 +01002991 Dimension height; // total Toolbar height
2992 Dimension whgt; // height of each widget
2993 WidgetList children; // list of toolBar's children
2994 Cardinal numChildren; // how many children toolBar has
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995 int i;
2996
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00002997 borders = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998 height = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002999 if (toolBar != (Widget)0 && toolBarFrame != (Widget)0)
Bram Moolenaar734a8672019-12-02 22:49:38 +01003000 { // get height of XmFrame parent
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003001 Dimension fst;
3002 Dimension fmh;
3003 Dimension tst;
3004 Dimension tmh;
3005
Bram Moolenaar071d4272004-06-13 20:20:40 +00003006 XtVaGetValues(toolBarFrame,
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003007 XmNshadowThickness, &fst,
3008 XmNmarginHeight, &fmh,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 NULL);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003010 borders += fst + fmh;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011 XtVaGetValues(toolBar,
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003012 XmNshadowThickness, &tst,
3013 XmNmarginHeight, &tmh,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014 XmNchildren, &children,
3015 XmNnumChildren, &numChildren, NULL);
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003016 borders += tst + tmh;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00003017 for (i = 0; i < (int)numChildren; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 {
3019 whgt = 0;
3020 XtVaGetValues(children[i], XmNheight, &whgt, NULL);
3021 if (height < whgt)
3022 height = whgt;
3023 }
3024 }
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003025#ifdef LESSTIF_VERSION
Bram Moolenaar734a8672019-12-02 22:49:38 +01003026 // Hack: When starting up we get wrong dimensions.
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003027 if (height < 10)
3028 height = 24;
3029#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003031 return (int)(height + (borders << 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032}
3033
Bram Moolenaar7c626922005-02-07 22:01:03 +00003034 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003035motif_get_toolbar_colors(
3036 Pixel *bgp,
3037 Pixel *fgp,
3038 Pixel *bsp,
3039 Pixel *tsp,
3040 Pixel *hsp)
Bram Moolenaar7c626922005-02-07 22:01:03 +00003041{
3042 XtVaGetValues(toolBar,
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003043 XmNbackground, bgp,
3044 XmNforeground, fgp,
3045 XmNbottomShadowColor, bsp,
3046 XmNtopShadowColor, tsp,
3047 XmNhighlightColor, hsp,
3048 NULL);
Bram Moolenaar7c626922005-02-07 22:01:03 +00003049}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050#endif
3051
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003052#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
3053/*
3054 * Show or hide the tabline.
3055 */
3056 void
3057gui_mch_show_tabline(int showit)
3058{
3059 if (tabLine == (Widget)0)
3060 return;
3061
3062 if (!showit != !showing_tabline)
3063 {
3064 if (showit)
3065 {
3066 XtManageChild(tabLine);
3067 XtUnmanageChild(XtNameToWidget(tabLine, "PageScroller"));
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00003068 XtUnmanageChild(XtNameToWidget(tabLine, "MinorTabScrollerNext"));
3069 XtUnmanageChild(XtNameToWidget(tabLine,
3070 "MinorTabScrollerPrevious"));
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003071#ifdef FEAT_MENU
3072# ifdef FEAT_TOOLBAR
3073 if (XtIsManaged(XtParent(toolBar)))
3074 XtVaSetValues(tabLine,
3075 XmNtopAttachment, XmATTACH_WIDGET,
3076 XmNtopWidget, XtParent(toolBar), NULL);
3077 else
3078# endif
3079 if (XtIsManaged(menuBar))
3080 XtVaSetValues(tabLine,
3081 XmNtopAttachment, XmATTACH_WIDGET,
3082 XmNtopWidget, menuBar, NULL);
3083 else
3084#endif
3085 XtVaSetValues(tabLine,
3086 XmNtopAttachment, XmATTACH_FORM, NULL);
3087 XtVaSetValues(textAreaForm,
3088 XmNtopAttachment, XmATTACH_WIDGET,
3089 XmNtopWidget, tabLine,
3090 NULL);
3091 }
3092 else
3093 {
3094 XtUnmanageChild(tabLine);
3095#ifdef FEAT_MENU
3096# ifdef FEAT_TOOLBAR
3097 if (XtIsManaged(XtParent(toolBar)))
3098 XtVaSetValues(textAreaForm,
3099 XmNtopAttachment, XmATTACH_WIDGET,
3100 XmNtopWidget, XtParent(toolBar), NULL);
3101 else
3102# endif
3103 if (XtIsManaged(menuBar))
3104 XtVaSetValues(textAreaForm,
3105 XmNtopAttachment, XmATTACH_WIDGET,
3106 XmNtopWidget, menuBar, NULL);
3107 else
3108#endif
3109 XtVaSetValues(textAreaForm,
3110 XmNtopAttachment, XmATTACH_FORM, NULL);
3111 }
3112 showing_tabline = showit;
3113 }
3114}
3115
3116/*
3117 * Return TRUE when tabline is displayed.
3118 */
3119 int
3120gui_mch_showing_tabline(void)
3121{
3122 return tabLine != (Widget)0 && showing_tabline;
3123}
3124
3125/*
3126 * Update the labels of the tabline.
3127 */
3128 void
3129gui_mch_update_tabline(void)
3130{
3131 tabpage_T *tp;
3132 int nr = 1, n;
3133 Arg args[10];
3134 int curtabidx = 0, currentpage;
3135 Widget tab;
3136 XmNotebookPageInfo page_info;
3137 XmNotebookPageStatus page_status;
3138 int last_page, tab_count;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00003139 XmString label_str;
3140 char *label_cstr;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00003141 BalloonEval *beval;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003142
3143 if (tabLine == (Widget)0)
3144 return;
3145
Bram Moolenaar734a8672019-12-02 22:49:38 +01003146 // Add a label for each tab page. They all contain the same text area.
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003147 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
3148 {
3149 if (tp == curtab)
3150 curtabidx = nr;
3151
3152 page_status = XmNotebookGetPageInfo(tabLine, nr, &page_info);
3153 if (page_status == XmPAGE_INVALID
Bram Moolenaarf193fff2006-04-27 00:02:13 +00003154 || page_info.major_tab_widget == (Widget)0)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003155 {
Bram Moolenaar734a8672019-12-02 22:49:38 +01003156 // Add the tab
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003157 n = 0;
3158 XtSetArg(args[n], XmNnotebookChildType, XmMAJOR_TAB); n++;
3159 XtSetArg(args[n], XmNtraversalOn, False); n++;
3160 XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
3161 XtSetArg(args[n], XmNhighlightThickness, 1); n++;
3162 XtSetArg(args[n], XmNshadowThickness , 1); n++;
3163 tab = XmCreatePushButton(tabLine, "-Empty-", args, n);
3164 XtManageChild(tab);
Bram Moolenaarf193fff2006-04-27 00:02:13 +00003165 beval = gui_mch_create_beval_area(tab, NULL, tabline_balloon_cb,
3166 NULL);
3167 XtVaSetValues(tab, XmNuserData, beval, NULL);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003168 }
3169 else
3170 tab = page_info.major_tab_widget;
3171
3172 XtVaSetValues(tab, XmNpageNumber, nr, NULL);
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00003173
3174 /*
3175 * Change the label text only if it is different
3176 */
3177 XtVaGetValues(tab, XmNlabelString, &label_str, NULL);
3178 if (XmStringGetLtoR(label_str, XmSTRING_DEFAULT_CHARSET, &label_cstr))
3179 {
Bram Moolenaar57657d82006-04-21 22:12:41 +00003180 get_tabline_label(tp, FALSE);
3181 if (STRCMP(label_cstr, NameBuff) != 0)
3182 {
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00003183 XtVaSetValues(tab, XtVaTypedArg, XmNlabelString, XmRString,
3184 NameBuff, STRLEN(NameBuff) + 1, NULL);
3185 /*
3186 * Force a resize of the tab label button
3187 */
3188 XtUnmanageChild(tab);
3189 XtManageChild(tab);
3190 }
3191 XtFree(label_cstr);
3192 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003193 }
3194
3195 tab_count = nr - 1;
3196
3197 XtVaGetValues(tabLine, XmNlastPageNumber, &last_page, NULL);
3198
Bram Moolenaar734a8672019-12-02 22:49:38 +01003199 // Remove any old labels.
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003200 while (nr <= last_page)
3201 {
3202 if (XmNotebookGetPageInfo(tabLine, nr, &page_info) != XmPAGE_INVALID
3203 && page_info.page_number == nr
3204 && page_info.major_tab_widget != (Widget)0)
3205 {
Bram Moolenaarf193fff2006-04-27 00:02:13 +00003206 XtVaGetValues(page_info.major_tab_widget, XmNuserData, &beval, NULL);
3207 if (beval != NULL)
3208 gui_mch_destroy_beval_area(beval);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003209 XtUnmanageChild(page_info.major_tab_widget);
3210 XtDestroyWidget(page_info.major_tab_widget);
3211 }
3212 nr++;
3213 }
3214
3215 XtVaSetValues(tabLine, XmNlastPageNumber, tab_count, NULL);
3216
3217 XtVaGetValues(tabLine, XmNcurrentPageNumber, &currentpage, NULL);
3218 if (currentpage != curtabidx)
3219 XtVaSetValues(tabLine, XmNcurrentPageNumber, curtabidx, NULL);
3220}
3221
3222/*
3223 * Set the current tab to "nr". First tab is 1.
3224 */
3225 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003226gui_mch_set_curtab(int nr)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003227{
3228 int currentpage;
3229
3230 if (tabLine == (Widget)0)
3231 return;
3232
3233 XtVaGetValues(tabLine, XmNcurrentPageNumber, &currentpage, NULL);
3234 if (currentpage != nr)
3235 XtVaSetValues(tabLine, XmNcurrentPageNumber, nr, NULL);
3236}
3237#endif
3238
Bram Moolenaar071d4272004-06-13 20:20:40 +00003239/*
3240 * Set the colors of Widget "id" to the menu colors.
3241 */
3242 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003243gui_motif_menu_colors(Widget id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244{
3245 if (gui.menu_bg_pixel != INVALCOLOR)
3246#if (XmVersion >= 1002)
3247 XmChangeColor(id, gui.menu_bg_pixel);
3248#else
3249 XtVaSetValues(id, XmNbackground, gui.menu_bg_pixel, NULL);
3250#endif
3251 if (gui.menu_fg_pixel != INVALCOLOR)
3252 XtVaSetValues(id, XmNforeground, gui.menu_fg_pixel, NULL);
3253}
3254
3255/*
3256 * Set the colors of Widget "id" to the scrollbar colors.
3257 */
3258 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003259gui_motif_scroll_colors(Widget id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260{
3261 if (gui.scroll_bg_pixel != INVALCOLOR)
3262#if (XmVersion >= 1002)
3263 XmChangeColor(id, gui.scroll_bg_pixel);
3264#else
3265 XtVaSetValues(id, XmNbackground, gui.scroll_bg_pixel, NULL);
3266#endif
3267 if (gui.scroll_fg_pixel != INVALCOLOR)
3268 XtVaSetValues(id, XmNforeground, gui.scroll_fg_pixel, NULL);
3269}
3270
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271/*
3272 * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font.
3273 */
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003274 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003275gui_motif_menu_fontlist(Widget id UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276{
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003277#ifdef FEAT_MENU
Bram Moolenaar071d4272004-06-13 20:20:40 +00003278#ifdef FONTSET_ALWAYS
3279 if (gui.menu_fontset != NOFONTSET)
3280 {
3281 XmFontList fl;
3282
3283 fl = gui_motif_fontset2fontlist((XFontSet *)&gui.menu_fontset);
3284 if (fl != NULL)
3285 {
3286 if (XtIsManaged(id))
3287 {
3288 XtUnmanageChild(id);
3289 XtVaSetValues(id, XmNfontList, fl, NULL);
Bram Moolenaar734a8672019-12-02 22:49:38 +01003290 // We should force the widget to recalculate its
3291 // geometry now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 XtManageChild(id);
3293 }
3294 else
3295 XtVaSetValues(id, XmNfontList, fl, NULL);
3296 XmFontListFree(fl);
3297 }
3298 }
3299#else
3300 if (gui.menu_font != NOFONT)
3301 {
3302 XmFontList fl;
3303
3304 fl = gui_motif_create_fontlist((XFontStruct *)gui.menu_font);
3305 if (fl != NULL)
3306 {
3307 if (XtIsManaged(id))
3308 {
3309 XtUnmanageChild(id);
3310 XtVaSetValues(id, XmNfontList, fl, NULL);
Bram Moolenaar734a8672019-12-02 22:49:38 +01003311 // We should force the widget to recalculate its
3312 // geometry now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313 XtManageChild(id);
3314 }
3315 else
3316 XtVaSetValues(id, XmNfontList, fl, NULL);
3317 XmFontListFree(fl);
3318 }
3319 }
3320#endif
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003321#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322}
3323
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324
3325/*
3326 * We don't create it twice for the sake of speed.
3327 */
3328
3329typedef struct _SharedFindReplace
3330{
Bram Moolenaar734a8672019-12-02 22:49:38 +01003331 Widget dialog; // the main dialog widget
3332 Widget wword; // 'Exact match' check button
3333 Widget mcase; // 'match case' check button
3334 Widget up; // search direction 'Up' radio button
3335 Widget down; // search direction 'Down' radio button
3336 Widget what; // 'Find what' entry text widget
3337 Widget with; // 'Replace with' entry text widget
3338 Widget find; // 'Find Next' action button
3339 Widget replace; // 'Replace With' action button
3340 Widget all; // 'Replace All' action button
3341 Widget undo; // 'Undo' action button
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342
3343 Widget cancel;
3344} SharedFindReplace;
3345
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00003346static SharedFindReplace find_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
3347static SharedFindReplace repl_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003350find_replace_destroy_callback(
3351 Widget w UNUSED,
3352 XtPointer client_data,
3353 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354{
3355 SharedFindReplace *cd = (SharedFindReplace *)client_data;
3356
Bram Moolenaarb7fcef52005-01-02 11:31:05 +00003357 if (cd != NULL)
Bram Moolenaar734a8672019-12-02 22:49:38 +01003358 // suppress_dialog_mnemonics(cd->dialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003359 cd->dialog = (Widget)0;
3360}
3361
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003363find_replace_dismiss_callback(
3364 Widget w UNUSED,
3365 XtPointer client_data,
3366 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367{
3368 SharedFindReplace *cd = (SharedFindReplace *)client_data;
3369
3370 if (cd != NULL)
3371 XtUnmanageChild(cd->dialog);
3372}
3373
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003375entry_activate_callback(
3376 Widget w UNUSED,
3377 XtPointer client_data,
3378 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379{
3380 XmProcessTraversal((Widget)client_data, XmTRAVERSE_CURRENT);
3381}
3382
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003384find_replace_callback(
3385 Widget w UNUSED,
3386 XtPointer client_data,
3387 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388{
3389 long_u flags = (long_u)client_data;
3390 char *find_text, *repl_text;
3391 Boolean direction_down = TRUE;
3392 Boolean wword;
3393 Boolean mcase;
3394 SharedFindReplace *sfr;
3395
3396 if (flags == FRD_UNDO)
3397 {
3398 char_u *save_cpo = p_cpo;
3399
Bram Moolenaar734a8672019-12-02 22:49:38 +01003400 // No need to be Vi compatible here.
Bram Moolenaarbb0956f2021-01-03 22:12:15 +01003401 p_cpo = empty_option;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 u_undo(1);
3403 p_cpo = save_cpo;
3404 gui_update_screen();
3405 return;
3406 }
3407
Bram Moolenaar734a8672019-12-02 22:49:38 +01003408 // Get the search/replace strings from the dialog
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409 if (flags == FRD_FINDNEXT)
3410 {
3411 repl_text = NULL;
3412 sfr = &find_widgets;
3413 }
3414 else
3415 {
3416 repl_text = XmTextFieldGetString(repl_widgets.with);
3417 sfr = &repl_widgets;
3418 }
3419 find_text = XmTextFieldGetString(sfr->what);
3420 XtVaGetValues(sfr->down, XmNset, &direction_down, NULL);
3421 XtVaGetValues(sfr->wword, XmNset, &wword, NULL);
3422 XtVaGetValues(sfr->mcase, XmNset, &mcase, NULL);
3423 if (wword)
3424 flags |= FRD_WHOLE_WORD;
3425 if (mcase)
3426 flags |= FRD_MATCH_CASE;
3427
3428 (void)gui_do_findrepl((int)flags, (char_u *)find_text, (char_u *)repl_text,
3429 direction_down);
3430
3431 if (find_text != NULL)
3432 XtFree(find_text);
3433 if (repl_text != NULL)
3434 XtFree(repl_text);
3435}
3436
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003438find_replace_keypress(
3439 Widget w UNUSED,
3440 SharedFindReplace *frdp,
Bram Moolenaar9dbe7012021-03-29 20:10:26 +02003441 XKeyEvent *event,
3442 Boolean *b UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443{
3444 KeySym keysym;
3445
3446 if (frdp == NULL)
3447 return;
3448
3449 keysym = XLookupKeysym(event, 0);
3450
Bram Moolenaar734a8672019-12-02 22:49:38 +01003451 // the scape key pops the whole dialog down
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452 if (keysym == XK_Escape)
3453 XtUnmanageChild(frdp->dialog);
3454}
3455
3456 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003457set_label(Widget w, char *label)
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003458{
3459 XmString str;
3460 char_u *p, *next;
3461 KeySym mnemonic = NUL;
3462
3463 if (!w)
3464 return;
3465
Bram Moolenaar3dbcd0c2013-06-22 13:00:16 +02003466 p = vim_strsave((char_u *)label);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003467 if (p == NULL)
3468 return;
3469 for (next = p; *next; ++next)
3470 {
3471 if (*next == DLG_HOTKEY_CHAR)
3472 {
3473 int len = STRLEN(next);
3474
3475 if (len > 0)
3476 {
3477 mch_memmove(next, next + 1, len);
3478 mnemonic = next[0];
3479 }
3480 }
3481 }
3482
3483 str = XmStringCreateSimple((char *)p);
3484 vim_free(p);
3485 if (str)
3486 {
3487 XtVaSetValues(w,
3488 XmNlabelString, str,
3489 XmNmnemonic, mnemonic,
3490 NULL);
3491 XmStringFree(str);
3492 }
3493 gui_motif_menu_fontlist(w);
3494}
3495
3496 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003497find_replace_dialog_create(char_u *arg, int do_replace)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498{
3499 SharedFindReplace *frdp;
3500 Widget separator;
3501 Widget input_form;
3502 Widget button_form;
3503 Widget toggle_form;
3504 Widget frame;
3505 XmString str;
3506 int n;
3507 Arg args[6];
3508 int wword = FALSE;
3509 int mcase = !p_ic;
3510 Dimension width;
3511 Dimension widest;
3512 char_u *entry_text;
3513
3514 frdp = do_replace ? &repl_widgets : &find_widgets;
3515
Bram Moolenaar734a8672019-12-02 22:49:38 +01003516 // Get the search string to use.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003517 entry_text = get_find_dialog_text(arg, &wword, &mcase);
3518
Bram Moolenaar734a8672019-12-02 22:49:38 +01003519 // If the dialog already exists, just raise it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520 if (frdp->dialog)
3521 {
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003522 gui_motif_synch_fonts();
3523
Bram Moolenaar734a8672019-12-02 22:49:38 +01003524 // If the window is already up, just pop it to the top
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 if (XtIsManaged(frdp->dialog))
3526 XMapRaised(XtDisplay(frdp->dialog),
3527 XtWindow(XtParent(frdp->dialog)));
3528 else
3529 XtManageChild(frdp->dialog);
3530 XtPopup(XtParent(frdp->dialog), XtGrabNone);
3531 XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);
3532
3533 if (entry_text != NULL)
3534 XmTextFieldSetString(frdp->what, (char *)entry_text);
3535 vim_free(entry_text);
3536
3537 XtVaSetValues(frdp->wword, XmNset, wword, NULL);
3538 return;
3539 }
3540
Bram Moolenaar734a8672019-12-02 22:49:38 +01003541 // Create a fresh new dialog window
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542 if (do_replace)
3543 str = XmStringCreateSimple(_("VIM - Search and Replace..."));
3544 else
3545 str = XmStringCreateSimple(_("VIM - Search..."));
3546
3547 n = 0;
3548 XtSetArg(args[n], XmNautoUnmanage, False); n++;
3549 XtSetArg(args[n], XmNnoResize, True); n++;
3550 XtSetArg(args[n], XmNdialogTitle, str); n++;
3551
3552 frdp->dialog = XmCreateFormDialog(vimShell, "findReplaceDialog", args, n);
3553 XmStringFree(str);
3554 XtAddCallback(frdp->dialog, XmNdestroyCallback,
3555 find_replace_destroy_callback, frdp);
3556
3557 button_form = XtVaCreateWidget("buttonForm",
3558 xmFormWidgetClass, frdp->dialog,
3559 XmNrightAttachment, XmATTACH_FORM,
3560 XmNrightOffset, 4,
3561 XmNtopAttachment, XmATTACH_FORM,
3562 XmNtopOffset, 4,
3563 XmNbottomAttachment, XmATTACH_FORM,
3564 XmNbottomOffset, 4,
3565 NULL);
3566
Bram Moolenaar071d4272004-06-13 20:20:40 +00003567 frdp->find = XtVaCreateManagedWidget("findButton",
3568 xmPushButtonWidgetClass, button_form,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 XmNsensitive, True,
3570 XmNtopAttachment, XmATTACH_FORM,
3571 XmNleftAttachment, XmATTACH_FORM,
3572 XmNrightAttachment, XmATTACH_FORM,
3573 NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003574 set_label(frdp->find, _("Find &Next"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575
3576 XtAddCallback(frdp->find, XmNactivateCallback,
3577 find_replace_callback,
Bram Moolenaare9e3b572008-01-22 10:06:48 +00003578 (do_replace ? (XtPointer)FRD_R_FINDNEXT : (XtPointer)FRD_FINDNEXT));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003579
3580 if (do_replace)
3581 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582 frdp->replace = XtVaCreateManagedWidget("replaceButton",
3583 xmPushButtonWidgetClass, button_form,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 XmNtopAttachment, XmATTACH_WIDGET,
3585 XmNtopWidget, frdp->find,
3586 XmNleftAttachment, XmATTACH_FORM,
3587 XmNrightAttachment, XmATTACH_FORM,
3588 NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003589 set_label(frdp->replace, _("&Replace"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 XtAddCallback(frdp->replace, XmNactivateCallback,
3591 find_replace_callback, (XtPointer)FRD_REPLACE);
3592
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593 frdp->all = XtVaCreateManagedWidget("replaceAllButton",
3594 xmPushButtonWidgetClass, button_form,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595 XmNtopAttachment, XmATTACH_WIDGET,
3596 XmNtopWidget, frdp->replace,
3597 XmNleftAttachment, XmATTACH_FORM,
3598 XmNrightAttachment, XmATTACH_FORM,
3599 NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003600 set_label(frdp->all, _("Replace &All"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 XtAddCallback(frdp->all, XmNactivateCallback,
3602 find_replace_callback, (XtPointer)FRD_REPLACEALL);
3603
Bram Moolenaar071d4272004-06-13 20:20:40 +00003604 frdp->undo = XtVaCreateManagedWidget("undoButton",
3605 xmPushButtonWidgetClass, button_form,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003606 XmNtopAttachment, XmATTACH_WIDGET,
3607 XmNtopWidget, frdp->all,
3608 XmNleftAttachment, XmATTACH_FORM,
3609 XmNrightAttachment, XmATTACH_FORM,
3610 NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003611 set_label(frdp->undo, _("&Undo"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612 XtAddCallback(frdp->undo, XmNactivateCallback,
3613 find_replace_callback, (XtPointer)FRD_UNDO);
3614 }
3615
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616 frdp->cancel = XtVaCreateManagedWidget("closeButton",
3617 xmPushButtonWidgetClass, button_form,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618 XmNleftAttachment, XmATTACH_FORM,
3619 XmNrightAttachment, XmATTACH_FORM,
3620 XmNbottomAttachment, XmATTACH_FORM,
3621 NULL);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003622 set_label(frdp->cancel, _("&Cancel"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623 XtAddCallback(frdp->cancel, XmNactivateCallback,
3624 find_replace_dismiss_callback, frdp);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003625 gui_motif_menu_fontlist(frdp->cancel);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003626
3627 XtManageChild(button_form);
3628
3629 n = 0;
3630 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
3631 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
3632 XtSetArg(args[n], XmNrightWidget, button_form); n++;
3633 XtSetArg(args[n], XmNrightOffset, 4); n++;
3634 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
3635 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
3636 separator = XmCreateSeparatorGadget(frdp->dialog, "separator", args, n);
3637 XtManageChild(separator);
3638
3639 input_form = XtVaCreateWidget("inputForm",
3640 xmFormWidgetClass, frdp->dialog,
3641 XmNleftAttachment, XmATTACH_FORM,
3642 XmNleftOffset, 4,
3643 XmNrightAttachment, XmATTACH_WIDGET,
3644 XmNrightWidget, separator,
3645 XmNrightOffset, 4,
3646 XmNtopAttachment, XmATTACH_FORM,
3647 XmNtopOffset, 4,
3648 NULL);
3649
3650 {
3651 Widget label_what;
3652 Widget label_with = (Widget)0;
3653
3654 str = XmStringCreateSimple(_("Find what:"));
3655 label_what = XtVaCreateManagedWidget("whatLabel",
3656 xmLabelGadgetClass, input_form,
3657 XmNlabelString, str,
3658 XmNleftAttachment, XmATTACH_FORM,
3659 XmNtopAttachment, XmATTACH_FORM,
3660 XmNtopOffset, 4,
3661 NULL);
3662 XmStringFree(str);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003663 gui_motif_menu_fontlist(label_what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664
3665 frdp->what = XtVaCreateManagedWidget("whatText",
3666 xmTextFieldWidgetClass, input_form,
3667 XmNtopAttachment, XmATTACH_FORM,
3668 XmNrightAttachment, XmATTACH_FORM,
3669 XmNleftAttachment, XmATTACH_FORM,
3670 NULL);
3671
3672 if (do_replace)
3673 {
3674 frdp->with = XtVaCreateManagedWidget("withText",
3675 xmTextFieldWidgetClass, input_form,
3676 XmNtopAttachment, XmATTACH_WIDGET,
3677 XmNtopWidget, frdp->what,
3678 XmNtopOffset, 4,
3679 XmNleftAttachment, XmATTACH_FORM,
3680 XmNrightAttachment, XmATTACH_FORM,
3681 XmNbottomAttachment, XmATTACH_FORM,
3682 NULL);
3683
3684 XtAddCallback(frdp->with, XmNactivateCallback,
3685 find_replace_callback, (XtPointer) FRD_R_FINDNEXT);
3686
3687 str = XmStringCreateSimple(_("Replace with:"));
3688 label_with = XtVaCreateManagedWidget("withLabel",
3689 xmLabelGadgetClass, input_form,
3690 XmNlabelString, str,
3691 XmNleftAttachment, XmATTACH_FORM,
3692 XmNtopAttachment, XmATTACH_WIDGET,
3693 XmNtopWidget, frdp->what,
3694 XmNtopOffset, 4,
3695 XmNbottomAttachment, XmATTACH_FORM,
3696 NULL);
3697 XmStringFree(str);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003698 gui_motif_menu_fontlist(label_with);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003699
3700 /*
3701 * Make the entry activation only change the input focus onto the
3702 * with item.
3703 */
3704 XtAddCallback(frdp->what, XmNactivateCallback,
3705 entry_activate_callback, frdp->with);
3706 XtAddEventHandler(frdp->with, KeyPressMask, False,
3707 (XtEventHandler)find_replace_keypress,
3708 (XtPointer) frdp);
3709
3710 }
3711 else
3712 {
3713 /*
3714 * Make the entry activation do the search.
3715 */
3716 XtAddCallback(frdp->what, XmNactivateCallback,
3717 find_replace_callback, (XtPointer)FRD_FINDNEXT);
3718 }
3719 XtAddEventHandler(frdp->what, KeyPressMask, False,
3720 (XtEventHandler)find_replace_keypress,
3721 (XtPointer)frdp);
3722
Bram Moolenaar734a8672019-12-02 22:49:38 +01003723 // Get the maximum width between the label widgets and line them up.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 n = 0;
3725 XtSetArg(args[n], XmNwidth, &width); n++;
3726 XtGetValues(label_what, args, n);
3727 widest = width;
3728 if (do_replace)
3729 {
3730 XtGetValues(label_with, args, n);
3731 if (width > widest)
3732 widest = width;
3733 }
3734
3735 XtVaSetValues(frdp->what, XmNleftOffset, widest, NULL);
3736 if (do_replace)
3737 XtVaSetValues(frdp->with, XmNleftOffset, widest, NULL);
3738
3739 }
3740
3741 XtManageChild(input_form);
3742
3743 {
3744 Widget radio_box;
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003745 Widget w;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746
3747 frame = XtVaCreateWidget("directionFrame",
3748 xmFrameWidgetClass, frdp->dialog,
3749 XmNtopAttachment, XmATTACH_WIDGET,
3750 XmNtopWidget, input_form,
3751 XmNtopOffset, 4,
3752 XmNbottomAttachment, XmATTACH_FORM,
3753 XmNbottomOffset, 4,
3754 XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
3755 XmNrightWidget, input_form,
3756 NULL);
3757
3758 str = XmStringCreateSimple(_("Direction"));
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003759 w = XtVaCreateManagedWidget("directionFrameLabel",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760 xmLabelGadgetClass, frame,
3761 XmNlabelString, str,
3762 XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
3763 XmNchildType, XmFRAME_TITLE_CHILD,
3764 NULL);
3765 XmStringFree(str);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003766 gui_motif_menu_fontlist(w);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767
3768 radio_box = XmCreateRadioBox(frame, "radioBox",
3769 (ArgList)NULL, 0);
3770
3771 str = XmStringCreateSimple( _("Up"));
3772 frdp->up = XtVaCreateManagedWidget("upRadioButton",
3773 xmToggleButtonGadgetClass, radio_box,
3774 XmNlabelString, str,
3775 XmNset, False,
3776 NULL);
3777 XmStringFree(str);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003778 gui_motif_menu_fontlist(frdp->up);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003779
3780 str = XmStringCreateSimple(_("Down"));
3781 frdp->down = XtVaCreateManagedWidget("downRadioButton",
3782 xmToggleButtonGadgetClass, radio_box,
3783 XmNlabelString, str,
3784 XmNset, True,
3785 NULL);
3786 XmStringFree(str);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003787 gui_motif_menu_fontlist(frdp->down);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788
3789 XtManageChild(radio_box);
3790 XtManageChild(frame);
3791 }
3792
3793 toggle_form = XtVaCreateWidget("toggleForm",
3794 xmFormWidgetClass, frdp->dialog,
3795 XmNleftAttachment, XmATTACH_FORM,
3796 XmNleftOffset, 4,
3797 XmNrightAttachment, XmATTACH_WIDGET,
3798 XmNrightWidget, frame,
3799 XmNrightOffset, 4,
3800 XmNtopAttachment, XmATTACH_WIDGET,
3801 XmNtopWidget, input_form,
3802 XmNtopOffset, 4,
3803 XmNbottomAttachment, XmATTACH_FORM,
3804 XmNbottomOffset, 4,
3805 NULL);
3806
3807 str = XmStringCreateSimple(_("Match whole word only"));
3808 frdp->wword = XtVaCreateManagedWidget("wordToggle",
3809 xmToggleButtonGadgetClass, toggle_form,
3810 XmNlabelString, str,
3811 XmNtopAttachment, XmATTACH_FORM,
3812 XmNtopOffset, 4,
3813 XmNleftAttachment, XmATTACH_FORM,
3814 XmNleftOffset, 4,
3815 XmNset, wword,
3816 NULL);
3817 XmStringFree(str);
3818
3819 str = XmStringCreateSimple(_("Match case"));
3820 frdp->mcase = XtVaCreateManagedWidget("caseToggle",
3821 xmToggleButtonGadgetClass, toggle_form,
3822 XmNlabelString, str,
3823 XmNleftAttachment, XmATTACH_FORM,
3824 XmNleftOffset, 4,
3825 XmNtopAttachment, XmATTACH_WIDGET,
3826 XmNtopWidget, frdp->wword,
3827 XmNtopOffset, 4,
3828 XmNset, mcase,
3829 NULL);
3830 XmStringFree(str);
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003831 gui_motif_menu_fontlist(frdp->wword);
3832 gui_motif_menu_fontlist(frdp->mcase);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833
3834 XtManageChild(toggle_form);
3835
3836 if (entry_text != NULL)
3837 XmTextFieldSetString(frdp->what, (char *)entry_text);
3838 vim_free(entry_text);
3839
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003840 gui_motif_synch_fonts();
3841
3842 manage_centered(frdp->dialog);
3843 activate_dialog_mnemonics(frdp->dialog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003844 XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);
3845}
3846
3847 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003848gui_mch_find_dialog(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849{
3850 if (!gui.in_use)
3851 return;
3852
3853 find_replace_dialog_create(eap->arg, FALSE);
3854}
3855
3856
3857 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01003858gui_mch_replace_dialog(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859{
3860 if (!gui.in_use)
3861 return;
3862
3863 find_replace_dialog_create(eap->arg, TRUE);
3864}
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003865
3866/*
Bram Moolenaar52797ba2021-12-16 14:45:13 +00003867 * Synchronize all gui elements, which are dependent upon the
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003868 * main text font used. Those are in esp. the find/replace dialogs.
3869 * If you don't understand why this should be needed, please try to
Bram Moolenaar305598b2016-01-30 13:53:36 +01003870 * search for "pi\xea\xb6\xe6" in iso8859-2.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003871 */
3872 void
3873gui_motif_synch_fonts(void)
3874{
3875 SharedFindReplace *frdp;
3876 int do_replace;
3877 XFontStruct *font;
3878 XmFontList font_list;
3879
Bram Moolenaar734a8672019-12-02 22:49:38 +01003880 // FIXME: Unless we find out how to create a XmFontList from a XFontSet,
3881 // we just give up here on font synchronization.
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003882 font = (XFontStruct *)gui.norm_font;
3883 if (font == NULL)
3884 return;
3885
3886 font_list = gui_motif_create_fontlist(font);
3887
Bram Moolenaar734a8672019-12-02 22:49:38 +01003888 // OK this loop is a bit tricky...
Bram Moolenaardfccaf02004-12-31 20:56:11 +00003889 for (do_replace = 0; do_replace <= 1; ++do_replace)
3890 {
3891 frdp = (do_replace) ? (&repl_widgets) : (&find_widgets);
3892 if (frdp->dialog)
3893 {
3894 XtVaSetValues(frdp->what, XmNfontList, font_list, NULL);
3895 if (do_replace)
3896 XtVaSetValues(frdp->with, XmNfontList, font_list, NULL);
3897 }
3898 }
3899
3900 XmFontListFree(font_list);
3901}