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