blob: 155509d1ffb2e497d48223980635a12eaa49984d [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI/Motif support by Robert Webb
5 * Athena port by Bill Foster
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
Bram Moolenaarf7506ca2017-02-25 16:01:49 +010012#include "vim.h"
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include <X11/StringDefs.h>
15#include <X11/Intrinsic.h>
16#ifdef FEAT_GUI_NEXTAW
17# include <X11/neXtaw/Form.h>
18# include <X11/neXtaw/SimpleMenu.h>
19# include <X11/neXtaw/MenuButton.h>
20# include <X11/neXtaw/SmeBSB.h>
21# include <X11/neXtaw/SmeLine.h>
22# include <X11/neXtaw/Box.h>
23# include <X11/neXtaw/Dialog.h>
24# include <X11/neXtaw/Text.h>
25# include <X11/neXtaw/AsciiText.h>
26# include <X11/neXtaw/Scrollbar.h>
27#else
28# include <X11/Xaw/Form.h>
29# include <X11/Xaw/SimpleMenu.h>
30# include <X11/Xaw/MenuButton.h>
31# include <X11/Xaw/SmeBSB.h>
32# include <X11/Xaw/SmeLine.h>
33# include <X11/Xaw/Box.h>
34# include <X11/Xaw/Dialog.h>
35# include <X11/Xaw/Text.h>
36# include <X11/Xaw/AsciiText.h>
37#endif /* FEAT_GUI_NEXTAW */
38
Bram Moolenaar071d4272004-06-13 20:20:40 +000039#ifndef FEAT_GUI_NEXTAW
40# include "gui_at_sb.h"
41#endif
42
43extern Widget vimShell;
44
45static Widget vimForm = (Widget)0;
Bram Moolenaara5319ae2005-03-18 20:15:36 +000046Widget textArea = (Widget)0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000047#ifdef FEAT_MENU
48static Widget menuBar = (Widget)0;
49static XtIntervalId timer = 0; /* 0 = expired, otherwise active */
50
51/* Used to figure out menu ordering */
52static vimmenu_T *a_cur_menu = NULL;
Bram Moolenaard25c16e2016-01-29 22:13:30 +010053static Cardinal athena_calculate_ins_pos(Widget);
Bram Moolenaar071d4272004-06-13 20:20:40 +000054
Bram Moolenaard25c16e2016-01-29 22:13:30 +010055static void gui_athena_popup_callback(Widget, XtPointer, XtPointer);
56static void gui_athena_delayed_arm_action(Widget, XEvent *, String *,
57 Cardinal *);
58static void gui_athena_popdown_submenus_action(Widget, XEvent *,
59 String *, Cardinal *);
Bram Moolenaar071d4272004-06-13 20:20:40 +000060static XtActionsRec pullAction[2] = {
61 { "menu-delayedpopup", (XtActionProc)gui_athena_delayed_arm_action},
62 { "menu-popdownsubmenus", (XtActionProc)gui_athena_popdown_submenus_action}
63};
64#endif
65
66#ifdef FEAT_TOOLBAR
Bram Moolenaard25c16e2016-01-29 22:13:30 +010067static void gui_mch_reset_focus(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000068static Widget toolBar = (Widget)0;
69#endif
70
Bram Moolenaar071d4272004-06-13 20:20:40 +000071#if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
Bram Moolenaard25c16e2016-01-29 22:13:30 +010072static void gui_athena_menu_colors(Widget id);
Bram Moolenaar071d4272004-06-13 20:20:40 +000073#endif
Bram Moolenaard25c16e2016-01-29 22:13:30 +010074static void gui_athena_scroll_colors(Widget id);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76#ifdef FEAT_MENU
77static XtTranslations popupTrans, parentTrans, menuTrans, supermenuTrans;
78static Pixmap pullerBitmap = None;
79static int puller_width = 0;
80#endif
81
82/*
83 * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
84 * left or middle mouse button.
85 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000086 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +010087gui_athena_scroll_cb_jump(
88 Widget w UNUSED,
Bram Moolenaar02fdaea2016-01-30 18:13:55 +010089 XtPointer client_data,
90 XtPointer call_data)
Bram Moolenaar071d4272004-06-13 20:20:40 +000091{
92 scrollbar_T *sb, *sb_info;
93 long value;
94
95 sb = gui_find_scrollbar((long)client_data);
96
97 if (sb == NULL)
98 return;
99 else if (sb->wp != NULL) /* Left or right scrollbar */
100 {
101 /*
102 * Careful: need to get scrollbar info out of first (left) scrollbar
103 * for window, but keep real scrollbar too because we must pass it to
104 * gui_drag_scrollbar().
105 */
106 sb_info = &sb->wp->w_scrollbars[0];
107 }
108 else /* Bottom scrollbar */
109 sb_info = sb;
110
111 value = (long)(*((float *)call_data) * (float)(sb_info->max + 1) + 0.001);
112 if (value > sb_info->max)
113 value = sb_info->max;
114
115 gui_drag_scrollbar(sb, value, TRUE);
116}
117
118/*
119 * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
120 * right mouse buttons.
121 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000122 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100123gui_athena_scroll_cb_scroll(
124 Widget w UNUSED,
Bram Moolenaar02fdaea2016-01-30 18:13:55 +0100125 XtPointer client_data,
126 XtPointer call_data)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127{
128 scrollbar_T *sb, *sb_info;
129 long value;
130 int data = (int)(long)call_data;
131 int page;
132
133 sb = gui_find_scrollbar((long)client_data);
134
135 if (sb == NULL)
136 return;
137 if (sb->wp != NULL) /* Left or right scrollbar */
138 {
139 /*
140 * Careful: need to get scrollbar info out of first (left) scrollbar
141 * for window, but keep real scrollbar too because we must pass it to
142 * gui_drag_scrollbar().
143 */
144 sb_info = &sb->wp->w_scrollbars[0];
145
146 if (sb_info->size > 5)
147 page = sb_info->size - 2; /* use two lines of context */
148 else
149 page = sb_info->size;
150#ifdef FEAT_GUI_NEXTAW
151 if (data < 0)
152 {
153 data = (data - gui.char_height + 1) / gui.char_height;
154 if (data > -sb_info->size)
155 data = -1;
156 else
157 data = -page;
158 }
159 else if (data > 0)
160 {
161 data = (data + gui.char_height - 1) / gui.char_height;
162 if (data < sb_info->size)
163 data = 1;
164 else
165 data = page;
166 }
167#else
168 switch (data)
169 {
170 case ONE_LINE_DATA: data = 1; break;
171 case -ONE_LINE_DATA: data = -1; break;
172 case ONE_PAGE_DATA: data = page; break;
173 case -ONE_PAGE_DATA: data = -page; break;
174 case END_PAGE_DATA: data = sb_info->max; break;
175 case -END_PAGE_DATA: data = -sb_info->max; break;
176 default: data = 0; break;
177 }
178#endif
179 }
180 else /* Bottom scrollbar */
181 {
182 sb_info = sb;
183#ifdef FEAT_GUI_NEXTAW
184 if (data < 0)
185 {
186 data = (data - gui.char_width + 1) / gui.char_width;
187 if (data > -sb->size)
188 data = -1;
189 }
190 else if (data > 0)
191 {
192 data = (data + gui.char_width - 1) / gui.char_width;
193 if (data < sb->size)
194 data = 1;
195 }
196#endif
197 if (data < -1) /* page-width left */
198 {
199 if (sb->size > 8)
200 data = -(sb->size - 5);
201 else
202 data = -sb->size;
203 }
204 else if (data > 1) /* page-width right */
205 {
206 if (sb->size > 8)
207 data = (sb->size - 5);
208 else
209 data = sb->size;
210 }
211 }
212
213 value = sb_info->value + data;
214 if (value > sb_info->max)
215 value = sb_info->max;
216 else if (value < 0)
217 value = 0;
218
219 /* Update the bottom scrollbar an extra time (why is this needed?? */
220 if (sb->wp == NULL) /* Bottom scrollbar */
221 gui_mch_set_scrollbar_thumb(sb, value, sb->size, sb->max);
222
223 gui_drag_scrollbar(sb, value, FALSE);
224}
225
226/*
227 * Create all the Athena widgets necessary.
228 */
229 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100230gui_x11_create_widgets(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231{
232 /*
233 * We don't have any borders handled internally by the textArea to worry
234 * about so only skip over the configured border width.
235 */
236 gui.border_offset = gui.border_width;
237
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238 /* The form containing all the other widgets */
239 vimForm = XtVaCreateManagedWidget("vimForm",
240 formWidgetClass, vimShell,
241 XtNborderWidth, 0,
242 NULL);
243 gui_athena_scroll_colors(vimForm);
244
245#ifdef FEAT_MENU
246 /* The top menu bar */
247 menuBar = XtVaCreateManagedWidget("menuBar",
248 boxWidgetClass, vimForm,
249 XtNresizable, True,
250 XtNtop, XtChainTop,
251 XtNbottom, XtChainTop,
252 XtNleft, XtChainLeft,
253 XtNright, XtChainRight,
254 XtNinsertPosition, athena_calculate_ins_pos,
255 NULL);
256 gui_athena_menu_colors(menuBar);
257 if (gui.menu_fg_pixel != INVALCOLOR)
258 XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
259#endif
260
261#ifdef FEAT_TOOLBAR
262 /* Don't create it Managed, it will be managed when creating the first
263 * item. Otherwise an empty toolbar shows up. */
264 toolBar = XtVaCreateWidget("toolBar",
265 boxWidgetClass, vimForm,
266 XtNresizable, True,
267 XtNtop, XtChainTop,
268 XtNbottom, XtChainTop,
269 XtNleft, XtChainLeft,
270 XtNright, XtChainRight,
271 XtNorientation, XtorientHorizontal,
272 XtNhSpace, 1,
273 XtNvSpace, 3,
274 XtNinsertPosition, athena_calculate_ins_pos,
275 NULL);
276 gui_athena_menu_colors(toolBar);
277#endif
278
279 /* The text area. */
280 textArea = XtVaCreateManagedWidget("textArea",
281 coreWidgetClass, vimForm,
282 XtNresizable, True,
283 XtNtop, XtChainTop,
284 XtNbottom, XtChainTop,
285 XtNleft, XtChainLeft,
286 XtNright, XtChainLeft,
287 XtNbackground, gui.back_pixel,
288 XtNborderWidth, 0,
289 NULL);
290
291 /*
292 * Install the callbacks.
293 */
294 gui_x11_callbacks(textArea, vimForm);
295
296#ifdef FEAT_MENU
297 popupTrans = XtParseTranslationTable(
298 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
299 "<LeaveWindow>: unhighlight()\n"
300 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
301 "<Motion>: highlight() menu-delayedpopup()");
302 parentTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight()");
303 menuTrans = XtParseTranslationTable(
304 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
305 "<LeaveWindow>: menu-popdownsubmenus() XtMenuPopdown() unhighlight()\n"
306 "<BtnUp>: notify() unhighlight()\n"
307 "<BtnMotion>: highlight() menu-delayedpopup()");
308 supermenuTrans = XtParseTranslationTable(
309 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
310 "<LeaveWindow>: unhighlight()\n"
311 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
312 "<BtnMotion>: highlight() menu-delayedpopup()");
313
314 XtAppAddActions(XtWidgetToApplicationContext(vimForm), pullAction,
315 XtNumber(pullAction));
316#endif
317
318 /* Pretend we don't have input focus, we will get an event if we do. */
319 gui.in_focus = FALSE;
320}
321
322#ifdef FEAT_MENU
323/*
324 * Calculates the Pixmap based on the size of the current menu font.
325 */
326 static Pixmap
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100327gui_athena_create_pullright_pixmap(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000328{
329 Pixmap retval;
330#ifdef FONTSET_ALWAYS
331 XFontSet font = None;
332#else
333 XFontStruct *font = NULL;
334#endif
335
336#ifdef FONTSET_ALWAYS
337 if (gui.menu_fontset == NOFONTSET)
338#else
339 if (gui.menu_font == NOFONT)
340#endif
341 {
342 XrmValue from, to;
343 WidgetList children;
344 Cardinal num_children;
345
346#ifdef FONTSET_ALWAYS
347 from.size = strlen(from.addr = XtDefaultFontSet);
348 to.addr = (XtPointer)&font;
349 to.size = sizeof(XFontSet);
350#else
351 from.size = strlen(from.addr = XtDefaultFont);
352 to.addr = (XtPointer)&font;
353 to.size = sizeof(XFontStruct *);
354#endif
355 /* Assumption: The menuBar children will use the same font as the
356 * pulldown menu items AND they will all be of type
357 * XtNfont.
358 */
359 XtVaGetValues(menuBar, XtNchildren, &children,
360 XtNnumChildren, &num_children,
361 NULL);
362 if (XtConvertAndStore(w ? w :
363 (num_children > 0) ? children[0] : menuBar,
364 XtRString, &from,
365#ifdef FONTSET_ALWAYS
366 XtRFontSet, &to
367#else
368 XtRFontStruct, &to
369#endif
370 ) == False)
371 return None;
372 /* "font" should now contain data */
373 }
374 else
375#ifdef FONTSET_ALWAYS
376 font = (XFontSet)gui.menu_fontset;
377#else
378 font = (XFontStruct *)gui.menu_font;
379#endif
380
381 {
382 int width, height;
383 GC draw_gc, undraw_gc;
384 XGCValues gc_values;
385 XPoint points[3];
386
387#ifdef FONTSET_ALWAYS
388 height = fontset_height2(font);
389#else
390 height = font->max_bounds.ascent + font->max_bounds.descent;
391#endif
392 width = height - 2;
393 puller_width = width + 4;
394 retval = XCreatePixmap(gui.dpy,DefaultRootWindow(gui.dpy),width,
395 height, 1);
396 gc_values.foreground = 1;
397 gc_values.background = 0;
398 draw_gc = XCreateGC(gui.dpy, retval,
399 GCForeground | GCBackground,
400 &gc_values);
401 gc_values.foreground = 0;
402 gc_values.background = 1;
403 undraw_gc = XCreateGC(gui.dpy, retval,
404 GCForeground | GCBackground,
405 &gc_values);
406 points[0].x = 0;
407 points[0].y = 0;
408 points[1].x = width - 1;
409 points[1].y = (height - 1) / 2;
410 points[2].x = 0;
411 points[2].y = height - 1;
412 XFillRectangle(gui.dpy, retval, undraw_gc, 0, 0, height, height);
413 XFillPolygon(gui.dpy, retval, draw_gc, points, XtNumber(points),
414 Convex, CoordModeOrigin);
415 XFreeGC(gui.dpy, draw_gc);
416 XFreeGC(gui.dpy, undraw_gc);
417 }
418 return retval;
419}
420#endif
421
422/*
423 * Called when the GUI is not going to start after all.
424 */
425 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100426gui_x11_destroy_widgets(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427{
428 textArea = NULL;
429#ifdef FEAT_MENU
430 menuBar = NULL;
431#endif
432#ifdef FEAT_TOOLBAR
433 toolBar = NULL;
434#endif
435}
436
437#if defined(FEAT_TOOLBAR) || defined(PROTO)
Bram Moolenaar34114692005-01-02 11:28:13 +0000438# include "gui_x11_pm.h"
439# ifdef HAVE_X11_XPM_H
440# include <X11/xpm.h>
441# endif
442
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100443static void createXpmImages(char_u *path, char **xpm, Pixmap *sen);
Bram Moolenaar34114692005-01-02 11:28:13 +0000444
445/*
446 * Allocated a pixmap for toolbar menu "menu".
447 * Return in "sen".
448 */
449 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100450get_toolbar_pixmap(vimmenu_T *menu, Pixmap *sen)
Bram Moolenaar34114692005-01-02 11:28:13 +0000451{
452 char_u buf[MAXPATHL]; /* buffer storing expanded pathname */
453 char **xpm = NULL; /* xpm array */
454
455 buf[0] = NUL; /* start with NULL path */
456
457 if (menu->iconfile != NULL)
458 {
459 /* Use the "icon=" argument. */
460 gui_find_iconfile(menu->iconfile, buf, "xpm");
461 createXpmImages(buf, NULL, sen);
462
463 /* If it failed, try using the menu name. */
464 if (*sen == (Pixmap)0 && gui_find_bitmap(menu->name, buf, "xpm") == OK)
465 createXpmImages(buf, NULL, sen);
466 if (*sen != (Pixmap)0)
467 return;
468 }
469
470 if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL)
471 {
472 if (menu->iconidx >= 0 && menu->iconidx
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000473 < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0])))
Bram Moolenaar34114692005-01-02 11:28:13 +0000474 xpm = built_in_pixmaps[menu->iconidx];
475 else
476 xpm = tb_blank_xpm;
477 }
478
479 if (xpm != NULL || buf[0] != NUL)
480 createXpmImages(buf, xpm, sen);
481}
482
483/*
484 * Read an Xpm file, doing color substitutions for the foreground and
485 * background colors. If there is an error reading a color xpm file,
486 * drop back and read the monochrome file. If successful, create the
487 * insensitive Pixmap too.
488 */
489 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100490createXpmImages(char_u *path, char **xpm, Pixmap *sen)
Bram Moolenaar34114692005-01-02 11:28:13 +0000491{
492 Window rootWindow;
493 XpmAttributes attrs;
494 XpmColorSymbol color[5] =
495 {
496 {"none", "none", 0},
497 {"iconColor1", NULL, 0},
498 {"bottomShadowColor", NULL, 0},
499 {"topShadowColor", NULL, 0},
500 {"selectColor", NULL, 0}
501 };
502 int screenNum;
503 int status;
504 Pixmap mask;
505 Pixmap map;
506
507 gui_mch_get_toolbar_colors(
508 &color[BACKGROUND].pixel,
509 &color[FOREGROUND].pixel,
510 &color[BOTTOM_SHADOW].pixel,
511 &color[TOP_SHADOW].pixel,
512 &color[HIGHLIGHT].pixel);
513
Bram Moolenaar84a05ac2013-05-06 04:24:17 +0200514 /* Setup the color substitution table */
Bram Moolenaar34114692005-01-02 11:28:13 +0000515 attrs.valuemask = XpmColorSymbols;
516 attrs.colorsymbols = color;
517 attrs.numsymbols = 5;
518
519 screenNum = DefaultScreen(gui.dpy);
520 rootWindow = RootWindow(gui.dpy, screenNum);
521
522 /* Create the "sensitive" pixmap */
523 if (xpm != NULL)
524 status = XpmCreatePixmapFromData(gui.dpy, rootWindow, xpm,
525 &map, &mask, &attrs);
526 else
527 status = XpmReadFileToPixmap(gui.dpy, rootWindow, (char *)path,
528 &map, &mask, &attrs);
529 if (status == XpmSuccess && map != 0)
530 {
531 XGCValues gcvalues;
532 GC back_gc;
533 GC mask_gc;
534
535 /* Need to create new Pixmaps with the mask applied. */
536 gcvalues.foreground = color[BACKGROUND].pixel;
537 back_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
538 mask_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
539 XSetClipMask(gui.dpy, mask_gc, mask);
540
541 /* Create the "sensitive" pixmap. */
542 *sen = XCreatePixmap(gui.dpy, rootWindow,
543 attrs.width, attrs.height,
544 DefaultDepth(gui.dpy, screenNum));
545 XFillRectangle(gui.dpy, *sen, back_gc, 0, 0,
546 attrs.width, attrs.height);
547 XCopyArea(gui.dpy, map, *sen, mask_gc, 0, 0,
548 attrs.width, attrs.height, 0, 0);
549
550 XFreeGC(gui.dpy, back_gc);
551 XFreeGC(gui.dpy, mask_gc);
552 XFreePixmap(gui.dpy, map);
553 }
554 else
555 *sen = 0;
556
557 XpmFreeAttributes(&attrs);
558}
559
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100561gui_mch_set_toolbar_pos(
562 int x,
563 int y,
564 int w,
565 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566{
567 Dimension border;
568 int height;
569
570 if (!XtIsManaged(toolBar)) /* nothing to do */
571 return;
572 XtUnmanageChild(toolBar);
573 XtVaGetValues(toolBar,
574 XtNborderWidth, &border,
575 NULL);
576 height = h - 2 * border;
577 if (height < 0)
578 height = 1;
579 XtVaSetValues(toolBar,
580 XtNhorizDistance, x,
581 XtNvertDistance, y,
582 XtNwidth, w - 2 * border,
583 XtNheight, height,
584 NULL);
585 XtManageChild(toolBar);
586}
587#endif
588
589 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100590gui_mch_set_text_area_pos(
591 int x,
592 int y,
593 int w,
594 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595{
596 XtUnmanageChild(textArea);
597 XtVaSetValues(textArea,
598 XtNhorizDistance, x,
599 XtNvertDistance, y,
600 XtNwidth, w,
601 XtNheight, h,
602 NULL);
603 XtManageChild(textArea);
604#ifdef FEAT_TOOLBAR
605 /* Give keyboard focus to the textArea instead of the toolbar. */
606 gui_mch_reset_focus();
607#endif
608}
609
610#ifdef FEAT_TOOLBAR
611/*
612 * A toolbar button has been pushed; now reset the input focus
613 * such that the user can type page up/down etc. and have the
614 * input go to the editor window, not the button
615 */
616 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100617gui_mch_reset_focus(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618{
619 XtSetKeyboardFocus(vimForm, textArea);
620}
621#endif
622
623
624 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100625gui_x11_set_back_color(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626{
627 if (textArea != NULL)
628 XtVaSetValues(textArea,
629 XtNbackground, gui.back_pixel,
630 NULL);
631}
632
633#if defined(FEAT_MENU) || defined(PROTO)
634/*
635 * Menu stuff.
636 */
637
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100638static char_u *make_pull_name(char_u * name);
639static Widget get_popup_entry(Widget w);
640static Widget submenu_widget(Widget);
641static Boolean has_submenu(Widget);
642static void gui_mch_submenu_change(vimmenu_T *mp, int colors);
643static void gui_athena_menu_font(Widget id);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644
645 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100646gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647{
648 if (flag)
649 {
650 XtManageChild(menuBar);
651# ifdef FEAT_TOOLBAR
652 if (XtIsManaged(toolBar))
653 {
654 XtVaSetValues(toolBar,
655 XtNvertDistance, gui.menu_height,
656 NULL);
657 XtVaSetValues(textArea,
658 XtNvertDistance, gui.menu_height + gui.toolbar_height,
659 NULL);
660 }
661# endif
662 }
663 else
664 {
665 XtUnmanageChild(menuBar);
666# ifdef FEAT_TOOLBAR
667 if (XtIsManaged(toolBar))
668 {
669 XtVaSetValues(toolBar,
670 XtNvertDistance, 0,
671 NULL);
672 }
673# endif
674 }
675}
676
677 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100678gui_mch_set_menu_pos(
679 int x,
680 int y,
681 int w,
682 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683{
684 Dimension border;
685 int height;
686
687 XtUnmanageChild(menuBar);
688 XtVaGetValues(menuBar, XtNborderWidth, &border, NULL);
689 /* avoid trouble when there are no menu items, and h is 1 */
690 height = h - 2 * border;
691 if (height < 0)
692 height = 1;
693 XtVaSetValues(menuBar,
694 XtNhorizDistance, x,
695 XtNvertDistance, y,
696 XtNwidth, w - 2 * border,
697 XtNheight, height,
698 NULL);
699 XtManageChild(menuBar);
700}
701
702/*
703 * Used to calculate the insertion position of a widget with respect to its
704 * neighbors.
705 *
706 * Valid range of return values is: 0 (beginning of children) to
707 * numChildren (end of children).
708 */
709 static Cardinal
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100710athena_calculate_ins_pos(Widget widget)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711{
712 /* Assume that if the parent of the vimmenu_T is NULL, then we can get
713 * to this menu by traversing "next", starting at "root_menu".
714 *
715 * This holds true for popup menus, toolbar, and toplevel menu items.
716 */
717
718 /* Popup menus: "id" is NULL. Only submenu_id is valid */
719
720 /* Menus that are not toplevel: "parent" will be non-NULL, "id" &
721 * "submenu_id" will be non-NULL.
722 */
723
724 /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */
725
726 WidgetList children;
727 Cardinal num_children = 0;
728 int retval;
729 Arg args[2];
730 int n = 0;
731 int i;
732
733 XtSetArg(args[n], XtNchildren, &children); n++;
734 XtSetArg(args[n], XtNnumChildren, &num_children); n++;
735 XtGetValues(XtParent(widget), args, n);
736
737 retval = num_children;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000738 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 Widget current = children[i];
741 vimmenu_T *menu = NULL;
742
743 for (menu = (a_cur_menu->parent == NULL)
744 ? root_menu : a_cur_menu->parent->children;
745 menu != NULL;
746 menu = menu->next)
747 if (current == menu->id
748 && a_cur_menu->priority < menu->priority
749 && i < retval)
750 retval = i;
751 }
752 return retval;
753}
754
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100756gui_mch_add_menu(vimmenu_T *menu, int idx UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757{
758 char_u *pullright_name;
759 Dimension height, space, border;
760 vimmenu_T *parent = menu->parent;
761
762 a_cur_menu = menu;
763 if (parent == NULL)
764 {
765 if (menu_is_popup(menu->dname))
766 {
767 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
768 simpleMenuWidgetClass, vimShell,
769 XtNinsertPosition, athena_calculate_ins_pos,
770 XtNtranslations, popupTrans,
771 NULL);
772 gui_athena_menu_colors(menu->submenu_id);
773 }
774 else if (menu_is_menubar(menu->dname))
775 {
776 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
777 menuButtonWidgetClass, menuBar,
778 XtNmenuName, menu->dname,
779#ifdef FONTSET_ALWAYS
780 XtNinternational, True,
781#endif
782 NULL);
783 if (menu->id == (Widget)0)
784 return;
785 gui_athena_menu_colors(menu->id);
786 gui_athena_menu_font(menu->id);
787
788 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
789 simpleMenuWidgetClass, menu->id,
790 XtNinsertPosition, athena_calculate_ins_pos,
791 XtNtranslations, supermenuTrans,
792 NULL);
793 gui_athena_menu_colors(menu->submenu_id);
794 gui_athena_menu_font(menu->submenu_id);
795
796 /* Don't update the menu height when it was set at a fixed value */
797 if (!gui.menu_height_fixed)
798 {
799 /*
800 * When we add a top-level item to the menu bar, we can figure
801 * out how high the menu bar should be.
802 */
803 XtVaGetValues(menuBar,
804 XtNvSpace, &space,
805 XtNborderWidth, &border,
806 NULL);
807 XtVaGetValues(menu->id,
808 XtNheight, &height,
809 NULL);
810 gui.menu_height = height + 2 * (space + border);
811 }
812 }
813 }
814 else if (parent->submenu_id != (Widget)0)
815 {
816 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
817 smeBSBObjectClass, parent->submenu_id,
818 XtNlabel, menu->dname,
819#ifdef FONTSET_ALWAYS
820 XtNinternational, True,
821#endif
822 NULL);
823 if (menu->id == (Widget)0)
824 return;
825 if (pullerBitmap == None)
826 pullerBitmap = gui_athena_create_pullright_pixmap(menu->id);
827
828 XtVaSetValues(menu->id, XtNrightBitmap, pullerBitmap,
829 NULL);
830 /* If there are other menu items that are not pulldown menus,
831 * we need to adjust the right margins of those, too.
832 */
833 {
834 WidgetList children;
835 Cardinal num_children;
836 int i;
837
838 XtVaGetValues(parent->submenu_id, XtNchildren, &children,
839 XtNnumChildren, &num_children,
840 NULL);
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000841 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842 {
843 XtVaSetValues(children[i],
844 XtNrightMargin, puller_width,
845 NULL);
846 }
847 }
848 gui_athena_menu_colors(menu->id);
849 gui_athena_menu_font(menu->id);
850
851 pullright_name = make_pull_name(menu->dname);
852 menu->submenu_id = XtVaCreatePopupShell((char *)pullright_name,
853 simpleMenuWidgetClass, parent->submenu_id,
854 XtNtranslations, menuTrans,
855 NULL);
856 gui_athena_menu_colors(menu->submenu_id);
857 gui_athena_menu_font(menu->submenu_id);
858 vim_free(pullright_name);
859 XtAddCallback(menu->submenu_id, XtNpopupCallback,
860 gui_athena_popup_callback, (XtPointer)menu);
861
862 if (parent->parent != NULL)
863 XtOverrideTranslations(parent->submenu_id, parentTrans);
864 }
865 a_cur_menu = NULL;
866}
867
868/* Used to determine whether a SimpleMenu has pulldown entries.
869 *
870 * "id" is the parent of the menu items.
871 * Ignore widget "ignore" in the pane.
872 */
873 static Boolean
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100874gui_athena_menu_has_submenus(Widget id, Widget ignore)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875{
876 WidgetList children;
877 Cardinal num_children;
878 int i;
879
880 XtVaGetValues(id, XtNchildren, &children,
881 XtNnumChildren, &num_children,
882 NULL);
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000883 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 {
885 if (children[i] == ignore)
886 continue;
887 if (has_submenu(children[i]))
888 return True;
889 }
890 return False;
891}
892
893 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100894gui_athena_menu_font(Widget id)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895{
896#ifdef FONTSET_ALWAYS
897 if (gui.menu_fontset != NOFONTSET)
898 {
899 if (XtIsManaged(id))
900 {
901 XtUnmanageChild(id);
902 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
903 /* We should force the widget to recalculate it's
904 * geometry now. */
905 XtManageChild(id);
906 }
907 else
908 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
909 if (has_submenu(id))
910 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
911 }
912#else
913 int managed = FALSE;
914
915 if (gui.menu_font != NOFONT)
916 {
917 if (XtIsManaged(id))
918 {
919 XtUnmanageChild(id);
920 managed = TRUE;
921 }
922
923# ifdef FEAT_XFONTSET
924 if (gui.fontset != NOFONTSET)
925 XtVaSetValues(id, XtNfontSet, gui.menu_font, NULL);
926 else
927# endif
928 XtVaSetValues(id, XtNfont, gui.menu_font, NULL);
929 if (has_submenu(id))
930 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
931
932 /* Force the widget to recalculate it's geometry now. */
933 if (managed)
934 XtManageChild(id);
935 }
936#endif
937}
938
939
940 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100941gui_mch_new_menu_font(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942{
943 Pixmap oldpuller = None;
944
945 if (menuBar == (Widget)0)
946 return;
947
948 if (pullerBitmap != None)
949 {
950 oldpuller = pullerBitmap;
951 pullerBitmap = gui_athena_create_pullright_pixmap(NULL);
952 }
953 gui_mch_submenu_change(root_menu, FALSE);
954
955 {
956 /* Iterate through the menubar menu items and get the height of
957 * each one. The menu bar height is set to the maximum of all
958 * the heights.
959 */
960 vimmenu_T *mp;
961 int max_height = 9999;
962
963 for (mp = root_menu; mp != NULL; mp = mp->next)
964 {
965 if (menu_is_menubar(mp->dname))
966 {
967 Dimension height;
968
969 XtVaGetValues(mp->id,
Bram Moolenaar623fd5e2005-01-25 21:42:15 +0000970 XtNheight, &height,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 NULL);
972 if (height < max_height)
973 max_height = height;
974 }
975 }
976 if (max_height != 9999)
977 {
978 /* Don't update the menu height when it was set at a fixed value */
979 if (!gui.menu_height_fixed)
980 {
981 Dimension space, border;
982
983 XtVaGetValues(menuBar,
984 XtNvSpace, &space,
985 XtNborderWidth, &border,
986 NULL);
987 gui.menu_height = max_height + 2 * (space + border);
988 }
989 }
990 }
991 /* Now, to simulate the window being resized. Only, this
992 * will resize the window to it's current state.
993 *
994 * There has to be a better way, but I do not see one at this time.
995 * (David Harrison)
996 */
997 {
998 Position w, h;
999
1000 XtVaGetValues(vimShell,
1001 XtNwidth, &w,
1002 XtNheight, &h,
1003 NULL);
1004 gui_resize_shell(w, h
1005#ifdef FEAT_XIM
1006 - xim_get_status_area_height()
1007#endif
1008 );
1009 }
Bram Moolenaar2e2a2812006-03-27 20:55:21 +00001010 gui_set_shellsize(FALSE, TRUE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 ui_new_shellsize();
1012 if (oldpuller != None)
1013 XFreePixmap(gui.dpy, oldpuller);
1014}
1015
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001016#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001018gui_mch_new_tooltip_font(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019{
1020# ifdef FEAT_TOOLBAR
1021 vimmenu_T *menu;
1022
1023 if (toolBar == (Widget)0)
1024 return;
1025
1026 menu = gui_find_menu((char_u *)"ToolBar");
1027 if (menu != NULL)
1028 gui_mch_submenu_change(menu, FALSE);
1029# endif
1030}
1031
1032 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001033gui_mch_new_tooltip_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001034{
1035# ifdef FEAT_TOOLBAR
1036 vimmenu_T *menu;
1037
1038 if (toolBar == (Widget)0)
1039 return;
1040
1041 menu = gui_find_menu((char_u *)"ToolBar");
1042 if (menu != NULL)
1043 gui_mch_submenu_change(menu, TRUE);
1044# endif
1045}
1046#endif
1047
1048 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001049gui_mch_submenu_change(
1050 vimmenu_T *menu,
1051 int colors) /* TRUE for colors, FALSE for font */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052{
1053 vimmenu_T *mp;
1054
1055 for (mp = menu; mp != NULL; mp = mp->next)
1056 {
1057 if (mp->id != (Widget)0)
1058 {
1059 if (colors)
1060 {
1061 gui_athena_menu_colors(mp->id);
1062#ifdef FEAT_TOOLBAR
1063 /* For a toolbar item: Free the pixmap and allocate a new one,
1064 * so that the background color is right. */
1065 if (mp->image != (Pixmap)0)
1066 {
1067 XFreePixmap(gui.dpy, mp->image);
Bram Moolenaar34114692005-01-02 11:28:13 +00001068 get_toolbar_pixmap(mp, &mp->image);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 if (mp->image != (Pixmap)0)
1070 XtVaSetValues(mp->id, XtNbitmap, mp->image, NULL);
1071 }
1072
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001073# ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 /* If we have a tooltip, then we need to change it's colors */
1075 if (mp->tip != NULL)
1076 {
1077 Arg args[2];
1078
1079 args[0].name = XtNbackground;
1080 args[0].value = gui.tooltip_bg_pixel;
1081 args[1].name = XtNforeground;
1082 args[1].value = gui.tooltip_fg_pixel;
1083 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1084 }
1085# endif
1086#endif
1087 }
1088 else
1089 {
1090 gui_athena_menu_font(mp->id);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001091#ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 /* If we have a tooltip, then we need to change it's font */
1093 /* Assume XtNinternational == True (in createBalloonEvalWindow)
1094 */
1095 if (mp->tip != NULL)
1096 {
1097 Arg args[1];
1098
1099 args[0].name = XtNfontSet;
1100 args[0].value = (XtArgVal)gui.tooltip_fontset;
1101 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1102 }
1103#endif
1104 }
1105 }
1106
1107 if (mp->children != NULL)
1108 {
1109 /* Set the colors/font for the tear off widget */
1110 if (mp->submenu_id != (Widget)0)
1111 {
1112 if (colors)
1113 gui_athena_menu_colors(mp->submenu_id);
1114 else
1115 gui_athena_menu_font(mp->submenu_id);
1116 }
1117 /* Set the colors for the children */
1118 gui_mch_submenu_change(mp->children, colors);
1119 }
1120 }
1121}
1122
1123/*
1124 * Make a submenu name into a pullright name.
1125 * Replace '.' by '_', can't include '.' in the submenu name.
1126 */
1127 static char_u *
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001128make_pull_name(char_u * name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129{
1130 char_u *pname;
1131 char_u *p;
1132
1133 pname = vim_strnsave(name, STRLEN(name) + strlen("-pullright"));
1134 if (pname != NULL)
1135 {
1136 strcat((char *)pname, "-pullright");
1137 while ((p = vim_strchr(pname, '.')) != NULL)
1138 *p = '_';
1139 }
1140 return pname;
1141}
1142
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001144gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001145{
1146 vimmenu_T *parent = menu->parent;
1147
1148 a_cur_menu = menu;
1149# ifdef FEAT_TOOLBAR
1150 if (menu_is_toolbar(parent->name))
1151 {
1152 WidgetClass type;
1153 int n;
1154 Arg args[21];
1155
1156 n = 0;
1157 if (menu_is_separator(menu->name))
1158 {
1159 XtSetArg(args[n], XtNlabel, ""); n++;
1160 XtSetArg(args[n], XtNborderWidth, 0); n++;
1161 }
1162 else
1163 {
Bram Moolenaar34114692005-01-02 11:28:13 +00001164 get_toolbar_pixmap(menu, &menu->image);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 XtSetArg(args[n], XtNlabel, menu->dname); n++;
1166 XtSetArg(args[n], XtNinternalHeight, 1); n++;
1167 XtSetArg(args[n], XtNinternalWidth, 1); n++;
1168 XtSetArg(args[n], XtNborderWidth, 1); n++;
1169 if (menu->image != 0)
1170 XtSetArg(args[n], XtNbitmap, menu->image); n++;
1171 }
1172 XtSetArg(args[n], XtNhighlightThickness, 0); n++;
1173 type = commandWidgetClass;
1174 /* TODO: figure out the position in the toolbar?
1175 * This currently works fine for the default toolbar, but
1176 * what if we add/remove items during later runtime?
1177 */
1178
1179 /* NOTE: "idx" isn't used here. The position is calculated by
1180 * athena_calculate_ins_pos(). The position it calculates
1181 * should be equal to "idx".
1182 */
1183 /* TODO: Could we just store "idx" and use that as the child
1184 * placement?
1185 */
1186
1187 if (menu->id == NULL)
1188 {
1189 menu->id = XtCreateManagedWidget((char *)menu->dname,
1190 type, toolBar, args, n);
1191 XtAddCallback(menu->id,
1192 XtNcallback, gui_x11_menu_cb, menu);
1193 }
1194 else
1195 XtSetValues(menu->id, args, n);
1196 gui_athena_menu_colors(menu->id);
1197
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001198#ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001199 gui_mch_menu_set_tip(menu);
1200#endif
1201
1202 menu->parent = parent;
1203 menu->submenu_id = NULL;
1204 if (!XtIsManaged(toolBar)
1205 && vim_strchr(p_go, GO_TOOLBAR) != NULL)
1206 gui_mch_show_toolbar(TRUE);
1207 gui.toolbar_height = gui_mch_compute_toolbar_height();
1208 return;
1209 } /* toolbar menu item */
1210# endif
1211
1212 /* Add menu separator */
1213 if (menu_is_separator(menu->name))
1214 {
1215 menu->submenu_id = (Widget)0;
1216 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
1217 smeLineObjectClass, parent->submenu_id,
1218 NULL);
1219 if (menu->id == (Widget)0)
1220 return;
1221 gui_athena_menu_colors(menu->id);
1222 }
1223 else
1224 {
1225 if (parent != NULL && parent->submenu_id != (Widget)0)
1226 {
1227 menu->submenu_id = (Widget)0;
1228 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
1229 smeBSBObjectClass, parent->submenu_id,
1230 XtNlabel, menu->dname,
1231#ifdef FONTSET_ALWAYS
1232 XtNinternational, True,
1233#endif
1234 NULL);
1235 if (menu->id == (Widget)0)
1236 return;
1237
1238 /* If there are other "pulldown" items in this pane, then adjust
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02001239 * the right margin to accommodate the arrow pixmap, otherwise
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 * the right margin will be the same as the left margin.
1241 */
1242 {
1243 Dimension left_margin;
1244
1245 XtVaGetValues(menu->id, XtNleftMargin, &left_margin, NULL);
1246 XtVaSetValues(menu->id, XtNrightMargin,
1247 gui_athena_menu_has_submenus(parent->submenu_id, NULL) ?
1248 puller_width :
1249 left_margin,
1250 NULL);
1251 }
1252
1253 gui_athena_menu_colors(menu->id);
1254 gui_athena_menu_font(menu->id);
1255 XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
1256 (XtPointer)menu);
1257 }
1258 }
1259 a_cur_menu = NULL;
1260}
1261
1262#if defined(FEAT_TOOLBAR) || defined(PROTO)
1263 void
1264gui_mch_show_toolbar(int showit)
1265{
1266 Cardinal numChildren; /* how many children toolBar has */
1267
1268 if (toolBar == (Widget)0)
1269 return;
1270 XtVaGetValues(toolBar, XtNnumChildren, &numChildren, NULL);
1271 if (showit && numChildren > 0)
1272 {
1273 /* Assume that we want to show the toolbar if p_toolbar contains valid
1274 * option settings, therefore p_toolbar must not be NULL.
1275 */
1276 WidgetList children;
1277
1278 XtVaGetValues(toolBar, XtNchildren, &children, NULL);
1279 {
1280 void (*action)(BalloonEval *);
1281 int text = 0;
1282
1283 if (strstr((const char *)p_toolbar, "tooltips"))
1284 action = &gui_mch_enable_beval_area;
1285 else
1286 action = &gui_mch_disable_beval_area;
1287 if (strstr((const char *)p_toolbar, "text"))
1288 text = 1;
1289 else if (strstr((const char *)p_toolbar, "icons"))
1290 text = -1;
1291 if (text != 0)
1292 {
1293 vimmenu_T *toolbar;
1294 vimmenu_T *cur;
1295
1296 for (toolbar = root_menu; toolbar; toolbar = toolbar->next)
1297 if (menu_is_toolbar(toolbar->dname))
1298 break;
1299 /* Assumption: toolbar is NULL if there is no toolbar,
1300 * otherwise it contains the toolbar menu structure.
1301 *
1302 * Assumption: "numChildren" == the number of items in the list
1303 * of items beginning with toolbar->children.
1304 */
1305 if (toolbar)
1306 {
1307 for (cur = toolbar->children; cur; cur = cur->next)
1308 {
1309 Arg args[2];
1310 int n = 0;
1311
1312 /* Enable/Disable tooltip (OK to enable while currently
1313 * enabled)
1314 */
1315 if (cur->tip != NULL)
1316 (*action)(cur->tip);
1317 if (text == 1)
1318 {
1319 XtSetArg(args[n], XtNbitmap, None);
1320 n++;
1321 XtSetArg(args[n], XtNlabel,
1322 menu_is_separator(cur->name) ? "" :
1323 (char *)cur->dname);
1324 n++;
1325 }
1326 else
1327 {
1328 XtSetArg(args[n], XtNbitmap, cur->image);
1329 n++;
1330 XtSetArg(args[n], XtNlabel, (cur->image == None) ?
1331 menu_is_separator(cur->name) ?
1332 "" :
1333 (char *)cur->dname
1334 :
1335 (char *)None);
1336 n++;
1337 }
1338 if (cur->id != NULL)
1339 {
1340 XtUnmanageChild(cur->id);
1341 XtSetValues(cur->id, args, n);
1342 XtManageChild(cur->id);
1343 }
1344 }
1345 }
1346 }
1347 }
1348 gui.toolbar_height = gui_mch_compute_toolbar_height();
1349 XtManageChild(toolBar);
1350 if (XtIsManaged(menuBar))
1351 {
1352 XtVaSetValues(textArea,
1353 XtNvertDistance, gui.toolbar_height + gui.menu_height,
1354 NULL);
1355 XtVaSetValues(toolBar,
1356 XtNvertDistance, gui.menu_height,
1357 NULL);
1358 }
1359 else
1360 {
1361 XtVaSetValues(textArea,
1362 XtNvertDistance, gui.toolbar_height,
1363 NULL);
1364 XtVaSetValues(toolBar,
1365 XtNvertDistance, 0,
1366 NULL);
1367 }
1368 }
1369 else
1370 {
1371 gui.toolbar_height = 0;
1372 if (XtIsManaged(menuBar))
1373 XtVaSetValues(textArea,
1374 XtNvertDistance, gui.menu_height,
1375 NULL);
1376 else
1377 XtVaSetValues(textArea,
1378 XtNvertDistance, 0,
1379 NULL);
1380
1381 XtUnmanageChild(toolBar);
1382 }
Bram Moolenaar2e2a2812006-03-27 20:55:21 +00001383 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384}
1385
1386
1387 int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001388gui_mch_compute_toolbar_height(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001389{
1390 Dimension height; /* total Toolbar height */
1391 Dimension whgt; /* height of each widget */
1392 Dimension marginHeight; /* XmNmarginHeight of toolBar */
1393 Dimension shadowThickness; /* thickness of Xtparent(toolBar) */
1394 WidgetList children; /* list of toolBar's children */
1395 Cardinal numChildren; /* how many children toolBar has */
1396 int i;
1397
1398 height = 0;
1399 shadowThickness = 0;
1400 marginHeight = 0;
1401 if (toolBar != (Widget)0)
1402 {
1403 XtVaGetValues(toolBar,
1404 XtNborderWidth, &shadowThickness,
1405 XtNvSpace, &marginHeight,
1406 XtNchildren, &children,
1407 XtNnumChildren, &numChildren,
1408 NULL);
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00001409 for (i = 0; i < (int)numChildren; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001410 {
1411 whgt = 0;
1412
1413 XtVaGetValues(children[i], XtNheight, &whgt, NULL);
1414 if (height < whgt)
1415 height = whgt;
1416 }
1417 }
1418
1419 return (int)(height + (marginHeight << 1) + (shadowThickness << 1));
1420}
1421
1422 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001423gui_mch_get_toolbar_colors(
1424 Pixel *bgp,
1425 Pixel *fgp,
1426 Pixel *bsp,
1427 Pixel *tsp,
1428 Pixel *hsp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429{
1430 XtVaGetValues(toolBar, XtNbackground, bgp, XtNborderColor, fgp, NULL);
1431 *bsp = *bgp;
1432 *tsp = *fgp;
1433 *hsp = *tsp;
1434}
1435#endif
1436
1437
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001439gui_mch_toggle_tearoffs(int enable UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001440{
1441 /* no tearoff menus */
1442}
1443
1444 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001445gui_mch_new_menu_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446{
1447 if (menuBar == (Widget)0)
1448 return;
1449 if (gui.menu_fg_pixel != INVALCOLOR)
1450 XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
1451 gui_athena_menu_colors(menuBar);
1452#ifdef FEAT_TOOLBAR
1453 gui_athena_menu_colors(toolBar);
1454#endif
1455
1456 gui_mch_submenu_change(root_menu, TRUE);
1457}
1458
1459/*
1460 * Destroy the machine specific menu widget.
1461 */
1462 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001463gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001464{
1465 Widget parent;
1466
1467 /* There is no item for the toolbar. */
1468 if (menu->id == (Widget)0)
1469 return;
1470
1471 parent = XtParent(menu->id);
1472
1473 /* When removing the last "pulldown" menu item from a pane, adjust the
1474 * right margins of the remaining widgets.
1475 */
1476 if (menu->submenu_id != (Widget)0)
1477 {
1478 /* Go through the menu items in the parent of this item and
1479 * adjust their margins, if necessary.
1480 * This takes care of the case when we delete the last menu item in a
1481 * pane that has a submenu. In this case, there will be no arrow
1482 * pixmaps shown anymore.
1483 */
1484 {
1485 WidgetList children;
1486 Cardinal num_children;
1487 int i;
1488 Dimension right_margin = 0;
1489 Boolean get_left_margin = False;
1490
1491 XtVaGetValues(parent, XtNchildren, &children,
1492 XtNnumChildren, &num_children,
1493 NULL);
1494 if (gui_athena_menu_has_submenus(parent, menu->id))
1495 right_margin = puller_width;
1496 else
1497 get_left_margin = True;
1498
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00001499 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500 {
1501 if (children[i] == menu->id)
1502 continue;
1503 if (get_left_margin == True)
1504 {
1505 Dimension left_margin;
1506
1507 XtVaGetValues(children[i], XtNleftMargin, &left_margin,
1508 NULL);
1509 XtVaSetValues(children[i], XtNrightMargin, left_margin,
1510 NULL);
1511 }
1512 else
1513 XtVaSetValues(children[i], XtNrightMargin, right_margin,
1514 NULL);
1515 }
1516 }
1517 }
1518 /* Please be sure to destroy the parent widget first (i.e. menu->id).
1519 *
1520 * This code should be basically identical to that in the file gui_motif.c
1521 * because they are both Xt based.
1522 */
1523 if (menu->id != (Widget)0)
1524 {
1525 Cardinal num_children;
1526 Dimension height, space, border;
1527
1528 XtVaGetValues(menuBar,
1529 XtNvSpace, &space,
1530 XtNborderWidth, &border,
1531 NULL);
1532 XtVaGetValues(menu->id,
1533 XtNheight, &height,
1534 NULL);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001535#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL_GUI)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001536 if (parent == toolBar && menu->tip != NULL)
1537 {
1538 /* We try to destroy this before the actual menu, because there are
1539 * callbacks, etc. that will be unregistered during the tooltip
1540 * destruction.
1541 *
1542 * If you call "gui_mch_destroy_beval_area()" after destroying
1543 * menu->id, then the tooltip's window will have already been
1544 * deallocated by Xt, and unknown behaviour will ensue (probably
1545 * a core dump).
1546 */
1547 gui_mch_destroy_beval_area(menu->tip);
1548 menu->tip = NULL;
1549 }
1550#endif
1551 /*
1552 * This is a hack to stop the Athena simpleMenuWidget from getting a
1553 * BadValue error when a menu's last child is destroyed. We check to
1554 * see if this is the last child and if so, don't delete it. The parent
1555 * will be deleted soon anyway, and it will delete it's children like
1556 * all good widgets do.
1557 */
1558 /* NOTE: The cause of the BadValue X Protocol Error is because when the
1559 * last child is destroyed, it is first unmanaged, thus causing a
1560 * geometry resize request from the parent Shell widget.
1561 * Since the Shell widget has no more children, it is resized to have
1562 * width/height of 0. XConfigureWindow() is then called with the
1563 * width/height of 0, which generates the BadValue.
1564 *
1565 * This happens in phase two of the widget destruction process.
1566 */
1567 {
1568 if (parent != menuBar
1569#ifdef FEAT_TOOLBAR
1570 && parent != toolBar
1571#endif
1572 )
1573 {
1574 XtVaGetValues(parent, XtNnumChildren, &num_children, NULL);
1575 if (num_children > 1)
1576 XtDestroyWidget(menu->id);
1577 }
1578 else
1579 XtDestroyWidget(menu->id);
1580 menu->id = (Widget)0;
1581 }
1582
1583 if (parent == menuBar)
1584 {
1585 if (!gui.menu_height_fixed)
1586 gui.menu_height = height + 2 * (space + border);
1587 }
1588#ifdef FEAT_TOOLBAR
1589 else if (parent == toolBar)
1590 {
1591 /* When removing last toolbar item, don't display the toolbar. */
1592 XtVaGetValues(toolBar, XtNnumChildren, &num_children, NULL);
1593 if (num_children == 0)
1594 gui_mch_show_toolbar(FALSE);
1595 else
1596 gui.toolbar_height = gui_mch_compute_toolbar_height();
1597 }
1598#endif
1599 }
1600 if (menu->submenu_id != (Widget)0)
1601 {
1602 XtDestroyWidget(menu->submenu_id);
1603 menu->submenu_id = (Widget)0;
1604 }
1605}
1606
Bram Moolenaar071d4272004-06-13 20:20:40 +00001607 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001608gui_athena_menu_timeout(
1609 XtPointer client_data,
1610 XtIntervalId *id UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611{
1612 Widget w = (Widget)client_data;
1613 Widget popup;
1614
1615 timer = 0;
1616 if (XtIsSubclass(w,smeBSBObjectClass))
1617 {
1618 Pixmap p;
1619
1620 XtVaGetValues(w, XtNrightBitmap, &p, NULL);
1621 if ((p != None) && (p != XtUnspecifiedPixmap))
1622 {
1623 /* We are dealing with an item that has a submenu */
1624 popup = get_popup_entry(XtParent(w));
1625 if (popup == (Widget)0)
1626 return;
1627 XtPopup(popup, XtGrabNonexclusive);
1628 }
1629 }
1630}
1631
1632/* This routine is used to calculate the position (in screen coordinates)
1633 * where a submenu should appear relative to the menu entry that popped it
1634 * up. It should appear even with and just slightly to the left of the
1635 * rightmost end of the menu entry that caused the popup.
1636 *
1637 * This is called when XtPopup() is called.
1638 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001640gui_athena_popup_callback(
1641 Widget w,
1642 XtPointer client_data,
1643 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001644{
1645 /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */
1646 vimmenu_T *menu = (vimmenu_T *)client_data;
1647 Dimension width;
1648 Position root_x, root_y;
1649
1650 /* First, popdown any siblings that may have menus popped up */
1651 {
1652 vimmenu_T *i;
1653
1654 for (i = menu->parent->children; i != NULL; i = i->next)
1655 {
1656 if (i->submenu_id != NULL && XtIsManaged(i->submenu_id))
1657 XtPopdown(i->submenu_id);
1658 }
1659 }
1660 XtVaGetValues(XtParent(w),
1661 XtNwidth, &width,
1662 NULL);
1663 /* Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id */
1664 /* i.e. This IS the active entry */
1665 XtTranslateCoords(menu->id,width - 5, 0, &root_x, &root_y);
1666 XtVaSetValues(w, XtNx, root_x,
1667 XtNy, root_y,
1668 NULL);
1669}
1670
Bram Moolenaar071d4272004-06-13 20:20:40 +00001671 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001672gui_athena_popdown_submenus_action(
1673 Widget w,
1674 XEvent *event,
1675 String *args,
1676 Cardinal *nargs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001677{
1678 WidgetList children;
1679 Cardinal num_children;
1680
1681 XtVaGetValues(w, XtNchildren, &children,
1682 XtNnumChildren, &num_children,
1683 NULL);
1684 for (; num_children > 0; --num_children)
1685 {
1686 Widget child = children[num_children - 1];
1687
1688 if (has_submenu(child))
1689 {
1690 Widget temp_w;
1691
1692 temp_w = submenu_widget(child);
1693 gui_athena_popdown_submenus_action(temp_w,event,args,nargs);
1694 XtPopdown(temp_w);
1695 }
1696 }
1697}
1698
1699/* Used to determine if the given widget has a submenu that can be popped up. */
1700 static Boolean
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001701has_submenu(Widget widget)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702{
1703 if ((widget != NULL) && XtIsSubclass(widget,smeBSBObjectClass))
1704 {
1705 Pixmap p;
1706
1707 XtVaGetValues(widget, XtNrightBitmap, &p, NULL);
1708 if ((p != None) && (p != XtUnspecifiedPixmap))
1709 return True;
1710 }
1711 return False;
1712}
1713
Bram Moolenaar071d4272004-06-13 20:20:40 +00001714 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001715gui_athena_delayed_arm_action(
1716 Widget w,
1717 XEvent *event,
1718 String *args,
1719 Cardinal *nargs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720{
1721 Dimension width, height;
1722
1723 if (event->type != MotionNotify)
1724 return;
1725
1726 XtVaGetValues(w,
1727 XtNwidth, &width,
1728 XtNheight, &height,
1729 NULL);
1730
1731 if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height)
1732 return;
1733
1734 {
1735 static Widget previous_active_widget = NULL;
1736 Widget current;
1737
1738 current = XawSimpleMenuGetActiveEntry(w);
1739 if (current != previous_active_widget)
1740 {
1741 if (timer)
1742 {
1743 /* If the timeout hasn't been triggered, remove it */
1744 XtRemoveTimeOut(timer);
1745 }
1746 gui_athena_popdown_submenus_action(w,event,args,nargs);
1747 if (has_submenu(current))
1748 {
1749 XtAppAddTimeOut(XtWidgetToApplicationContext(w), 600L,
1750 gui_athena_menu_timeout,
1751 (XtPointer)current);
1752 }
1753 previous_active_widget = current;
1754 }
1755 }
1756}
1757
1758 static Widget
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001759get_popup_entry(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760{
1761 Widget menuw;
1762
1763 /* Get the active entry for the current menu */
1764 if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)0)
1765 return NULL;
1766
1767 return submenu_widget(menuw);
1768}
1769
1770/* Given the widget that has been determined to have a submenu, return the submenu widget
1771 * that is to be popped up.
1772 */
1773 static Widget
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001774submenu_widget(Widget widget)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775{
1776 /* Precondition: has_submenu(widget) == True
1777 * XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True
1778 */
1779
1780 char_u *pullright_name;
1781 Widget popup;
1782
1783 pullright_name = make_pull_name((char_u *)XtName(widget));
1784 popup = XtNameToWidget(XtParent(widget), (char *)pullright_name);
1785 vim_free(pullright_name);
1786
1787 return popup;
1788 /* Postcondition: (popup != NULL) implies
1789 * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */
1790}
1791
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001793gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794{
1795 int rootx, rooty, winx, winy;
1796 Window root, child;
1797 unsigned int mask;
1798
1799 if (menu->submenu_id == (Widget)0)
1800 return;
1801
1802 /* Position the popup menu at the pointer */
1803 if (XQueryPointer(gui.dpy, XtWindow(vimShell), &root, &child,
1804 &rootx, &rooty, &winx, &winy, &mask))
1805 {
1806 rootx -= 30;
1807 if (rootx < 0)
1808 rootx = 0;
1809 rooty -= 5;
1810 if (rooty < 0)
1811 rooty = 0;
1812 XtVaSetValues(menu->submenu_id,
1813 XtNx, rootx,
1814 XtNy, rooty,
1815 NULL);
1816 }
1817
1818 XtOverrideTranslations(menu->submenu_id, popupTrans);
1819 XtPopupSpringLoaded(menu->submenu_id);
1820}
1821
1822#endif /* FEAT_MENU */
1823
1824/*
1825 * Set the menu and scrollbar colors to their default values.
1826 */
1827 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001828gui_mch_def_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829{
1830 /*
1831 * Get the colors ourselves. Using the automatic conversion doesn't
1832 * handle looking for approximate colors.
1833 */
1834 if (gui.in_use)
1835 {
1836 gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
1837 gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
1838 gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
1839 gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001840#ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841 gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
1842 gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
1843#endif
1844 }
1845}
1846
1847
1848/*
1849 * Scrollbar stuff.
1850 */
1851
1852 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001853gui_mch_set_scrollbar_thumb(
1854 scrollbar_T *sb,
1855 long val,
1856 long size,
1857 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001858{
1859 double v, s;
1860
1861 if (sb->id == (Widget)0)
1862 return;
1863
1864 /*
1865 * Athena scrollbar must go from 0.0 to 1.0.
1866 */
1867 if (max == 0)
1868 {
1869 /* So you can't scroll it at all (normally it scrolls past end) */
1870#ifdef FEAT_GUI_NEXTAW
1871 XawScrollbarSetThumb(sb->id, 0.0, 1.0);
1872#else
1873 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
1874#endif
1875 }
1876 else
1877 {
1878 v = (double)val / (double)(max + 1);
1879 s = (double)size / (double)(max + 1);
1880#ifdef FEAT_GUI_NEXTAW
1881 XawScrollbarSetThumb(sb->id, v, s);
1882#else
1883 vim_XawScrollbarSetThumb(sb->id, v, s, 1.0);
1884#endif
1885 }
1886}
1887
1888 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001889gui_mch_set_scrollbar_pos(
1890 scrollbar_T *sb,
1891 int x,
1892 int y,
1893 int w,
1894 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895{
1896 if (sb->id == (Widget)0)
1897 return;
1898
1899 XtUnmanageChild(sb->id);
1900 XtVaSetValues(sb->id,
1901 XtNhorizDistance, x,
1902 XtNvertDistance, y,
1903 XtNwidth, w,
1904 XtNheight, h,
1905 NULL);
1906 XtManageChild(sb->id);
1907}
1908
1909 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001910gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911{
1912 if (sb->id != (Widget)0)
1913 {
1914 if (flag)
1915 XtManageChild(sb->id);
1916 else
1917 XtUnmanageChild(sb->id);
1918 }
1919}
1920
1921 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001922gui_mch_create_scrollbar(
1923 scrollbar_T *sb,
1924 int orient) /* SBAR_VERT or SBAR_HORIZ */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925{
1926 sb->id = XtVaCreateWidget("scrollBar",
1927#ifdef FEAT_GUI_NEXTAW
1928 scrollbarWidgetClass, vimForm,
1929#else
1930 vim_scrollbarWidgetClass, vimForm,
1931#endif
1932 XtNresizable, True,
1933 XtNtop, XtChainTop,
1934 XtNbottom, XtChainTop,
1935 XtNleft, XtChainLeft,
1936 XtNright, XtChainLeft,
1937 XtNborderWidth, 0,
1938 XtNorientation, (orient == SBAR_VERT) ? XtorientVertical
1939 : XtorientHorizontal,
1940 XtNforeground, gui.scroll_fg_pixel,
1941 XtNbackground, gui.scroll_bg_pixel,
1942 NULL);
1943 if (sb->id == (Widget)0)
1944 return;
1945
1946 XtAddCallback(sb->id, XtNjumpProc,
1947 gui_athena_scroll_cb_jump, (XtPointer)sb->ident);
1948 XtAddCallback(sb->id, XtNscrollProc,
1949 gui_athena_scroll_cb_scroll, (XtPointer)sb->ident);
1950
1951#ifdef FEAT_GUI_NEXTAW
1952 XawScrollbarSetThumb(sb->id, 0.0, 1.0);
1953#else
1954 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
1955#endif
1956}
1957
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001959gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960{
1961 if (sb->id != (Widget)0)
1962 XtDestroyWidget(sb->id);
1963}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001964
1965 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001966gui_mch_set_scrollbar_colors(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967{
1968 if (sb->id != (Widget)0)
1969 XtVaSetValues(sb->id,
1970 XtNforeground, gui.scroll_fg_pixel,
1971 XtNbackground, gui.scroll_bg_pixel,
1972 NULL);
1973
1974 /* This is needed for the rectangle below the vertical scrollbars. */
1975 if (sb == &gui.bottom_sbar && vimForm != (Widget)0)
1976 gui_athena_scroll_colors(vimForm);
1977}
1978
1979/*
1980 * Miscellaneous stuff:
1981 */
1982 Window
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001983gui_x11_get_wid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984{
1985 return XtWindow(textArea);
1986}
1987
1988#if defined(FEAT_BROWSE) || defined(PROTO)
1989/*
1990 * Put up a file requester.
1991 * Returns the selected name in allocated memory, or NULL for Cancel.
1992 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001993 char_u *
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001994gui_mch_browse(
1995 int saving UNUSED, /* select file to write */
1996 char_u *title, /* title for the window */
1997 char_u *dflt, /* default name */
1998 char_u *ext UNUSED, /* extension added */
1999 char_u *initdir, /* initial directory, NULL for current dir */
2000 char_u *filter UNUSED) /* file name filter */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001{
2002 Position x, y;
2003 char_u dirbuf[MAXPATHL];
2004
2005 /* Concatenate "initdir" and "dflt". */
2006 if (initdir == NULL || *initdir == NUL)
2007 mch_dirname(dirbuf, MAXPATHL);
2008 else if (STRLEN(initdir) + 2 < MAXPATHL)
2009 STRCPY(dirbuf, initdir);
2010 else
2011 dirbuf[0] = NUL;
2012 if (dflt != NULL && *dflt != NUL
2013 && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL)
2014 {
2015 add_pathsep(dirbuf);
2016 STRCAT(dirbuf, dflt);
2017 }
2018
2019 /* Position the file selector just below the menubar */
2020 XtTranslateCoords(vimShell, (Position)0, (Position)
2021#ifdef FEAT_MENU
2022 gui.menu_height
2023#else
2024 0
2025#endif
2026 , &x, &y);
2027 return (char_u *)vim_SelFile(vimShell, (char *)title, (char *)dirbuf,
2028 NULL, (int)x, (int)y, gui.menu_fg_pixel, gui.menu_bg_pixel,
2029 gui.scroll_fg_pixel, gui.scroll_bg_pixel);
2030}
2031#endif
2032
2033#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2034
2035static int dialogStatus;
2036static Atom dialogatom;
2037
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038/*
2039 * Callback function for the textfield. When CR is hit this works like
2040 * hitting the "OK" button, ESC like "Cancel".
2041 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002043keyhit_callback(
2044 Widget w UNUSED,
2045 XtPointer client_data UNUSED,
2046 XEvent *event,
2047 Boolean *cont UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048{
2049 char buf[2];
2050
2051 if (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1)
2052 {
2053 if (*buf == CAR)
2054 dialogStatus = 1;
2055 else if (*buf == ESC)
2056 dialogStatus = 0;
2057 }
2058}
2059
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002061butproc(
2062 Widget w UNUSED,
2063 XtPointer client_data,
2064 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065{
2066 dialogStatus = (int)(long)client_data + 1;
2067}
2068
2069/*
2070 * Function called when dialog window closed.
2071 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002073dialog_wm_handler(
2074 Widget w UNUSED,
2075 XtPointer client_data UNUSED,
2076 XEvent *event,
2077 Boolean *dum UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078{
2079 if (event->type == ClientMessage
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00002080 && (Atom)((XClientMessageEvent *)event)->data.l[0] == dialogatom)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081 dialogStatus = 0;
2082}
2083
Bram Moolenaar071d4272004-06-13 20:20:40 +00002084 int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002085gui_mch_dialog(
2086 int type UNUSED,
2087 char_u *title,
2088 char_u *message,
2089 char_u *buttons,
2090 int dfltbutton UNUSED,
2091 char_u *textfield,
2092 int ex_cmd UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093{
2094 char_u *buts;
2095 char_u *p, *next;
2096 XtAppContext app;
2097 XEvent event;
2098 Position wd, hd;
2099 Position wv, hv;
2100 Position x, y;
2101 Widget dialog;
2102 Widget dialogshell;
2103 Widget dialogmessage;
2104 Widget dialogtextfield = 0;
2105 Widget dialogButton;
2106 Widget prev_dialogButton = NULL;
2107 int butcount;
2108 int vertical;
2109
2110 if (title == NULL)
2111 title = (char_u *)_("Vim dialog");
2112 dialogStatus = -1;
2113
2114 /* if our pointer is currently hidden, then we should show it. */
2115 gui_mch_mousehide(FALSE);
2116
2117 /* Check 'v' flag in 'guioptions': vertical button placement. */
2118 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
2119
2120 /* The shell is created each time, to make sure it is resized properly */
2121 dialogshell = XtVaCreatePopupShell("dialogShell",
2122 transientShellWidgetClass, vimShell,
2123 XtNtitle, title,
2124 NULL);
2125 if (dialogshell == (Widget)0)
2126 goto error;
2127
2128 dialog = XtVaCreateManagedWidget("dialog",
2129 formWidgetClass, dialogshell,
2130 XtNdefaultDistance, 20,
2131 NULL);
2132 if (dialog == (Widget)0)
2133 goto error;
2134 gui_athena_menu_colors(dialog);
2135 dialogmessage = XtVaCreateManagedWidget("dialogMessage",
2136 labelWidgetClass, dialog,
2137 XtNlabel, message,
2138 XtNtop, XtChainTop,
2139 XtNbottom, XtChainTop,
2140 XtNleft, XtChainLeft,
2141 XtNright, XtChainLeft,
2142 XtNresizable, True,
2143 XtNborderWidth, 0,
2144 NULL);
2145 gui_athena_menu_colors(dialogmessage);
2146
2147 if (textfield != NULL)
2148 {
2149 dialogtextfield = XtVaCreateManagedWidget("textfield",
2150 asciiTextWidgetClass, dialog,
2151 XtNwidth, 400,
2152 XtNtop, XtChainTop,
2153 XtNbottom, XtChainTop,
2154 XtNleft, XtChainLeft,
2155 XtNright, XtChainRight,
2156 XtNfromVert, dialogmessage,
2157 XtNresizable, True,
2158 XtNstring, textfield,
2159 XtNlength, IOSIZE,
2160 XtNuseStringInPlace, True,
2161 XtNeditType, XawtextEdit,
2162 XtNwrap, XawtextWrapNever,
2163 XtNresize, XawtextResizeHeight,
2164 NULL);
2165 XtManageChild(dialogtextfield);
2166 XtAddEventHandler(dialogtextfield, KeyPressMask, False,
2167 (XtEventHandler)keyhit_callback, (XtPointer)NULL);
2168 XawTextSetInsertionPoint(dialogtextfield,
2169 (XawTextPosition)STRLEN(textfield));
2170 XtSetKeyboardFocus(dialog, dialogtextfield);
2171 }
2172
2173 /* make a copy, so that we can insert NULs */
2174 buts = vim_strsave(buttons);
2175 if (buts == NULL)
2176 return -1;
2177
2178 p = buts;
2179 for (butcount = 0; *p; ++butcount)
2180 {
2181 for (next = p; *next; ++next)
2182 {
2183 if (*next == DLG_HOTKEY_CHAR)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002184 STRMOVE(next, next + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185 if (*next == DLG_BUTTON_SEP)
2186 {
2187 *next++ = NUL;
2188 break;
2189 }
2190 }
2191 dialogButton = XtVaCreateManagedWidget("button",
2192 commandWidgetClass, dialog,
2193 XtNlabel, p,
2194 XtNtop, XtChainBottom,
2195 XtNbottom, XtChainBottom,
2196 XtNleft, XtChainLeft,
2197 XtNright, XtChainLeft,
2198 XtNfromVert, textfield == NULL ? dialogmessage : dialogtextfield,
2199 XtNvertDistance, vertical ? 4 : 20,
2200 XtNresizable, False,
2201 NULL);
2202 gui_athena_menu_colors(dialogButton);
2203 if (butcount > 0)
2204 XtVaSetValues(dialogButton,
2205 vertical ? XtNfromVert : XtNfromHoriz, prev_dialogButton,
2206 NULL);
2207
Bram Moolenaar9d6650f2010-06-06 23:04:47 +02002208 XtAddCallback(dialogButton, XtNcallback, butproc, (XtPointer)(long_u)butcount);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209 p = next;
2210 prev_dialogButton = dialogButton;
2211 }
2212 vim_free(buts);
2213
2214 XtRealizeWidget(dialogshell);
2215
2216 /* Setup for catching the close-window event, don't let it close Vim! */
2217 dialogatom = XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
2218 XSetWMProtocols(gui.dpy, XtWindow(dialogshell), &dialogatom, 1);
2219 XtAddEventHandler(dialogshell, NoEventMask, True, dialog_wm_handler, NULL);
2220
2221 XtVaGetValues(dialogshell,
2222 XtNwidth, &wd,
2223 XtNheight, &hd,
2224 NULL);
2225 XtVaGetValues(vimShell,
2226 XtNwidth, &wv,
2227 XtNheight, &hv,
2228 NULL);
2229 XtTranslateCoords(vimShell,
2230 (Position)((wv - wd) / 2),
2231 (Position)((hv - hd) / 2),
2232 &x, &y);
2233 if (x < 0)
2234 x = 0;
2235 if (y < 0)
2236 y = 0;
2237 XtVaSetValues(dialogshell, XtNx, x, XtNy, y, NULL);
2238
2239 /* Position the mouse pointer in the dialog, required for when focus
2240 * follows mouse. */
2241 XWarpPointer(gui.dpy, (Window)0, XtWindow(dialogshell), 0, 0, 0, 0, 20, 40);
2242
2243
2244 app = XtWidgetToApplicationContext(dialogshell);
2245
2246 XtPopup(dialogshell, XtGrabNonexclusive);
2247
Bram Moolenaarac76e4d2005-07-09 20:58:57 +00002248 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 {
2250 XtAppNextEvent(app, &event);
2251 XtDispatchEvent(&event);
2252 if (dialogStatus >= 0)
2253 break;
2254 }
2255
2256 XtPopdown(dialogshell);
2257
2258 if (textfield != NULL && dialogStatus < 0)
2259 *textfield = NUL;
2260
2261error:
2262 XtDestroyWidget(dialogshell);
2263
2264 return dialogStatus;
2265}
2266#endif
2267
2268#if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
2269/*
2270 * Set the colors of Widget "id" to the menu colors.
2271 */
2272 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002273gui_athena_menu_colors(Widget id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274{
2275 if (gui.menu_bg_pixel != INVALCOLOR)
2276 XtVaSetValues(id, XtNbackground, gui.menu_bg_pixel, NULL);
2277 if (gui.menu_fg_pixel != INVALCOLOR)
2278 XtVaSetValues(id, XtNforeground, gui.menu_fg_pixel, NULL);
2279}
2280#endif
2281
2282/*
2283 * Set the colors of Widget "id" to the scroll colors.
2284 */
2285 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002286gui_athena_scroll_colors(Widget id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287{
2288 if (gui.scroll_bg_pixel != INVALCOLOR)
2289 XtVaSetValues(id, XtNbackground, gui.scroll_bg_pixel, NULL);
2290 if (gui.scroll_fg_pixel != INVALCOLOR)
2291 XtVaSetValues(id, XtNforeground, gui.scroll_fg_pixel, NULL);
2292}