blob: 6cbabf81d2e65a5ce75310822e78800afdbca679 [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>
Bram Moolenaar30613902019-12-01 22:11:18 +010037#endif // FEAT_GUI_NEXTAW
Bram Moolenaar071d4272004-06-13 20:20:40 +000038
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;
Bram Moolenaar30613902019-12-01 22:11:18 +010049static XtIntervalId timer = 0; // 0 = expired, otherwise active
Bram Moolenaar071d4272004-06-13 20:20:40 +000050
Bram Moolenaar30613902019-12-01 22:11:18 +010051// Used to figure out menu ordering
Bram Moolenaar071d4272004-06-13 20:20:40 +000052static 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;
Bram Moolenaar30613902019-12-01 22:11:18 +010099 else if (sb->wp != NULL) // Left or right scrollbar
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100 {
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 }
Bram Moolenaar30613902019-12-01 22:11:18 +0100108 else // Bottom scrollbar
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109 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;
Bram Moolenaar30613902019-12-01 22:11:18 +0100137 if (sb->wp != NULL) // Left or right scrollbar
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138 {
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)
Bram Moolenaar30613902019-12-01 22:11:18 +0100147 page = sb_info->size - 2; // use two lines of context
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148 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 }
Bram Moolenaar30613902019-12-01 22:11:18 +0100180 else // Bottom scrollbar
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181 {
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
Bram Moolenaar30613902019-12-01 22:11:18 +0100197 if (data < -1) // page-width left
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198 {
199 if (sb->size > 8)
200 data = -(sb->size - 5);
201 else
202 data = -sb->size;
203 }
Bram Moolenaar30613902019-12-01 22:11:18 +0100204 else if (data > 1) // page-width right
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205 {
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
Dominique Pelleaf4a61a2021-12-27 17:21:41 +0000219 // Update the bottom scrollbar an extra time (why is this needed??)
Bram Moolenaar30613902019-12-01 22:11:18 +0100220 if (sb->wp == NULL) // Bottom scrollbar
Bram Moolenaar071d4272004-06-13 20:20:40 +0000221 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 Moolenaar30613902019-12-01 22:11:18 +0100238 // The form containing all the other widgets
Bram Moolenaar071d4272004-06-13 20:20:40 +0000239 vimForm = XtVaCreateManagedWidget("vimForm",
240 formWidgetClass, vimShell,
241 XtNborderWidth, 0,
242 NULL);
243 gui_athena_scroll_colors(vimForm);
244
245#ifdef FEAT_MENU
Bram Moolenaar30613902019-12-01 22:11:18 +0100246 // The top menu bar
Bram Moolenaar071d4272004-06-13 20:20:40 +0000247 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
Bram Moolenaar30613902019-12-01 22:11:18 +0100262 // Don't create it Managed, it will be managed when creating the first
263 // item. Otherwise an empty toolbar shows up.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264 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
Bram Moolenaar30613902019-12-01 22:11:18 +0100279 // The text area.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280 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
Bram Moolenaar30613902019-12-01 22:11:18 +0100318 // Pretend we don't have input focus, we will get an event if we do.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 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
Bram Moolenaar30613902019-12-01 22:11:18 +0100355 // Assumption: The menuBar children will use the same font as the
356 // pulldown menu items AND they will all be of type
357 // XtNfont.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358 XtVaGetValues(menuBar, XtNchildren, &children,
359 XtNnumChildren, &num_children,
360 NULL);
361 if (XtConvertAndStore(w ? w :
362 (num_children > 0) ? children[0] : menuBar,
363 XtRString, &from,
364#ifdef FONTSET_ALWAYS
365 XtRFontSet, &to
366#else
367 XtRFontStruct, &to
368#endif
369 ) == False)
370 return None;
Bram Moolenaar30613902019-12-01 22:11:18 +0100371 // "font" should now contain data
Bram Moolenaar071d4272004-06-13 20:20:40 +0000372 }
373 else
374#ifdef FONTSET_ALWAYS
375 font = (XFontSet)gui.menu_fontset;
376#else
377 font = (XFontStruct *)gui.menu_font;
378#endif
379
380 {
381 int width, height;
382 GC draw_gc, undraw_gc;
383 XGCValues gc_values;
384 XPoint points[3];
385
386#ifdef FONTSET_ALWAYS
387 height = fontset_height2(font);
388#else
389 height = font->max_bounds.ascent + font->max_bounds.descent;
390#endif
391 width = height - 2;
392 puller_width = width + 4;
393 retval = XCreatePixmap(gui.dpy,DefaultRootWindow(gui.dpy),width,
394 height, 1);
395 gc_values.foreground = 1;
396 gc_values.background = 0;
397 draw_gc = XCreateGC(gui.dpy, retval,
398 GCForeground | GCBackground,
399 &gc_values);
400 gc_values.foreground = 0;
401 gc_values.background = 1;
402 undraw_gc = XCreateGC(gui.dpy, retval,
403 GCForeground | GCBackground,
404 &gc_values);
405 points[0].x = 0;
406 points[0].y = 0;
407 points[1].x = width - 1;
408 points[1].y = (height - 1) / 2;
409 points[2].x = 0;
410 points[2].y = height - 1;
411 XFillRectangle(gui.dpy, retval, undraw_gc, 0, 0, height, height);
412 XFillPolygon(gui.dpy, retval, draw_gc, points, XtNumber(points),
413 Convex, CoordModeOrigin);
414 XFreeGC(gui.dpy, draw_gc);
415 XFreeGC(gui.dpy, undraw_gc);
416 }
417 return retval;
418}
419#endif
420
421/*
422 * Called when the GUI is not going to start after all.
423 */
424 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100425gui_x11_destroy_widgets(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426{
427 textArea = NULL;
428#ifdef FEAT_MENU
429 menuBar = NULL;
430#endif
431#ifdef FEAT_TOOLBAR
432 toolBar = NULL;
433#endif
434}
435
436#if defined(FEAT_TOOLBAR) || defined(PROTO)
Bram Moolenaar34114692005-01-02 11:28:13 +0000437# include "gui_x11_pm.h"
438# ifdef HAVE_X11_XPM_H
439# include <X11/xpm.h>
440# endif
441
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100442static void createXpmImages(char_u *path, char **xpm, Pixmap *sen);
Bram Moolenaar34114692005-01-02 11:28:13 +0000443
444/*
445 * Allocated a pixmap for toolbar menu "menu".
446 * Return in "sen".
447 */
448 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100449get_toolbar_pixmap(vimmenu_T *menu, Pixmap *sen)
Bram Moolenaar34114692005-01-02 11:28:13 +0000450{
Bram Moolenaar30613902019-12-01 22:11:18 +0100451 char_u buf[MAXPATHL]; // buffer storing expanded pathname
452 char **xpm = NULL; // xpm array
Bram Moolenaar34114692005-01-02 11:28:13 +0000453
Bram Moolenaar30613902019-12-01 22:11:18 +0100454 buf[0] = NUL; // start with NULL path
Bram Moolenaar34114692005-01-02 11:28:13 +0000455
456 if (menu->iconfile != NULL)
457 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100458 // Use the "icon=" argument.
Bram Moolenaar34114692005-01-02 11:28:13 +0000459 gui_find_iconfile(menu->iconfile, buf, "xpm");
460 createXpmImages(buf, NULL, sen);
461
Bram Moolenaar30613902019-12-01 22:11:18 +0100462 // If it failed, try using the menu name.
Bram Moolenaar34114692005-01-02 11:28:13 +0000463 if (*sen == (Pixmap)0 && gui_find_bitmap(menu->name, buf, "xpm") == OK)
464 createXpmImages(buf, NULL, sen);
465 if (*sen != (Pixmap)0)
466 return;
467 }
468
469 if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL)
470 {
471 if (menu->iconidx >= 0 && menu->iconidx
K.Takataeeec2542021-06-02 13:28:16 +0200472 < (int)ARRAY_LENGTH(built_in_pixmaps))
Bram Moolenaar34114692005-01-02 11:28:13 +0000473 xpm = built_in_pixmaps[menu->iconidx];
474 else
475 xpm = tb_blank_xpm;
476 }
477
478 if (xpm != NULL || buf[0] != NUL)
479 createXpmImages(buf, xpm, sen);
480}
481
482/*
483 * Read an Xpm file, doing color substitutions for the foreground and
484 * background colors. If there is an error reading a color xpm file,
485 * drop back and read the monochrome file. If successful, create the
486 * insensitive Pixmap too.
487 */
488 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100489createXpmImages(char_u *path, char **xpm, Pixmap *sen)
Bram Moolenaar34114692005-01-02 11:28:13 +0000490{
491 Window rootWindow;
492 XpmAttributes attrs;
493 XpmColorSymbol color[5] =
494 {
495 {"none", "none", 0},
496 {"iconColor1", NULL, 0},
497 {"bottomShadowColor", NULL, 0},
498 {"topShadowColor", NULL, 0},
499 {"selectColor", NULL, 0}
500 };
501 int screenNum;
502 int status;
503 Pixmap mask;
504 Pixmap map;
505
506 gui_mch_get_toolbar_colors(
507 &color[BACKGROUND].pixel,
508 &color[FOREGROUND].pixel,
509 &color[BOTTOM_SHADOW].pixel,
510 &color[TOP_SHADOW].pixel,
511 &color[HIGHLIGHT].pixel);
512
Bram Moolenaar30613902019-12-01 22:11:18 +0100513 // Setup the color substitution table
Bram Moolenaar34114692005-01-02 11:28:13 +0000514 attrs.valuemask = XpmColorSymbols;
515 attrs.colorsymbols = color;
516 attrs.numsymbols = 5;
517
518 screenNum = DefaultScreen(gui.dpy);
519 rootWindow = RootWindow(gui.dpy, screenNum);
520
Bram Moolenaar30613902019-12-01 22:11:18 +0100521 // Create the "sensitive" pixmap
Bram Moolenaar34114692005-01-02 11:28:13 +0000522 if (xpm != NULL)
523 status = XpmCreatePixmapFromData(gui.dpy, rootWindow, xpm,
524 &map, &mask, &attrs);
525 else
526 status = XpmReadFileToPixmap(gui.dpy, rootWindow, (char *)path,
527 &map, &mask, &attrs);
528 if (status == XpmSuccess && map != 0)
529 {
530 XGCValues gcvalues;
531 GC back_gc;
532 GC mask_gc;
533
Bram Moolenaar30613902019-12-01 22:11:18 +0100534 // Need to create new Pixmaps with the mask applied.
Bram Moolenaar34114692005-01-02 11:28:13 +0000535 gcvalues.foreground = color[BACKGROUND].pixel;
536 back_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
537 mask_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
538 XSetClipMask(gui.dpy, mask_gc, mask);
539
Bram Moolenaar30613902019-12-01 22:11:18 +0100540 // Create the "sensitive" pixmap.
Bram Moolenaar34114692005-01-02 11:28:13 +0000541 *sen = XCreatePixmap(gui.dpy, rootWindow,
542 attrs.width, attrs.height,
543 DefaultDepth(gui.dpy, screenNum));
544 XFillRectangle(gui.dpy, *sen, back_gc, 0, 0,
545 attrs.width, attrs.height);
546 XCopyArea(gui.dpy, map, *sen, mask_gc, 0, 0,
547 attrs.width, attrs.height, 0, 0);
548
549 XFreeGC(gui.dpy, back_gc);
550 XFreeGC(gui.dpy, mask_gc);
551 XFreePixmap(gui.dpy, map);
552 }
553 else
554 *sen = 0;
555
556 XpmFreeAttributes(&attrs);
557}
558
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100560gui_mch_set_toolbar_pos(
561 int x,
562 int y,
563 int w,
564 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565{
566 Dimension border;
567 int height;
568
Bram Moolenaar30613902019-12-01 22:11:18 +0100569 if (!XtIsManaged(toolBar)) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 return;
571 XtUnmanageChild(toolBar);
572 XtVaGetValues(toolBar,
573 XtNborderWidth, &border,
574 NULL);
575 height = h - 2 * border;
576 if (height < 0)
577 height = 1;
578 XtVaSetValues(toolBar,
579 XtNhorizDistance, x,
580 XtNvertDistance, y,
581 XtNwidth, w - 2 * border,
582 XtNheight, height,
583 NULL);
584 XtManageChild(toolBar);
585}
586#endif
587
588 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100589gui_mch_set_text_area_pos(
590 int x,
591 int y,
592 int w,
593 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594{
595 XtUnmanageChild(textArea);
596 XtVaSetValues(textArea,
597 XtNhorizDistance, x,
598 XtNvertDistance, y,
599 XtNwidth, w,
600 XtNheight, h,
601 NULL);
602 XtManageChild(textArea);
603#ifdef FEAT_TOOLBAR
Bram Moolenaar30613902019-12-01 22:11:18 +0100604 // Give keyboard focus to the textArea instead of the toolbar.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 gui_mch_reset_focus();
606#endif
607}
608
609#ifdef FEAT_TOOLBAR
610/*
611 * A toolbar button has been pushed; now reset the input focus
612 * such that the user can type page up/down etc. and have the
613 * input go to the editor window, not the button
614 */
615 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100616gui_mch_reset_focus(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000617{
618 XtSetKeyboardFocus(vimForm, textArea);
619}
620#endif
621
622
623 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100624gui_x11_set_back_color(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625{
626 if (textArea != NULL)
627 XtVaSetValues(textArea,
628 XtNbackground, gui.back_pixel,
629 NULL);
630}
631
632#if defined(FEAT_MENU) || defined(PROTO)
633/*
634 * Menu stuff.
635 */
636
Bram Moolenaard25c16e2016-01-29 22:13:30 +0100637static char_u *make_pull_name(char_u * name);
638static Widget get_popup_entry(Widget w);
639static Widget submenu_widget(Widget);
640static Boolean has_submenu(Widget);
641static void gui_mch_submenu_change(vimmenu_T *mp, int colors);
642static void gui_athena_menu_font(Widget id);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643
644 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100645gui_mch_enable_menu(int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646{
647 if (flag)
648 {
649 XtManageChild(menuBar);
650# ifdef FEAT_TOOLBAR
651 if (XtIsManaged(toolBar))
652 {
653 XtVaSetValues(toolBar,
654 XtNvertDistance, gui.menu_height,
655 NULL);
656 XtVaSetValues(textArea,
657 XtNvertDistance, gui.menu_height + gui.toolbar_height,
658 NULL);
659 }
660# endif
661 }
662 else
663 {
664 XtUnmanageChild(menuBar);
665# ifdef FEAT_TOOLBAR
666 if (XtIsManaged(toolBar))
667 {
668 XtVaSetValues(toolBar,
669 XtNvertDistance, 0,
670 NULL);
671 }
672# endif
673 }
674}
675
676 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100677gui_mch_set_menu_pos(
678 int x,
679 int y,
680 int w,
681 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682{
683 Dimension border;
684 int height;
685
686 XtUnmanageChild(menuBar);
687 XtVaGetValues(menuBar, XtNborderWidth, &border, NULL);
Bram Moolenaar30613902019-12-01 22:11:18 +0100688 // avoid trouble when there are no menu items, and h is 1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689 height = h - 2 * border;
690 if (height < 0)
691 height = 1;
692 XtVaSetValues(menuBar,
693 XtNhorizDistance, x,
694 XtNvertDistance, y,
695 XtNwidth, w - 2 * border,
696 XtNheight, height,
697 NULL);
698 XtManageChild(menuBar);
699}
700
701/*
702 * Used to calculate the insertion position of a widget with respect to its
703 * neighbors.
704 *
705 * Valid range of return values is: 0 (beginning of children) to
706 * numChildren (end of children).
707 */
708 static Cardinal
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100709athena_calculate_ins_pos(Widget widget)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710{
Bram Moolenaar30613902019-12-01 22:11:18 +0100711 // Assume that if the parent of the vimmenu_T is NULL, then we can get
712 // to this menu by traversing "next", starting at "root_menu".
713 //
714 // This holds true for popup menus, toolbar, and toplevel menu items.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715
Bram Moolenaar30613902019-12-01 22:11:18 +0100716 // Popup menus: "id" is NULL. Only submenu_id is valid
Bram Moolenaar071d4272004-06-13 20:20:40 +0000717
Bram Moolenaar30613902019-12-01 22:11:18 +0100718 // Menus that are not toplevel: "parent" will be non-NULL, "id" &
719 // "submenu_id" will be non-NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720
Bram Moolenaar30613902019-12-01 22:11:18 +0100721 // Toplevel menus: "parent" is NULL, id is the widget of the menu item
Bram Moolenaar071d4272004-06-13 20:20:40 +0000722
723 WidgetList children;
724 Cardinal num_children = 0;
725 int retval;
726 Arg args[2];
727 int n = 0;
728 int i;
729
730 XtSetArg(args[n], XtNchildren, &children); n++;
731 XtSetArg(args[n], XtNnumChildren, &num_children); n++;
732 XtGetValues(XtParent(widget), args, n);
733
734 retval = num_children;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000735 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 {
737 Widget current = children[i];
738 vimmenu_T *menu = NULL;
739
740 for (menu = (a_cur_menu->parent == NULL)
741 ? root_menu : a_cur_menu->parent->children;
742 menu != NULL;
743 menu = menu->next)
744 if (current == menu->id
745 && a_cur_menu->priority < menu->priority
746 && i < retval)
747 retval = i;
748 }
749 return retval;
750}
751
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100753gui_mch_add_menu(vimmenu_T *menu, int idx UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754{
755 char_u *pullright_name;
756 Dimension height, space, border;
757 vimmenu_T *parent = menu->parent;
758
759 a_cur_menu = menu;
760 if (parent == NULL)
761 {
762 if (menu_is_popup(menu->dname))
763 {
764 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
765 simpleMenuWidgetClass, vimShell,
766 XtNinsertPosition, athena_calculate_ins_pos,
767 XtNtranslations, popupTrans,
768 NULL);
769 gui_athena_menu_colors(menu->submenu_id);
770 }
771 else if (menu_is_menubar(menu->dname))
772 {
773 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
774 menuButtonWidgetClass, menuBar,
775 XtNmenuName, menu->dname,
776#ifdef FONTSET_ALWAYS
777 XtNinternational, True,
778#endif
779 NULL);
780 if (menu->id == (Widget)0)
781 return;
782 gui_athena_menu_colors(menu->id);
783 gui_athena_menu_font(menu->id);
784
785 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
786 simpleMenuWidgetClass, menu->id,
787 XtNinsertPosition, athena_calculate_ins_pos,
788 XtNtranslations, supermenuTrans,
789 NULL);
790 gui_athena_menu_colors(menu->submenu_id);
791 gui_athena_menu_font(menu->submenu_id);
792
Bram Moolenaar30613902019-12-01 22:11:18 +0100793 // Don't update the menu height when it was set at a fixed value
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 if (!gui.menu_height_fixed)
795 {
796 /*
797 * When we add a top-level item to the menu bar, we can figure
798 * out how high the menu bar should be.
799 */
800 XtVaGetValues(menuBar,
801 XtNvSpace, &space,
802 XtNborderWidth, &border,
803 NULL);
804 XtVaGetValues(menu->id,
805 XtNheight, &height,
806 NULL);
807 gui.menu_height = height + 2 * (space + border);
808 }
809 }
810 }
811 else if (parent->submenu_id != (Widget)0)
812 {
813 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
814 smeBSBObjectClass, parent->submenu_id,
815 XtNlabel, menu->dname,
816#ifdef FONTSET_ALWAYS
817 XtNinternational, True,
818#endif
819 NULL);
820 if (menu->id == (Widget)0)
821 return;
822 if (pullerBitmap == None)
823 pullerBitmap = gui_athena_create_pullright_pixmap(menu->id);
824
825 XtVaSetValues(menu->id, XtNrightBitmap, pullerBitmap,
826 NULL);
Bram Moolenaar30613902019-12-01 22:11:18 +0100827 // If there are other menu items that are not pulldown menus,
828 // we need to adjust the right margins of those, too.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 {
830 WidgetList children;
831 Cardinal num_children;
832 int i;
833
834 XtVaGetValues(parent->submenu_id, XtNchildren, &children,
835 XtNnumChildren, &num_children,
836 NULL);
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000837 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 {
839 XtVaSetValues(children[i],
840 XtNrightMargin, puller_width,
841 NULL);
842 }
843 }
844 gui_athena_menu_colors(menu->id);
845 gui_athena_menu_font(menu->id);
846
847 pullright_name = make_pull_name(menu->dname);
848 menu->submenu_id = XtVaCreatePopupShell((char *)pullright_name,
849 simpleMenuWidgetClass, parent->submenu_id,
850 XtNtranslations, menuTrans,
851 NULL);
852 gui_athena_menu_colors(menu->submenu_id);
853 gui_athena_menu_font(menu->submenu_id);
854 vim_free(pullright_name);
855 XtAddCallback(menu->submenu_id, XtNpopupCallback,
856 gui_athena_popup_callback, (XtPointer)menu);
857
858 if (parent->parent != NULL)
859 XtOverrideTranslations(parent->submenu_id, parentTrans);
860 }
861 a_cur_menu = NULL;
862}
863
Bram Moolenaar30613902019-12-01 22:11:18 +0100864// Used to determine whether a SimpleMenu has pulldown entries.
865//
866// "id" is the parent of the menu items.
867// Ignore widget "ignore" in the pane.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868 static Boolean
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100869gui_athena_menu_has_submenus(Widget id, Widget ignore)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870{
871 WidgetList children;
872 Cardinal num_children;
873 int i;
874
875 XtVaGetValues(id, XtNchildren, &children,
876 XtNnumChildren, &num_children,
877 NULL);
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +0000878 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879 {
880 if (children[i] == ignore)
881 continue;
882 if (has_submenu(children[i]))
883 return True;
884 }
885 return False;
886}
887
888 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100889gui_athena_menu_font(Widget id)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890{
891#ifdef FONTSET_ALWAYS
892 if (gui.menu_fontset != NOFONTSET)
893 {
894 if (XtIsManaged(id))
895 {
896 XtUnmanageChild(id);
897 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
Bram Moolenaar30613902019-12-01 22:11:18 +0100898 // We should force the widget to recalculate its
899 // geometry now.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 XtManageChild(id);
901 }
902 else
903 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
904 if (has_submenu(id))
905 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
906 }
907#else
908 int managed = FALSE;
909
910 if (gui.menu_font != NOFONT)
911 {
912 if (XtIsManaged(id))
913 {
914 XtUnmanageChild(id);
915 managed = TRUE;
916 }
917
918# ifdef FEAT_XFONTSET
919 if (gui.fontset != NOFONTSET)
920 XtVaSetValues(id, XtNfontSet, gui.menu_font, NULL);
921 else
922# endif
923 XtVaSetValues(id, XtNfont, gui.menu_font, NULL);
924 if (has_submenu(id))
925 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
926
Bram Moolenaar30613902019-12-01 22:11:18 +0100927 // Force the widget to recalculate its geometry now.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 if (managed)
929 XtManageChild(id);
930 }
931#endif
932}
933
934
935 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +0100936gui_mch_new_menu_font(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937{
938 Pixmap oldpuller = None;
939
940 if (menuBar == (Widget)0)
941 return;
942
943 if (pullerBitmap != None)
944 {
945 oldpuller = pullerBitmap;
946 pullerBitmap = gui_athena_create_pullright_pixmap(NULL);
947 }
948 gui_mch_submenu_change(root_menu, FALSE);
949
950 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100951 // Iterate through the menubar menu items and get the height of
952 // each one. The menu bar height is set to the maximum of all
953 // the heights.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954 vimmenu_T *mp;
955 int max_height = 9999;
956
Bram Moolenaar00d253e2020-04-06 22:13:01 +0200957 FOR_ALL_MENUS(mp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000958 {
959 if (menu_is_menubar(mp->dname))
960 {
961 Dimension height;
962
963 XtVaGetValues(mp->id,
Bram Moolenaar623fd5e2005-01-25 21:42:15 +0000964 XtNheight, &height,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000965 NULL);
966 if (height < max_height)
967 max_height = height;
968 }
969 }
970 if (max_height != 9999)
971 {
Bram Moolenaar30613902019-12-01 22:11:18 +0100972 // Don't update the menu height when it was set at a fixed value
Bram Moolenaar071d4272004-06-13 20:20:40 +0000973 if (!gui.menu_height_fixed)
974 {
975 Dimension space, border;
976
977 XtVaGetValues(menuBar,
978 XtNvSpace, &space,
979 XtNborderWidth, &border,
980 NULL);
981 gui.menu_height = max_height + 2 * (space + border);
982 }
983 }
984 }
Bram Moolenaar30613902019-12-01 22:11:18 +0100985 // Now, to simulate the window being resized. Only, this
986 // will resize the window to its current state.
987 //
988 // There has to be a better way, but I do not see one at this time.
989 // (David Harrison)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990 {
991 Position w, h;
992
993 XtVaGetValues(vimShell,
994 XtNwidth, &w,
995 XtNheight, &h,
996 NULL);
997 gui_resize_shell(w, h
998#ifdef FEAT_XIM
999 - xim_get_status_area_height()
1000#endif
1001 );
1002 }
Bram Moolenaar2e2a2812006-03-27 20:55:21 +00001003 gui_set_shellsize(FALSE, TRUE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001004 ui_new_shellsize();
1005 if (oldpuller != None)
1006 XFreePixmap(gui.dpy, oldpuller);
1007}
1008
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001009#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001011gui_mch_new_tooltip_font(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012{
1013# ifdef FEAT_TOOLBAR
1014 vimmenu_T *menu;
1015
1016 if (toolBar == (Widget)0)
1017 return;
1018
1019 menu = gui_find_menu((char_u *)"ToolBar");
1020 if (menu != NULL)
1021 gui_mch_submenu_change(menu, FALSE);
1022# endif
1023}
1024
1025 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001026gui_mch_new_tooltip_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001027{
1028# ifdef FEAT_TOOLBAR
1029 vimmenu_T *menu;
1030
1031 if (toolBar == (Widget)0)
1032 return;
1033
1034 menu = gui_find_menu((char_u *)"ToolBar");
1035 if (menu != NULL)
1036 gui_mch_submenu_change(menu, TRUE);
1037# endif
1038}
1039#endif
1040
1041 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001042gui_mch_submenu_change(
1043 vimmenu_T *menu,
Bram Moolenaar30613902019-12-01 22:11:18 +01001044 int colors) // TRUE for colors, FALSE for font
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045{
1046 vimmenu_T *mp;
1047
1048 for (mp = menu; mp != NULL; mp = mp->next)
1049 {
1050 if (mp->id != (Widget)0)
1051 {
1052 if (colors)
1053 {
1054 gui_athena_menu_colors(mp->id);
1055#ifdef FEAT_TOOLBAR
Bram Moolenaar30613902019-12-01 22:11:18 +01001056 // For a toolbar item: Free the pixmap and allocate a new one,
1057 // so that the background color is right.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 if (mp->image != (Pixmap)0)
1059 {
1060 XFreePixmap(gui.dpy, mp->image);
Bram Moolenaar34114692005-01-02 11:28:13 +00001061 get_toolbar_pixmap(mp, &mp->image);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 if (mp->image != (Pixmap)0)
1063 XtVaSetValues(mp->id, XtNbitmap, mp->image, NULL);
1064 }
1065
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001066# ifdef FEAT_BEVAL_GUI
Bram Moolenaar30613902019-12-01 22:11:18 +01001067 // If we have a tooltip, then we need to change its colors
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068 if (mp->tip != NULL)
1069 {
1070 Arg args[2];
1071
1072 args[0].name = XtNbackground;
1073 args[0].value = gui.tooltip_bg_pixel;
1074 args[1].name = XtNforeground;
1075 args[1].value = gui.tooltip_fg_pixel;
1076 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1077 }
1078# endif
1079#endif
1080 }
1081 else
1082 {
1083 gui_athena_menu_font(mp->id);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001084#ifdef FEAT_BEVAL_GUI
Bram Moolenaar30613902019-12-01 22:11:18 +01001085 // If we have a tooltip, then we need to change its font
1086 // Assume XtNinternational == True (in createBalloonEvalWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001087 if (mp->tip != NULL)
1088 {
1089 Arg args[1];
1090
1091 args[0].name = XtNfontSet;
1092 args[0].value = (XtArgVal)gui.tooltip_fontset;
1093 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
1094 }
1095#endif
1096 }
1097 }
1098
1099 if (mp->children != NULL)
1100 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001101 // Set the colors/font for the tear off widget
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102 if (mp->submenu_id != (Widget)0)
1103 {
1104 if (colors)
1105 gui_athena_menu_colors(mp->submenu_id);
1106 else
1107 gui_athena_menu_font(mp->submenu_id);
1108 }
Bram Moolenaar30613902019-12-01 22:11:18 +01001109 // Set the colors for the children
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 gui_mch_submenu_change(mp->children, colors);
1111 }
1112 }
1113}
1114
1115/*
1116 * Make a submenu name into a pullright name.
1117 * Replace '.' by '_', can't include '.' in the submenu name.
1118 */
1119 static char_u *
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001120make_pull_name(char_u * name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121{
1122 char_u *pname;
1123 char_u *p;
1124
1125 pname = vim_strnsave(name, STRLEN(name) + strlen("-pullright"));
1126 if (pname != NULL)
1127 {
1128 strcat((char *)pname, "-pullright");
1129 while ((p = vim_strchr(pname, '.')) != NULL)
1130 *p = '_';
1131 }
1132 return pname;
1133}
1134
Bram Moolenaar071d4272004-06-13 20:20:40 +00001135 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001136gui_mch_add_menu_item(vimmenu_T *menu, int idx UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137{
1138 vimmenu_T *parent = menu->parent;
1139
1140 a_cur_menu = menu;
1141# ifdef FEAT_TOOLBAR
1142 if (menu_is_toolbar(parent->name))
1143 {
1144 WidgetClass type;
1145 int n;
1146 Arg args[21];
1147
1148 n = 0;
1149 if (menu_is_separator(menu->name))
1150 {
1151 XtSetArg(args[n], XtNlabel, ""); n++;
1152 XtSetArg(args[n], XtNborderWidth, 0); n++;
1153 }
1154 else
1155 {
Bram Moolenaar34114692005-01-02 11:28:13 +00001156 get_toolbar_pixmap(menu, &menu->image);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 XtSetArg(args[n], XtNlabel, menu->dname); n++;
1158 XtSetArg(args[n], XtNinternalHeight, 1); n++;
1159 XtSetArg(args[n], XtNinternalWidth, 1); n++;
1160 XtSetArg(args[n], XtNborderWidth, 1); n++;
1161 if (menu->image != 0)
Dominique Pellea33737b2022-01-06 12:35:31 +00001162 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 XtSetArg(args[n], XtNbitmap, menu->image); n++;
Dominique Pellea33737b2022-01-06 12:35:31 +00001164 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 }
1166 XtSetArg(args[n], XtNhighlightThickness, 0); n++;
1167 type = commandWidgetClass;
Bram Moolenaar30613902019-12-01 22:11:18 +01001168 // TODO: figure out the position in the toolbar?
1169 // This currently works fine for the default toolbar, but
1170 // what if we add/remove items during later runtime?
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171
Bram Moolenaar30613902019-12-01 22:11:18 +01001172 // NOTE: "idx" isn't used here. The position is calculated by
1173 // athena_calculate_ins_pos(). The position it calculates
1174 // should be equal to "idx".
1175 // TODO: Could we just store "idx" and use that as the child
1176 // placement?
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177
1178 if (menu->id == NULL)
1179 {
1180 menu->id = XtCreateManagedWidget((char *)menu->dname,
1181 type, toolBar, args, n);
1182 XtAddCallback(menu->id,
1183 XtNcallback, gui_x11_menu_cb, menu);
1184 }
1185 else
1186 XtSetValues(menu->id, args, n);
1187 gui_athena_menu_colors(menu->id);
1188
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001189#ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190 gui_mch_menu_set_tip(menu);
1191#endif
1192
1193 menu->parent = parent;
1194 menu->submenu_id = NULL;
1195 if (!XtIsManaged(toolBar)
1196 && vim_strchr(p_go, GO_TOOLBAR) != NULL)
1197 gui_mch_show_toolbar(TRUE);
1198 gui.toolbar_height = gui_mch_compute_toolbar_height();
1199 return;
Bram Moolenaar30613902019-12-01 22:11:18 +01001200 } // toolbar menu item
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201# endif
1202
Bram Moolenaar30613902019-12-01 22:11:18 +01001203 // Add menu separator
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 if (menu_is_separator(menu->name))
1205 {
1206 menu->submenu_id = (Widget)0;
1207 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
1208 smeLineObjectClass, parent->submenu_id,
1209 NULL);
1210 if (menu->id == (Widget)0)
1211 return;
1212 gui_athena_menu_colors(menu->id);
1213 }
1214 else
1215 {
1216 if (parent != NULL && parent->submenu_id != (Widget)0)
1217 {
1218 menu->submenu_id = (Widget)0;
1219 menu->id = XtVaCreateManagedWidget((char *)menu->dname,
1220 smeBSBObjectClass, parent->submenu_id,
1221 XtNlabel, menu->dname,
1222#ifdef FONTSET_ALWAYS
1223 XtNinternational, True,
1224#endif
1225 NULL);
1226 if (menu->id == (Widget)0)
1227 return;
1228
Bram Moolenaar30613902019-12-01 22:11:18 +01001229 // If there are other "pulldown" items in this pane, then adjust
1230 // the right margin to accommodate the arrow pixmap, otherwise
1231 // the right margin will be the same as the left margin.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001232 {
1233 Dimension left_margin;
1234
1235 XtVaGetValues(menu->id, XtNleftMargin, &left_margin, NULL);
1236 XtVaSetValues(menu->id, XtNrightMargin,
1237 gui_athena_menu_has_submenus(parent->submenu_id, NULL) ?
1238 puller_width :
1239 left_margin,
1240 NULL);
1241 }
1242
1243 gui_athena_menu_colors(menu->id);
1244 gui_athena_menu_font(menu->id);
1245 XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
1246 (XtPointer)menu);
1247 }
1248 }
1249 a_cur_menu = NULL;
1250}
1251
1252#if defined(FEAT_TOOLBAR) || defined(PROTO)
1253 void
1254gui_mch_show_toolbar(int showit)
1255{
Bram Moolenaar30613902019-12-01 22:11:18 +01001256 Cardinal numChildren; // how many children toolBar has
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257
1258 if (toolBar == (Widget)0)
1259 return;
1260 XtVaGetValues(toolBar, XtNnumChildren, &numChildren, NULL);
1261 if (showit && numChildren > 0)
1262 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001263 // Assume that we want to show the toolbar if p_toolbar contains valid
1264 // option settings, therefore p_toolbar must not be NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 WidgetList children;
1266
1267 XtVaGetValues(toolBar, XtNchildren, &children, NULL);
1268 {
1269 void (*action)(BalloonEval *);
1270 int text = 0;
1271
1272 if (strstr((const char *)p_toolbar, "tooltips"))
1273 action = &gui_mch_enable_beval_area;
1274 else
1275 action = &gui_mch_disable_beval_area;
1276 if (strstr((const char *)p_toolbar, "text"))
1277 text = 1;
1278 else if (strstr((const char *)p_toolbar, "icons"))
1279 text = -1;
1280 if (text != 0)
1281 {
1282 vimmenu_T *toolbar;
1283 vimmenu_T *cur;
1284
Bram Moolenaar00d253e2020-04-06 22:13:01 +02001285 FOR_ALL_MENUS(toolbar)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286 if (menu_is_toolbar(toolbar->dname))
1287 break;
Bram Moolenaar30613902019-12-01 22:11:18 +01001288 // Assumption: toolbar is NULL if there is no toolbar,
1289 // otherwise it contains the toolbar menu structure.
1290 //
1291 // Assumption: "numChildren" == the number of items in the list
1292 // of items beginning with toolbar->children.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 if (toolbar)
1294 {
1295 for (cur = toolbar->children; cur; cur = cur->next)
1296 {
1297 Arg args[2];
1298 int n = 0;
1299
Bram Moolenaar30613902019-12-01 22:11:18 +01001300 // Enable/Disable tooltip (OK to enable while currently
1301 // enabled)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302 if (cur->tip != NULL)
1303 (*action)(cur->tip);
1304 if (text == 1)
1305 {
1306 XtSetArg(args[n], XtNbitmap, None);
1307 n++;
1308 XtSetArg(args[n], XtNlabel,
1309 menu_is_separator(cur->name) ? "" :
1310 (char *)cur->dname);
1311 n++;
1312 }
1313 else
1314 {
1315 XtSetArg(args[n], XtNbitmap, cur->image);
1316 n++;
1317 XtSetArg(args[n], XtNlabel, (cur->image == None) ?
1318 menu_is_separator(cur->name) ?
1319 "" :
1320 (char *)cur->dname
1321 :
1322 (char *)None);
1323 n++;
1324 }
1325 if (cur->id != NULL)
1326 {
1327 XtUnmanageChild(cur->id);
1328 XtSetValues(cur->id, args, n);
1329 XtManageChild(cur->id);
1330 }
1331 }
1332 }
1333 }
1334 }
1335 gui.toolbar_height = gui_mch_compute_toolbar_height();
1336 XtManageChild(toolBar);
1337 if (XtIsManaged(menuBar))
1338 {
1339 XtVaSetValues(textArea,
1340 XtNvertDistance, gui.toolbar_height + gui.menu_height,
1341 NULL);
1342 XtVaSetValues(toolBar,
1343 XtNvertDistance, gui.menu_height,
1344 NULL);
1345 }
1346 else
1347 {
1348 XtVaSetValues(textArea,
1349 XtNvertDistance, gui.toolbar_height,
1350 NULL);
1351 XtVaSetValues(toolBar,
1352 XtNvertDistance, 0,
1353 NULL);
1354 }
1355 }
1356 else
1357 {
1358 gui.toolbar_height = 0;
1359 if (XtIsManaged(menuBar))
1360 XtVaSetValues(textArea,
1361 XtNvertDistance, gui.menu_height,
1362 NULL);
1363 else
1364 XtVaSetValues(textArea,
1365 XtNvertDistance, 0,
1366 NULL);
1367
1368 XtUnmanageChild(toolBar);
1369 }
Bram Moolenaar2e2a2812006-03-27 20:55:21 +00001370 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001371}
1372
1373
1374 int
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001375gui_mch_compute_toolbar_height(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001376{
Bram Moolenaar30613902019-12-01 22:11:18 +01001377 Dimension height; // total Toolbar height
1378 Dimension whgt; // height of each widget
1379 Dimension marginHeight; // XmNmarginHeight of toolBar
1380 Dimension shadowThickness; // thickness of Xtparent(toolBar)
1381 WidgetList children; // list of toolBar's children
1382 Cardinal numChildren; // how many children toolBar has
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383 int i;
1384
1385 height = 0;
1386 shadowThickness = 0;
1387 marginHeight = 0;
1388 if (toolBar != (Widget)0)
1389 {
1390 XtVaGetValues(toolBar,
1391 XtNborderWidth, &shadowThickness,
1392 XtNvSpace, &marginHeight,
1393 XtNchildren, &children,
1394 XtNnumChildren, &numChildren,
1395 NULL);
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00001396 for (i = 0; i < (int)numChildren; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397 {
1398 whgt = 0;
1399
1400 XtVaGetValues(children[i], XtNheight, &whgt, NULL);
1401 if (height < whgt)
1402 height = whgt;
1403 }
1404 }
1405
1406 return (int)(height + (marginHeight << 1) + (shadowThickness << 1));
1407}
1408
1409 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001410gui_mch_get_toolbar_colors(
1411 Pixel *bgp,
1412 Pixel *fgp,
1413 Pixel *bsp,
1414 Pixel *tsp,
1415 Pixel *hsp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416{
1417 XtVaGetValues(toolBar, XtNbackground, bgp, XtNborderColor, fgp, NULL);
1418 *bsp = *bgp;
1419 *tsp = *fgp;
1420 *hsp = *tsp;
1421}
1422#endif
1423
1424
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001426gui_mch_toggle_tearoffs(int enable UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427{
Bram Moolenaar30613902019-12-01 22:11:18 +01001428 // no tearoff menus
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429}
1430
1431 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001432gui_mch_new_menu_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001433{
1434 if (menuBar == (Widget)0)
1435 return;
1436 if (gui.menu_fg_pixel != INVALCOLOR)
1437 XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
1438 gui_athena_menu_colors(menuBar);
1439#ifdef FEAT_TOOLBAR
1440 gui_athena_menu_colors(toolBar);
1441#endif
1442
1443 gui_mch_submenu_change(root_menu, TRUE);
1444}
1445
1446/*
1447 * Destroy the machine specific menu widget.
1448 */
1449 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001450gui_mch_destroy_menu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001451{
1452 Widget parent;
1453
Bram Moolenaar30613902019-12-01 22:11:18 +01001454 // There is no item for the toolbar.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455 if (menu->id == (Widget)0)
1456 return;
1457
1458 parent = XtParent(menu->id);
1459
Bram Moolenaar30613902019-12-01 22:11:18 +01001460 // When removing the last "pulldown" menu item from a pane, adjust the
1461 // right margins of the remaining widgets.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462 if (menu->submenu_id != (Widget)0)
1463 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001464 // Go through the menu items in the parent of this item and
1465 // adjust their margins, if necessary.
1466 // This takes care of the case when we delete the last menu item in a
1467 // pane that has a submenu. In this case, there will be no arrow
1468 // pixmaps shown anymore.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469 {
1470 WidgetList children;
1471 Cardinal num_children;
1472 int i;
1473 Dimension right_margin = 0;
1474 Boolean get_left_margin = False;
1475
1476 XtVaGetValues(parent, XtNchildren, &children,
1477 XtNnumChildren, &num_children,
1478 NULL);
1479 if (gui_athena_menu_has_submenus(parent, menu->id))
1480 right_margin = puller_width;
1481 else
1482 get_left_margin = True;
1483
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00001484 for (i = 0; i < (int)num_children; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485 {
1486 if (children[i] == menu->id)
1487 continue;
1488 if (get_left_margin == True)
1489 {
1490 Dimension left_margin;
1491
1492 XtVaGetValues(children[i], XtNleftMargin, &left_margin,
1493 NULL);
1494 XtVaSetValues(children[i], XtNrightMargin, left_margin,
1495 NULL);
1496 }
1497 else
1498 XtVaSetValues(children[i], XtNrightMargin, right_margin,
1499 NULL);
1500 }
1501 }
1502 }
Bram Moolenaar30613902019-12-01 22:11:18 +01001503 // Please be sure to destroy the parent widget first (i.e. menu->id).
1504 //
1505 // This code should be basically identical to that in the file gui_motif.c
1506 // because they are both Xt based.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507 if (menu->id != (Widget)0)
1508 {
1509 Cardinal num_children;
1510 Dimension height, space, border;
1511
1512 XtVaGetValues(menuBar,
1513 XtNvSpace, &space,
1514 XtNborderWidth, &border,
1515 NULL);
1516 XtVaGetValues(menu->id,
1517 XtNheight, &height,
1518 NULL);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001519#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL_GUI)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520 if (parent == toolBar && menu->tip != NULL)
1521 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001522 // We try to destroy this before the actual menu, because there are
1523 // callbacks, etc. that will be unregistered during the tooltip
1524 // destruction.
1525 //
1526 // If you call "gui_mch_destroy_beval_area()" after destroying
1527 // menu->id, then the tooltip's window will have already been
1528 // deallocated by Xt, and unknown behaviour will ensue (probably
1529 // a core dump).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530 gui_mch_destroy_beval_area(menu->tip);
1531 menu->tip = NULL;
1532 }
1533#endif
1534 /*
1535 * This is a hack to stop the Athena simpleMenuWidget from getting a
1536 * BadValue error when a menu's last child is destroyed. We check to
1537 * see if this is the last child and if so, don't delete it. The parent
Bram Moolenaarc4568ab2018-11-16 16:21:05 +01001538 * will be deleted soon anyway, and it will delete its children like
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539 * all good widgets do.
1540 */
Bram Moolenaar30613902019-12-01 22:11:18 +01001541 // NOTE: The cause of the BadValue X Protocol Error is because when the
1542 // last child is destroyed, it is first unmanaged, thus causing a
1543 // geometry resize request from the parent Shell widget.
1544 // Since the Shell widget has no more children, it is resized to have
1545 // width/height of 0. XConfigureWindow() is then called with the
1546 // width/height of 0, which generates the BadValue.
1547 //
1548 // This happens in phase two of the widget destruction process.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549 {
1550 if (parent != menuBar
1551#ifdef FEAT_TOOLBAR
1552 && parent != toolBar
1553#endif
1554 )
1555 {
1556 XtVaGetValues(parent, XtNnumChildren, &num_children, NULL);
1557 if (num_children > 1)
1558 XtDestroyWidget(menu->id);
1559 }
1560 else
1561 XtDestroyWidget(menu->id);
1562 menu->id = (Widget)0;
1563 }
1564
1565 if (parent == menuBar)
1566 {
1567 if (!gui.menu_height_fixed)
1568 gui.menu_height = height + 2 * (space + border);
1569 }
1570#ifdef FEAT_TOOLBAR
1571 else if (parent == toolBar)
1572 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001573 // When removing last toolbar item, don't display the toolbar.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574 XtVaGetValues(toolBar, XtNnumChildren, &num_children, NULL);
1575 if (num_children == 0)
1576 gui_mch_show_toolbar(FALSE);
1577 else
1578 gui.toolbar_height = gui_mch_compute_toolbar_height();
1579 }
1580#endif
1581 }
1582 if (menu->submenu_id != (Widget)0)
1583 {
1584 XtDestroyWidget(menu->submenu_id);
1585 menu->submenu_id = (Widget)0;
1586 }
1587}
1588
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001590gui_athena_menu_timeout(
1591 XtPointer client_data,
1592 XtIntervalId *id UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593{
1594 Widget w = (Widget)client_data;
1595 Widget popup;
1596
1597 timer = 0;
1598 if (XtIsSubclass(w,smeBSBObjectClass))
1599 {
1600 Pixmap p;
1601
1602 XtVaGetValues(w, XtNrightBitmap, &p, NULL);
1603 if ((p != None) && (p != XtUnspecifiedPixmap))
1604 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001605 // We are dealing with an item that has a submenu
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 popup = get_popup_entry(XtParent(w));
1607 if (popup == (Widget)0)
1608 return;
1609 XtPopup(popup, XtGrabNonexclusive);
1610 }
1611 }
1612}
1613
Bram Moolenaar30613902019-12-01 22:11:18 +01001614/*
1615 * This routine is used to calculate the position (in screen coordinates)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 * where a submenu should appear relative to the menu entry that popped it
1617 * up. It should appear even with and just slightly to the left of the
1618 * rightmost end of the menu entry that caused the popup.
1619 *
1620 * This is called when XtPopup() is called.
1621 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001622 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001623gui_athena_popup_callback(
1624 Widget w,
1625 XtPointer client_data,
1626 XtPointer call_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627{
Bram Moolenaar30613902019-12-01 22:11:18 +01001628 // Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629 vimmenu_T *menu = (vimmenu_T *)client_data;
1630 Dimension width;
1631 Position root_x, root_y;
1632
Bram Moolenaar30613902019-12-01 22:11:18 +01001633 // First, popdown any siblings that may have menus popped up
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634 {
1635 vimmenu_T *i;
1636
Bram Moolenaar00d253e2020-04-06 22:13:01 +02001637 FOR_ALL_CHILD_MENUS(menu->parent, i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638 {
1639 if (i->submenu_id != NULL && XtIsManaged(i->submenu_id))
1640 XtPopdown(i->submenu_id);
1641 }
1642 }
1643 XtVaGetValues(XtParent(w),
1644 XtNwidth, &width,
1645 NULL);
Bram Moolenaar30613902019-12-01 22:11:18 +01001646 // Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id
1647 // i.e. This IS the active entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 XtTranslateCoords(menu->id,width - 5, 0, &root_x, &root_y);
1649 XtVaSetValues(w, XtNx, root_x,
1650 XtNy, root_y,
1651 NULL);
1652}
1653
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001655gui_athena_popdown_submenus_action(
1656 Widget w,
1657 XEvent *event,
1658 String *args,
1659 Cardinal *nargs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660{
1661 WidgetList children;
1662 Cardinal num_children;
1663
1664 XtVaGetValues(w, XtNchildren, &children,
1665 XtNnumChildren, &num_children,
1666 NULL);
1667 for (; num_children > 0; --num_children)
1668 {
1669 Widget child = children[num_children - 1];
1670
1671 if (has_submenu(child))
1672 {
1673 Widget temp_w;
1674
1675 temp_w = submenu_widget(child);
1676 gui_athena_popdown_submenus_action(temp_w,event,args,nargs);
1677 XtPopdown(temp_w);
1678 }
1679 }
1680}
1681
Bram Moolenaar30613902019-12-01 22:11:18 +01001682/*
1683 * Used to determine if the given widget has a submenu that can be popped up.
1684 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685 static Boolean
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001686has_submenu(Widget widget)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687{
1688 if ((widget != NULL) && XtIsSubclass(widget,smeBSBObjectClass))
1689 {
1690 Pixmap p;
1691
1692 XtVaGetValues(widget, XtNrightBitmap, &p, NULL);
1693 if ((p != None) && (p != XtUnspecifiedPixmap))
1694 return True;
1695 }
1696 return False;
1697}
1698
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699 static void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001700gui_athena_delayed_arm_action(
1701 Widget w,
1702 XEvent *event,
1703 String *args,
1704 Cardinal *nargs)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705{
1706 Dimension width, height;
1707
1708 if (event->type != MotionNotify)
1709 return;
1710
1711 XtVaGetValues(w,
1712 XtNwidth, &width,
1713 XtNheight, &height,
1714 NULL);
1715
1716 if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height)
1717 return;
1718
1719 {
1720 static Widget previous_active_widget = NULL;
1721 Widget current;
1722
1723 current = XawSimpleMenuGetActiveEntry(w);
1724 if (current != previous_active_widget)
1725 {
1726 if (timer)
1727 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001728 // If the timeout hasn't been triggered, remove it
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 XtRemoveTimeOut(timer);
1730 }
1731 gui_athena_popdown_submenus_action(w,event,args,nargs);
1732 if (has_submenu(current))
1733 {
1734 XtAppAddTimeOut(XtWidgetToApplicationContext(w), 600L,
1735 gui_athena_menu_timeout,
1736 (XtPointer)current);
1737 }
1738 previous_active_widget = current;
1739 }
1740 }
1741}
1742
1743 static Widget
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001744get_popup_entry(Widget w)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745{
1746 Widget menuw;
1747
Bram Moolenaar30613902019-12-01 22:11:18 +01001748 // Get the active entry for the current menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749 if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)0)
1750 return NULL;
1751
1752 return submenu_widget(menuw);
1753}
1754
Bram Moolenaar30613902019-12-01 22:11:18 +01001755/*
1756 * Given the widget that has been determined to have a submenu, return the
1757 * submenu widget that is to be popped up.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758 */
1759 static Widget
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001760submenu_widget(Widget widget)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761{
Bram Moolenaar30613902019-12-01 22:11:18 +01001762 // Precondition: has_submenu(widget) == True
1763 // XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764
1765 char_u *pullright_name;
1766 Widget popup;
1767
1768 pullright_name = make_pull_name((char_u *)XtName(widget));
1769 popup = XtNameToWidget(XtParent(widget), (char *)pullright_name);
1770 vim_free(pullright_name);
1771
1772 return popup;
Bram Moolenaar30613902019-12-01 22:11:18 +01001773 // Postcondition: (popup != NULL) implies
1774 // (XtIsSubclass(popup,simpleMenuWidgetClass) == True)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775}
1776
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001778gui_mch_show_popupmenu(vimmenu_T *menu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779{
1780 int rootx, rooty, winx, winy;
1781 Window root, child;
1782 unsigned int mask;
1783
1784 if (menu->submenu_id == (Widget)0)
1785 return;
1786
Bram Moolenaar30613902019-12-01 22:11:18 +01001787 // Position the popup menu at the pointer
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788 if (XQueryPointer(gui.dpy, XtWindow(vimShell), &root, &child,
1789 &rootx, &rooty, &winx, &winy, &mask))
1790 {
1791 rootx -= 30;
1792 if (rootx < 0)
1793 rootx = 0;
1794 rooty -= 5;
1795 if (rooty < 0)
1796 rooty = 0;
1797 XtVaSetValues(menu->submenu_id,
1798 XtNx, rootx,
1799 XtNy, rooty,
1800 NULL);
1801 }
1802
1803 XtOverrideTranslations(menu->submenu_id, popupTrans);
1804 XtPopupSpringLoaded(menu->submenu_id);
1805}
1806
Bram Moolenaar30613902019-12-01 22:11:18 +01001807#endif // FEAT_MENU
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808
1809/*
1810 * Set the menu and scrollbar colors to their default values.
1811 */
1812 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001813gui_mch_def_colors(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814{
1815 /*
1816 * Get the colors ourselves. Using the automatic conversion doesn't
1817 * handle looking for approximate colors.
1818 */
1819 if (gui.in_use)
1820 {
1821 gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
1822 gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
1823 gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
1824 gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01001825#ifdef FEAT_BEVAL_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
1827 gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
1828#endif
1829 }
1830}
1831
1832
1833/*
1834 * Scrollbar stuff.
1835 */
1836
1837 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001838gui_mch_set_scrollbar_thumb(
1839 scrollbar_T *sb,
1840 long val,
1841 long size,
1842 long max)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843{
1844 double v, s;
1845
1846 if (sb->id == (Widget)0)
1847 return;
1848
1849 /*
1850 * Athena scrollbar must go from 0.0 to 1.0.
1851 */
1852 if (max == 0)
1853 {
Bram Moolenaar30613902019-12-01 22:11:18 +01001854 // So you can't scroll it at all (normally it scrolls past end)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001855#ifdef FEAT_GUI_NEXTAW
1856 XawScrollbarSetThumb(sb->id, 0.0, 1.0);
1857#else
1858 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
1859#endif
1860 }
1861 else
1862 {
1863 v = (double)val / (double)(max + 1);
1864 s = (double)size / (double)(max + 1);
1865#ifdef FEAT_GUI_NEXTAW
1866 XawScrollbarSetThumb(sb->id, v, s);
1867#else
1868 vim_XawScrollbarSetThumb(sb->id, v, s, 1.0);
1869#endif
1870 }
1871}
1872
1873 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001874gui_mch_set_scrollbar_pos(
1875 scrollbar_T *sb,
1876 int x,
1877 int y,
1878 int w,
1879 int h)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880{
1881 if (sb->id == (Widget)0)
1882 return;
1883
1884 XtUnmanageChild(sb->id);
1885 XtVaSetValues(sb->id,
1886 XtNhorizDistance, x,
1887 XtNvertDistance, y,
1888 XtNwidth, w,
1889 XtNheight, h,
1890 NULL);
1891 XtManageChild(sb->id);
1892}
1893
Bram Moolenaar203ec772020-07-17 20:43:43 +02001894 int
1895gui_mch_get_scrollbar_xpadding(void)
1896{
qsmodo28f1a512022-02-07 15:57:50 +00001897 int xpad;
1898 Dimension tw, ww;
1899 Position tx;
1900
1901 XtVaGetValues(textArea, XtNwidth, &tw, XtNx, &tx, NULL);
1902 XtVaGetValues(vimShell, XtNwidth, &ww, NULL);
1903 xpad = ww - tw - tx - gui.scrollbar_width;
1904 return (xpad < 0) ? 0 : xpad;
Bram Moolenaar203ec772020-07-17 20:43:43 +02001905}
1906
1907 int
1908gui_mch_get_scrollbar_ypadding(void)
1909{
qsmodo28f1a512022-02-07 15:57:50 +00001910 int ypad;
1911 Dimension th, wh;
1912 Position ty;
1913
1914 XtVaGetValues(textArea, XtNheight, &th, XtNy, &ty, NULL);
1915 XtVaGetValues(vimShell, XtNheight, &wh, NULL);
1916 ypad = wh - th - ty - gui.scrollbar_height;
1917 return (ypad < 0) ? 0 : ypad;
Bram Moolenaar203ec772020-07-17 20:43:43 +02001918}
1919
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001921gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922{
1923 if (sb->id != (Widget)0)
1924 {
1925 if (flag)
1926 XtManageChild(sb->id);
1927 else
1928 XtUnmanageChild(sb->id);
1929 }
1930}
1931
1932 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001933gui_mch_create_scrollbar(
1934 scrollbar_T *sb,
Bram Moolenaar30613902019-12-01 22:11:18 +01001935 int orient) // SBAR_VERT or SBAR_HORIZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936{
1937 sb->id = XtVaCreateWidget("scrollBar",
1938#ifdef FEAT_GUI_NEXTAW
1939 scrollbarWidgetClass, vimForm,
1940#else
1941 vim_scrollbarWidgetClass, vimForm,
1942#endif
1943 XtNresizable, True,
1944 XtNtop, XtChainTop,
1945 XtNbottom, XtChainTop,
1946 XtNleft, XtChainLeft,
1947 XtNright, XtChainLeft,
1948 XtNborderWidth, 0,
1949 XtNorientation, (orient == SBAR_VERT) ? XtorientVertical
1950 : XtorientHorizontal,
1951 XtNforeground, gui.scroll_fg_pixel,
1952 XtNbackground, gui.scroll_bg_pixel,
1953 NULL);
1954 if (sb->id == (Widget)0)
1955 return;
1956
1957 XtAddCallback(sb->id, XtNjumpProc,
1958 gui_athena_scroll_cb_jump, (XtPointer)sb->ident);
1959 XtAddCallback(sb->id, XtNscrollProc,
1960 gui_athena_scroll_cb_scroll, (XtPointer)sb->ident);
1961
1962#ifdef FEAT_GUI_NEXTAW
1963 XawScrollbarSetThumb(sb->id, 0.0, 1.0);
1964#else
1965 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
1966#endif
1967}
1968
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001970gui_mch_destroy_scrollbar(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971{
1972 if (sb->id != (Widget)0)
1973 XtDestroyWidget(sb->id);
1974}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001975
1976 void
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001977gui_mch_set_scrollbar_colors(scrollbar_T *sb)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978{
1979 if (sb->id != (Widget)0)
1980 XtVaSetValues(sb->id,
1981 XtNforeground, gui.scroll_fg_pixel,
1982 XtNbackground, gui.scroll_bg_pixel,
1983 NULL);
1984
Bram Moolenaar30613902019-12-01 22:11:18 +01001985 // This is needed for the rectangle below the vertical scrollbars.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 if (sb == &gui.bottom_sbar && vimForm != (Widget)0)
1987 gui_athena_scroll_colors(vimForm);
1988}
1989
1990/*
1991 * Miscellaneous stuff:
1992 */
1993 Window
Bram Moolenaar66f948e2016-01-30 16:39:25 +01001994gui_x11_get_wid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995{
1996 return XtWindow(textArea);
1997}
1998
1999#if defined(FEAT_BROWSE) || defined(PROTO)
2000/*
2001 * Put up a file requester.
2002 * Returns the selected name in allocated memory, or NULL for Cancel.
2003 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004 char_u *
Bram Moolenaar66f948e2016-01-30 16:39:25 +01002005gui_mch_browse(
Bram Moolenaar30613902019-12-01 22:11:18 +01002006 int saving UNUSED, // select file to write
2007 char_u *title, // title for the window
2008 char_u *dflt, // default name
2009 char_u *ext UNUSED, // extension added
2010 char_u *initdir, // initial directory, NULL for current dir
2011 char_u *filter UNUSED) // file name filter
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012{
2013 Position x, y;
2014 char_u dirbuf[MAXPATHL];
2015
Bram Moolenaar30613902019-12-01 22:11:18 +01002016 // Concatenate "initdir" and "dflt".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002017 if (initdir == NULL || *initdir == NUL)
2018 mch_dirname(dirbuf, MAXPATHL);
2019 else if (STRLEN(initdir) + 2 < MAXPATHL)
2020 STRCPY(dirbuf, initdir);
2021 else
2022 dirbuf[0] = NUL;
2023 if (dflt != NULL && *dflt != NUL
2024 && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL)
2025 {
2026 add_pathsep(dirbuf);
2027 STRCAT(dirbuf, dflt);
2028 }
2029
Bram Moolenaar30613902019-12-01 22:11:18 +01002030 // Position the file selector just below the menubar
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 XtTranslateCoords(vimShell, (Position)0, (Position)
2032#ifdef FEAT_MENU
2033 gui.menu_height
2034#else
2035 0
2036#endif
2037 , &x, &y);
2038 return (char_u *)vim_SelFile(vimShell, (char *)title, (char *)dirbuf,
2039 NULL, (int)x, (int)y, gui.menu_fg_pixel, gui.menu_bg_pixel,
2040 gui.scroll_fg_pixel, gui.scroll_bg_pixel);
2041}
2042#endif
2043
2044#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2045
2046static int dialogStatus;
2047static Atom dialogatom;
2048
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049/*
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
Bram Moolenaar30613902019-12-01 22:11:18 +01002125 // if our pointer is currently hidden, then we should show it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126 gui_mch_mousehide(FALSE);
2127
Bram Moolenaar30613902019-12-01 22:11:18 +01002128 // Check 'v' flag in 'guioptions': vertical button placement.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
2130
Bram Moolenaar30613902019-12-01 22:11:18 +01002131 // The shell is created each time, to make sure it is resized properly
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 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
Bram Moolenaar30613902019-12-01 22:11:18 +01002184 // make a copy, so that we can insert NULs
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185 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
Bram Moolenaar30613902019-12-01 22:11:18 +01002227 // Setup for catching the close-window event, don't let it close Vim!
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 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
Bram Moolenaar30613902019-12-01 22:11:18 +01002250 // Position the mouse pointer in the dialog, required for when focus
2251 // follows mouse.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 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}