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