428
+ − 1 /* Implements a lightweight menubar widget.
+ − 2 Copyright (C) 1992, 1993, 1994 Lucid, Inc.
+ − 3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
+ − 4
+ − 5 This file is part of the Lucid Widget Library.
+ − 6
+ − 7 The Lucid Widget Library is free software; you can redistribute it and/or
+ − 8 modify it under the terms of the GNU General Public License as published by
+ − 9 the Free Software Foundation; either version 2, or (at your option)
+ − 10 any later version.
+ − 11
+ − 12 The Lucid Widget Library is distributed in the hope that it will be useful,
+ − 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
+ − 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ − 15 GNU General Public License for more details.
+ − 16
+ − 17 You should have received a copy of the GNU General Public License
+ − 18 along with XEmacs; see the file COPYING. If not, write to
+ − 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ − 20 Boston, MA 02111-1307, USA. */
+ − 21
+ − 22 /* Created by devin@lucid.com */
+ − 23
+ − 24 #include <config.h>
+ − 25 #include <stdlib.h>
+ − 26 #include <string.h>
+ − 27 #include <ctype.h>
+ − 28 #include <stdio.h>
+ − 29 #include <sys/types.h>
+ − 30 #include <limits.h>
+ − 31 #ifdef HAVE_UNISTD_H
+ − 32 #include <unistd.h>
+ − 33 #endif
+ − 34
+ − 35 #include <X11/IntrinsicP.h>
+ − 36 #include <X11/ShellP.h>
+ − 37 #include <X11/StringDefs.h>
+ − 38 #include <X11/cursorfont.h>
+ − 39 #include <X11/bitmaps/gray>
+ − 40
+ − 41 #ifdef NEED_MOTIF
+ − 42 #include <Xm/Xm.h>
+ − 43 #if XmVersion < 1002 /* 1.1 or ancient */
+ − 44 #undef XmFONTLIST_DEFAULT_TAG
+ − 45 #define XmFONTLIST_DEFAULT_TAG XmSTRING_DEFAULT_CHARSET
+ − 46 #endif /* XmVersion < 1.2 */
+ − 47 #endif
+ − 48 #include "xlwmenuP.h"
+ − 49
+ − 50 #ifdef USE_DEBUG_MALLOC
+ − 51 #include <dmalloc.h>
+ − 52 #endif
+ − 53
442
+ − 54 /* simple, naive integer maximum */
428
+ − 55 #ifndef max
+ − 56 #define max(a,b) ((a)>(b)?(a):(b))
+ − 57 #endif
+ − 58
+ − 59 static char
+ − 60 xlwMenuTranslations [] =
+ − 61 "<BtnDown>: start()\n\
+ − 62 <BtnMotion>: drag()\n\
+ − 63 <BtnUp>: select()\n\
+ − 64 ";
+ − 65
+ − 66 extern Widget lw_menubar_widget;
+ − 67
+ − 68 #define offset(field) XtOffset(XlwMenuWidget, field)
+ − 69 static XtResource
+ − 70 xlwMenuResources[] =
+ − 71 {
+ − 72 #ifdef NEED_MOTIF
+ − 73 /* There are three font list resources, so that we can accept either of
+ − 74 the resources *fontList: or *font:, and so that we can tell the
+ − 75 difference between them being specified, and being defaulted to a
+ − 76 font from the XtRString specified here. */
+ − 77 {XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
+ − 78 offset(menu.font_list), XtRImmediate, (XtPointer)0},
+ − 79 {XtNfont, XtCFont, XmRFontList, sizeof(XmFontList),
+ − 80 offset(menu.font_list_2),XtRImmediate, (XtPointer)0},
+ − 81 {XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
+ − 82 offset(menu.fallback_font_list),
+ − 83 /* We must use an iso8859-1 font here, or people without $LANG set lose.
+ − 84 It's fair to assume that those who do have $LANG set also have the
+ − 85 *fontList resource set, or at least know how to deal with this. */
+ − 86 XtRString, (XtPointer) "-*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-1"},
+ − 87 #else
+ − 88 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ − 89 offset(menu.font), XtRString, (XtPointer) "XtDefaultFont"},
+ − 90 # ifdef USE_XFONTSET
442
+ − 91 /* #### Consider using the same method as for Motif; see the comment in
+ − 92 XlwMenuInitialize(). */
428
+ − 93 {XtNfontSet, XtCFontSet, XtRFontSet, sizeof(XFontSet),
+ − 94 offset(menu.font_set), XtRString, (XtPointer) "XtDefaultFontSet"},
+ − 95 # endif
+ − 96 #endif
+ − 97 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ − 98 offset(menu.foreground), XtRString, (XtPointer) "XtDefaultForeground"},
+ − 99 {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
+ − 100 offset(menu.button_foreground), XtRString, (XtPointer) "XtDefaultForeground"},
+ − 101 {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+ − 102 offset(menu.highlight_foreground), XtRString, (XtPointer) "XtDefaultForeground"},
+ − 103 {XtNtitleForeground, XtCTitleForeground, XtRPixel, sizeof(Pixel),
+ − 104 offset(menu.title_foreground), XtRString, (XtPointer) "XtDefaultForeground"},
+ − 105 {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
+ − 106 offset(menu.margin), XtRImmediate, (XtPointer)2},
+ − 107 {XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
+ − 108 offset(menu.horizontal_margin), XtRImmediate, (XtPointer)2},
+ − 109 {XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof(Dimension),
+ − 110 offset(menu.vertical_margin), XtRImmediate, (XtPointer)1},
+ − 111 {XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension),
+ − 112 offset(menu.column_spacing), XtRImmediate, (XtPointer)4},
+ − 113 {XmNindicatorSize, XmCIndicatorSize, XtRDimension, sizeof(Dimension),
+ − 114 offset(menu.indicator_size), XtRImmediate, (XtPointer)0},
+ − 115 #if 0
+ − 116 {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
+ − 117 sizeof (Dimension), offset (menu.shadow_thickness),
+ − 118 XtRImmediate, (XtPointer) 2},
+ − 119 #else
+ − 120 {XmNshadowThickness, XmCShadowThickness, XtRDimension,
+ − 121 sizeof (Dimension), offset (menu.shadow_thickness),
+ − 122 XtRImmediate, (XtPointer) 2},
+ − 123 #endif
+ − 124 {XmNselectColor, XmCSelectColor, XtRPixel, sizeof (Pixel),
+ − 125 offset (menu.select_color), XtRImmediate, (XtPointer)-1},
+ − 126 {XmNtopShadowColor, XmCTopShadowColor, XtRPixel, sizeof (Pixel),
+ − 127 offset (menu.top_shadow_color), XtRImmediate, (XtPointer)-1},
+ − 128 {XmNbottomShadowColor, XmCBottomShadowColor, XtRPixel, sizeof (Pixel),
+ − 129 offset (menu.bottom_shadow_color), XtRImmediate, (XtPointer)-1},
+ − 130 {XmNtopShadowPixmap, XmCTopShadowPixmap, XtRPixmap, sizeof (Pixmap),
+ − 131 offset (menu.top_shadow_pixmap), XtRImmediate, (XtPointer)None},
+ − 132 {XmNbottomShadowPixmap, XmCBottomShadowPixmap, XtRPixmap, sizeof (Pixmap),
+ − 133 offset (menu.bottom_shadow_pixmap), XtRImmediate, (XtPointer)None},
+ − 134
+ − 135 {XtNopen, XtCCallback, XtRCallback, sizeof(XtPointer),
+ − 136 offset(menu.open), XtRCallback, (XtPointer)NULL},
+ − 137 {XtNselect, XtCCallback, XtRCallback, sizeof(XtPointer),
+ − 138 offset(menu.select), XtRCallback, (XtPointer)NULL},
+ − 139 {XtNmenu, XtCMenu, XtRPointer, sizeof(XtPointer),
+ − 140 offset(menu.contents), XtRImmediate, (XtPointer)NULL},
+ − 141 {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ − 142 offset(menu.cursor_shape), XtRString, (XtPointer) "right_ptr"},
+ − 143 {XtNhorizontal, XtCHorizontal, XtRInt, sizeof(int),
+ − 144 offset(menu.horizontal), XtRImmediate, (XtPointer)True},
+ − 145 {XtNuseBackingStore, XtCUseBackingStore, XtRBoolean, sizeof (Boolean),
+ − 146 offset (menu.use_backing_store), XtRImmediate, (XtPointer)False},
+ − 147 {XtNbounceDown, XtCBounceDown, XtRBoolean, sizeof (Boolean),
+ − 148 offset (menu.bounce_down), XtRImmediate, (XtPointer)True},
+ − 149 {XtNresourceLabels, XtCResourceLabels, XtRBoolean, sizeof (Boolean),
+ − 150 offset (menu.lookup_labels), XtRImmediate, (XtPointer)False},
+ − 151 };
+ − 152 #undef offset
+ − 153
+ − 154 static Boolean XlwMenuSetValues (Widget current, Widget request, Widget new,
+ − 155 ArgList args, Cardinal *num_args);
+ − 156 static void XlwMenuRealize (Widget w, Mask *valueMask,
+ − 157 XSetWindowAttributes *attributes);
+ − 158 static void XlwMenuRedisplay (Widget w, XEvent *ev, Region region);
+ − 159 static void XlwMenuResize (Widget w);
+ − 160 static void XlwMenuInitialize (Widget request, Widget new, ArgList args,
+ − 161 Cardinal *num_args);
+ − 162 static void XlwMenuDestroy (Widget w);
+ − 163 static void XlwMenuClassInitialize (void);
+ − 164 static void Start (Widget w, XEvent *ev, String *params, Cardinal *num_params);
+ − 165 static void Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params);
+ − 166 static void Select(Widget w, XEvent *ev, String *params, Cardinal *num_params);
+ − 167
+ − 168 #ifdef NEED_MOTIF
+ − 169 static XFontStruct *default_font_of_font_list (XmFontList);
+ − 170 #endif
+ − 171
+ − 172 static XtActionsRec
+ − 173 xlwMenuActionsList [] =
+ − 174 {
+ − 175 {"start", Start},
+ − 176 {"drag", Drag},
+ − 177 {"select", Select},
+ − 178 };
+ − 179
+ − 180 #define SuperClass ((CoreWidgetClass)&coreClassRec)
+ − 181
+ − 182 XlwMenuClassRec xlwMenuClassRec =
+ − 183 {
+ − 184 { /* CoreClass fields initialization */
+ − 185 (WidgetClass) SuperClass, /* superclass */
+ − 186 "XlwMenu", /* class_name */
+ − 187 sizeof(XlwMenuRec), /* size */
+ − 188 XlwMenuClassInitialize, /* class_initialize */
+ − 189 NULL, /* class_part_initialize */
+ − 190 FALSE, /* class_inited */
+ − 191 XlwMenuInitialize, /* initialize */
+ − 192 NULL, /* initialize_hook */
+ − 193 XlwMenuRealize, /* realize */
+ − 194 xlwMenuActionsList, /* actions */
+ − 195 XtNumber(xlwMenuActionsList), /* num_actions */
+ − 196 xlwMenuResources, /* resources */
+ − 197 XtNumber(xlwMenuResources), /* resource_count */
+ − 198 NULLQUARK, /* xrm_class */
+ − 199 TRUE, /* compress_motion */
+ − 200 TRUE, /* compress_exposure */
+ − 201 TRUE, /* compress_enterleave */
+ − 202 FALSE, /* visible_interest */
+ − 203 XlwMenuDestroy, /* destroy */
+ − 204 XlwMenuResize, /* resize */
+ − 205 XlwMenuRedisplay, /* expose */
+ − 206 XlwMenuSetValues, /* set_values */
+ − 207 NULL, /* set_values_hook */
+ − 208 XtInheritSetValuesAlmost, /* set_values_almost */
+ − 209 NULL, /* get_values_hook */
+ − 210 NULL, /* #### - should this be set for grabs? accept_focus */
+ − 211 XtVersion, /* version */
+ − 212 NULL, /* callback_private */
+ − 213 xlwMenuTranslations, /* tm_table */
+ − 214 XtInheritQueryGeometry, /* query_geometry */
+ − 215 XtInheritDisplayAccelerator, /* display_accelerator */
+ − 216 NULL /* extension */
+ − 217 }, /* XlwMenuClass fields initialization */
+ − 218 {
+ − 219 0 /* dummy */
+ − 220 },
+ − 221 };
+ − 222
+ − 223 WidgetClass xlwMenuWidgetClass = (WidgetClass) &xlwMenuClassRec;
+ − 224
+ − 225 extern int lw_menu_accelerate;
+ − 226
+ − 227 /* Utilities */
+ − 228 #if 0 /* Apparently not used anywhere */
+ − 229
+ − 230 static char *
+ − 231 safe_strdup (char *s)
+ − 232 {
+ − 233 char *result;
+ − 234 if (! s) return 0;
+ − 235 result = (char *) malloc (strlen (s) + 1);
+ − 236 if (! result)
+ − 237 return 0;
+ − 238 strcpy (result, s);
+ − 239 return result;
+ − 240 }
+ − 241
+ − 242 #endif /* 0 */
+ − 243
+ − 244 /* Replacement for XAllocColor() that tries to return the nearest
+ − 245 available color if the colormap is full. From FSF Emacs. */
+ − 246
+ − 247 static int
+ − 248 allocate_nearest_color (Display *display, Colormap screen_colormap,
+ − 249 XColor *color_def)
+ − 250 {
+ − 251 int status = XAllocColor (display, screen_colormap, color_def);
+ − 252 if (status)
+ − 253 return status;
+ − 254
+ − 255 {
+ − 256 /* If we got to this point, the colormap is full, so we're
+ − 257 going to try to get the next closest color.
+ − 258 The algorithm used is a least-squares matching, which is
+ − 259 what X uses for closest color matching with StaticColor visuals. */
+ − 260
+ − 261 int nearest, x;
+ − 262 unsigned long nearest_delta = ULONG_MAX;
+ − 263
+ − 264 int no_cells = XDisplayCells (display, XDefaultScreen (display));
+ − 265 /* Don't use alloca here because lwlib doesn't have the
+ − 266 necessary configuration information that src does. */
+ − 267 XColor *cells = (XColor *) malloc (sizeof (XColor) * no_cells);
+ − 268
+ − 269 for (x = 0; x < no_cells; x++)
+ − 270 cells[x].pixel = x;
+ − 271
+ − 272 XQueryColors (display, screen_colormap, cells, no_cells);
+ − 273
+ − 274 for (nearest = 0, x = 0; x < no_cells; x++)
+ − 275 {
+ − 276 long dred = (color_def->red >> 8) - (cells[x].red >> 8);
+ − 277 long dgreen = (color_def->green >> 8) - (cells[x].green >> 8);
+ − 278 long dblue = (color_def->blue >> 8) - (cells[x].blue >> 8);
+ − 279 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
+ − 280
+ − 281 if (delta < nearest_delta)
+ − 282 {
+ − 283 nearest = x;
+ − 284 nearest_delta = delta;
+ − 285 }
+ − 286 }
+ − 287 color_def->red = cells[nearest].red;
+ − 288 color_def->green = cells[nearest].green;
+ − 289 color_def->blue = cells[nearest].blue;
+ − 290 free (cells);
+ − 291 return XAllocColor (display, screen_colormap, color_def);
+ − 292 }
+ − 293 }
+ − 294
+ − 295 static void
+ − 296 push_new_stack (XlwMenuWidget mw, widget_value *val)
+ − 297 {
+ − 298 if (!mw->menu.new_stack)
+ − 299 {
+ − 300 mw->menu.new_stack_length = 10;
+ − 301 mw->menu.new_stack =
+ − 302 (widget_value**)XtCalloc (mw->menu.new_stack_length,
+ − 303 sizeof (widget_value*));
+ − 304 }
+ − 305 else if (mw->menu.new_depth == mw->menu.new_stack_length)
+ − 306 {
+ − 307 mw->menu.new_stack_length *= 2;
+ − 308 mw->menu.new_stack =
+ − 309 (widget_value**)XtRealloc ((char *)mw->menu.new_stack,
+ − 310 mw->menu.new_stack_length *
+ − 311 sizeof (widget_value*));
+ − 312 }
+ − 313 mw->menu.new_stack [mw->menu.new_depth++] = val;
+ − 314 }
+ − 315
+ − 316 static void
+ − 317 pop_new_stack_if_no_contents (XlwMenuWidget mw)
+ − 318 {
+ − 319 if (mw->menu.new_depth &&
+ − 320 !mw->menu.new_stack [mw->menu.new_depth - 1]->contents)
+ − 321 mw->menu.new_depth -= 1;
+ − 322 }
+ − 323
+ − 324 static void
+ − 325 make_old_stack_space (XlwMenuWidget mw, int n)
+ − 326 {
+ − 327 if (!mw->menu.old_stack)
+ − 328 {
+ − 329 mw->menu.old_stack_length = max (10, n);
+ − 330 mw->menu.old_stack =
+ − 331 (widget_value**)XtCalloc (mw->menu.old_stack_length,
+ − 332 sizeof (widget_value*));
+ − 333 }
+ − 334 else if (mw->menu.old_stack_length < n)
+ − 335 {
+ − 336 while (mw->menu.old_stack_length < n)
+ − 337 mw->menu.old_stack_length *= 2;
+ − 338
+ − 339 mw->menu.old_stack =
+ − 340 (widget_value**)XtRealloc ((char *)mw->menu.old_stack,
+ − 341 mw->menu.old_stack_length *
+ − 342 sizeof (widget_value*));
+ − 343 }
+ − 344 }
+ − 345
+ − 346 static Boolean
+ − 347 close_to_reference_time (Widget w, Time reference_time, XEvent *ev)
+ − 348 {
+ − 349 return
+ − 350 reference_time &&
647
+ − 351 ((int) (ev->xbutton.time - reference_time) <
+ − 352 XtGetMultiClickTime (XtDisplay (w)));
428
+ − 353 }
+ − 354
+ − 355 /* Size code */
+ − 356 static int
+ − 357 string_width (XlwMenuWidget mw,
+ − 358 #ifdef NEED_MOTIF
+ − 359 XmString s
+ − 360 #else
+ − 361 char *s
+ − 362 #endif
+ − 363 )
+ − 364 {
+ − 365 #ifdef NEED_MOTIF
+ − 366 Dimension width, height;
+ − 367 XmStringExtent (mw->menu.font_list, s, &width, &height);
+ − 368 return width;
+ − 369 #else
+ − 370 # ifdef USE_XFONTSET
+ − 371 XRectangle ri, rl;
+ − 372 XmbTextExtents (mw->menu.font_set, s, strlen (s), &ri, &rl);
+ − 373 return rl.width;
+ − 374 # else
+ − 375 XCharStruct xcs;
+ − 376 int drop;
+ − 377 XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs);
+ − 378 return xcs.width;
+ − 379 # endif /* USE_XFONTSET */
+ − 380 #endif
+ − 381 }
+ − 382
+ − 383 static char massaged_resource_char[256];
+ − 384
+ − 385 static void
+ − 386 initialize_massaged_resource_char (void)
+ − 387 {
+ − 388 int j;
+ − 389 for (j = 0; j < (int) sizeof (massaged_resource_char); j++)
+ − 390 {
+ − 391 if ((j >= 'a' && j <= 'z') ||
+ − 392 (j >= 'A' && j <= 'Z') ||
+ − 393 (j >= '0' && j <= '9') ||
+ − 394 (j == '_') ||
+ − 395 (j >= 0xa0))
+ − 396 massaged_resource_char[j] = (char) j;
+ − 397 }
+ − 398 massaged_resource_char ['_'] = '_';
+ − 399 massaged_resource_char ['+'] = 'P'; /* Convert C++ to cPP */
+ − 400 massaged_resource_char ['.'] = '_'; /* Convert Buffers... to buffers___ */
+ − 401 }
+ − 402
+ − 403 static int
+ − 404 string_width_u (XlwMenuWidget mw,
+ − 405 #ifdef NEED_MOTIF
+ − 406 XmString string
+ − 407 #else
+ − 408 char *string
+ − 409 #endif
+ − 410 )
+ − 411 {
+ − 412 #ifdef NEED_MOTIF
+ − 413 Dimension width, height;
+ − 414 XmString newstring;
+ − 415 #else
+ − 416 # ifdef USE_XFONTSET
+ − 417 XRectangle ri, rl;
+ − 418 # else /* ! USE_XFONTSET */
+ − 419 XCharStruct xcs;
+ − 420 int drop;
+ − 421 # endif
+ − 422 #endif
+ − 423 char* newchars;
+ − 424 int charslength;
+ − 425 char *chars;
+ − 426 int i, j;
+ − 427
+ − 428 #ifdef NEED_MOTIF
+ − 429 chars = "";
+ − 430 if (!XmStringGetLtoR (string, XmFONTLIST_DEFAULT_TAG, &chars))
+ − 431 chars = "";
+ − 432 #else
+ − 433 chars = string;
+ − 434 #endif
+ − 435 charslength = strlen (chars);
+ − 436 newchars = (char *) alloca (charslength + 1);
+ − 437
+ − 438 for (i = j = 0; chars[i] && (j < charslength); i++)
+ − 439 if (chars[i]=='%'&&chars[i+1]=='_')
+ − 440 i++;
+ − 441 else
+ − 442 newchars[j++] = chars[i];
+ − 443 newchars[j] = '\0';
+ − 444
+ − 445 #ifdef NEED_MOTIF
+ − 446 newstring = XmStringLtoRCreate (newchars, XmFONTLIST_DEFAULT_TAG);
+ − 447 XmStringExtent (mw->menu.font_list, newstring, &width, &height);
+ − 448 XmStringFree (newstring);
+ − 449 XtFree (chars);
+ − 450 return width;
+ − 451 #else
+ − 452 # ifdef USE_XFONTSET
+ − 453 XmbTextExtents (mw->menu.font_set, newchars, j, &ri, &rl);
+ − 454 return rl.width;
+ − 455 # else /* ! USE_XFONTSET */
+ − 456 XTextExtents (mw->menu.font, newchars, j, &drop, &drop, &drop, &xcs);
+ − 457 return xcs.width;
+ − 458 # endif /* USE_XFONTSET */
+ − 459 #endif
+ − 460 }
+ − 461
+ − 462 static void
442
+ − 463 massage_resource_name (const char *in, char *out)
428
+ − 464 {
+ − 465 /* Turn a random string into something suitable for using as a resource.
+ − 466 For example:
+ − 467
+ − 468 "Kill Buffer" -> "killBuffer"
+ − 469 "Find File..." -> "findFile___"
+ − 470 "Search and Replace..." -> "searchAndReplace___"
+ − 471 "C++ Mode Commands" -> "cppModeCommands"
+ − 472
+ − 473 Valid characters in a resource NAME component are: a-zA-Z0-9_
+ − 474 */
+ − 475
+ − 476 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS
+ − 477 /* Compile with -DPRINT_XLWMENU_RESOURCE_CONVERSIONS to generate a
+ − 478 translation file for menu localizations. */
+ − 479 char *save_in = in, *save_out = out;
+ − 480 #endif
+ − 481
+ − 482 Boolean firstp = True;
+ − 483 while (*in)
+ − 484 {
442
+ − 485 if (*in == '%' && *(in + 1) == '_')
+ − 486 in += 2;
+ − 487 else
428
+ − 488 {
442
+ − 489 char ch;
+ − 490
+ − 491 if (*in == '%' && *(in + 1) == '%')
+ − 492 in++;
+ − 493 ch = massaged_resource_char[(unsigned char) *in++];
+ − 494 if (ch)
+ − 495 {
+ − 496 int int_ch = (int) (unsigned char) ch;
+ − 497 *out++ = firstp ? tolower (int_ch) : toupper (int_ch);
+ − 498 firstp = False;
+ − 499 while ((ch = massaged_resource_char[(unsigned char) *in++])
+ − 500 != '\0')
+ − 501 *out++ = ch;
+ − 502 if (!*(in-1)) /* Overshot the NULL byte? */
+ − 503 break;
+ − 504 }
428
+ − 505 }
+ − 506 }
+ − 507 *out = 0;
+ − 508
+ − 509 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS
+ − 510 printf ("! Emacs*XlwMenu.%s.labelString:\t%s\n", save_out, save_in);
+ − 511 printf ( "Emacs*XlwMenu.%s.labelString:\n", save_out);
+ − 512 #endif
+ − 513 }
+ − 514
+ − 515 static XtResource
+ − 516 nameResource[] =
+ − 517 {
+ − 518 { "labelString", "LabelString", XtRString, sizeof(String),
+ − 519 0, XtRImmediate, 0 }
+ − 520 };
+ − 521
442
+ − 522 /* This function searches STRING for parameter inserts of the form:
+ − 523 %[padding]1
+ − 524 padding is either space (' ') or dash ('-') meaning
+ − 525 padding to the left or right of the inserted parameter.
+ − 526 In essence, all %1 strings are replaced by VALUE in the return value.
+ − 527 The caller is expected to free the return value using XtFree().
+ − 528 %% means insert one % (like printf).
+ − 529 %1 means insert VALUE.
+ − 530 %-1 means insert VALUE followed by one space. The latter is
+ − 531 not inserted if VALUE is a zero length string.
+ − 532 */
428
+ − 533 static char*
442
+ − 534 parameterize_string (const char *string, const char *value)
428
+ − 535 {
442
+ − 536 const char *percent;
428
+ − 537 char *result;
+ − 538 unsigned int done = 0;
+ − 539 unsigned int ntimes;
+ − 540
+ − 541 if (!string)
+ − 542 {
+ − 543 result = XtMalloc(1);
+ − 544 result[0] = '\0';
442
+ − 545 return result;
428
+ − 546 }
+ − 547
+ − 548 if (!value)
+ − 549 value = "";
+ − 550
442
+ − 551 for (ntimes = 1, percent = string;
+ − 552 (percent = strchr (percent, '%'));
428
+ − 553 ntimes++)
442
+ − 554 percent++;
428
+ − 555
+ − 556 result = XtMalloc ((ntimes * strlen(value)) + strlen(string) + 4);
+ − 557 result[0] = '\0';
+ − 558
442
+ − 559 while ((percent = strchr (string, '%')))
428
+ − 560 {
+ − 561 unsigned int left_pad;
+ − 562 unsigned int right_pad;
442
+ − 563 const char *p;
428
+ − 564
+ − 565 if (percent[1] == '%')
+ − 566 { /* it's a real % */
+ − 567 strncat (result, string, 1 + percent - string); /* incl % */
+ − 568 string = &percent[2]; /* after the second '%' */
+ − 569 continue; /* with the while() loop */
+ − 570 }
+ − 571
+ − 572 left_pad = 0;
+ − 573 right_pad = 0;
+ − 574
+ − 575 for (p = &percent[1]; /* test *p inside the loop */ ; p++)
+ − 576 {
+ − 577 if (*p == ' ')
+ − 578 { /* left pad */
+ − 579 left_pad++;
+ − 580 }
+ − 581 else if (*p == '-')
+ − 582 { /* right pad */
+ − 583 right_pad++;
+ − 584 }
+ − 585 else if (*p == '1')
+ − 586 { /* param and terminator */
+ − 587 strncat (result, string, percent - string);
+ − 588 if (value[0] != '\0')
+ − 589 {
+ − 590 unsigned int i;
+ − 591 for (i = 0; i < left_pad; i++)
+ − 592 strcat (result, " ");
+ − 593 strcat (result, value);
+ − 594 for (i = 0; i < right_pad; i++)
+ − 595 strcat (result, " ");
+ − 596 }
+ − 597 string = &p[1]; /* after the '1' */
+ − 598 done++; /* no need to do old way */
+ − 599 break; /* out of for() loop */
+ − 600 }
+ − 601 else
+ − 602 { /* bogus, copy the format as is */
+ − 603 /* out of for() loop */
+ − 604 strncat (result, string, 1 + p - string);
+ − 605 string = (*p ? &p[1] : p);
+ − 606 break;
+ − 607 }
+ − 608 }
+ − 609 }
+ − 610
+ − 611 /* Copy the tail of the string */
+ − 612 strcat (result, string);
+ − 613
+ − 614 /* If we have not processed a % string, and we have a value, tail it. */
+ − 615 if (!done && value[0] != '\0')
+ − 616 {
+ − 617 strcat (result, " ");
+ − 618 strcat (result, value);
+ − 619 }
+ − 620
+ − 621 return result;
+ − 622 }
+ − 623
+ − 624 #ifdef NEED_MOTIF
+ − 625
+ − 626 static XmString
+ − 627 resource_widget_value (XlwMenuWidget mw, widget_value *val)
+ − 628 {
+ − 629 if (!val->toolkit_data)
+ − 630 {
+ − 631 char *resourced_name = NULL;
+ − 632 char *converted_name, *str;
+ − 633 XmString complete_name;
+ − 634 char massaged_name [1024];
+ − 635
+ − 636 if (mw->menu.lookup_labels)
+ − 637 {
+ − 638 /* Convert value style name into resource style name.
+ − 639 eg: "Free Willy" becomes "freeWilly" */
+ − 640 massage_resource_name (val->name, massaged_name);
+ − 641
+ − 642 /* If we have a value (parameter) see if we can find a "Named"
+ − 643 resource. */
+ − 644 if (val->value)
+ − 645 {
+ − 646 char named_name[1024];
+ − 647 sprintf (named_name, "%sNamed", massaged_name);
+ − 648 XtGetSubresources ((Widget) mw,
+ − 649 (XtPointer) &resourced_name,
+ − 650 named_name, named_name,
+ − 651 nameResource, 1, NULL, 0);
+ − 652 }
+ − 653
+ − 654 /* If nothing yet, try to load from the massaged name. */
+ − 655 if (!resourced_name)
+ − 656 {
+ − 657 XtGetSubresources ((Widget) mw,
+ − 658 (XtPointer) &resourced_name,
+ − 659 massaged_name, massaged_name,
+ − 660 nameResource, 1, NULL, 0);
+ − 661 }
+ − 662 } /* if (mw->menu.lookup_labels) */
+ − 663
+ − 664 /* Still nothing yet, use the name as the value. */
+ − 665 if (!resourced_name)
+ − 666 resourced_name = val->name;
+ − 667
+ − 668 /* Parameterize the string. */
+ − 669 converted_name = parameterize_string (resourced_name, val->value);
+ − 670
+ − 671 /* nuke newline characters to prevent menubar screwups */
+ − 672 for ( str = converted_name ; *str ; str++ )
+ − 673 {
+ − 674 if (str[0] == '\n') str[0] = ' ';
+ − 675 }
+ − 676
+ − 677 /* Improve OSF's bottom line. */
+ − 678 #if (XmVersion >= 1002)
+ − 679 complete_name = XmStringCreateLocalized (converted_name);
+ − 680 #else
+ − 681 complete_name = XmStringCreateLtoR (converted_name,
+ − 682 XmSTRING_DEFAULT_CHARSET);
+ − 683 #endif
+ − 684 XtFree (converted_name);
+ − 685
+ − 686 val->toolkit_data = complete_name;
+ − 687 val->free_toolkit_data = True;
+ − 688 }
+ − 689 return (XmString) val->toolkit_data;
+ − 690 }
+ − 691
+ − 692 /* Unused */
+ − 693 #if 0
442
+ − 694 /* These two routines should be a separate file..djw */
428
+ − 695 static char *
+ − 696 xlw_create_localized_string (Widget w,
+ − 697 char *name,
+ − 698 char **args,
+ − 699 unsigned int nargs)
+ − 700 {
+ − 701 char *string = NULL;
+ − 702 char *arg = NULL;
+ − 703
+ − 704 if (nargs > 0)
+ − 705 arg = args[0];
+ − 706
+ − 707 XtGetSubresources (w,
+ − 708 (XtPointer)&string,
+ − 709 name,
+ − 710 name,
+ − 711 nameResource, 1,
+ − 712 NULL, 0);
+ − 713
+ − 714 if (!string)
+ − 715 string = name;
+ − 716
+ − 717 return parameterize_string (string, arg);
+ − 718 }
+ − 719
+ − 720 static XmString
+ − 721 xlw_create_localized_xmstring (Widget w,
+ − 722 char *name,
+ − 723 char **args,
+ − 724 unsigned int nargs)
+ − 725 {
+ − 726 char * string = xlw_create_localized_string (w, name, args, nargs);
+ − 727 XmString xm_string = XmStringCreateLtoR (string, XmSTRING_DEFAULT_CHARSET);
+ − 728 XtFree (string);
+ − 729 return xm_string;
+ − 730 }
+ − 731 #endif /* 0 */
+ − 732
+ − 733 #else /* !Motif */
+ − 734
+ − 735 static char*
+ − 736 resource_widget_value (XlwMenuWidget mw, widget_value *val)
+ − 737 {
+ − 738 if (!val->toolkit_data)
+ − 739 {
+ − 740 char *resourced_name = NULL;
+ − 741 char *complete_name;
+ − 742 char massaged_name [1024];
+ − 743
+ − 744 if (mw->menu.lookup_labels)
+ − 745 {
+ − 746 massage_resource_name (val->name, massaged_name);
+ − 747
+ − 748 XtGetSubresources ((Widget) mw,
+ − 749 (XtPointer) &resourced_name,
+ − 750 massaged_name, massaged_name,
+ − 751 nameResource, 1, NULL, 0);
+ − 752 }
+ − 753 if (!resourced_name)
+ − 754 resourced_name = val->name;
+ − 755
+ − 756 complete_name = parameterize_string (resourced_name, val->value);
+ − 757
+ − 758 val->toolkit_data = complete_name;
+ − 759 /* nuke newline characters to prevent menubar screwups */
+ − 760 for ( ; *complete_name ; complete_name++ )
+ − 761 {
+ − 762 if (complete_name[0] == '\n')
+ − 763 complete_name[0] = ' ';
+ − 764 }
+ − 765 val->free_toolkit_data = True;
+ − 766 }
+ − 767 return (char *) val->toolkit_data;
+ − 768 }
+ − 769
+ − 770 #endif /* !Motif */
+ − 771
+ − 772 /* Code for drawing strings. */
+ − 773 static void
+ − 774 string_draw (XlwMenuWidget mw,
+ − 775 Window window,
+ − 776 int x, int y,
+ − 777 GC gc,
+ − 778 #ifdef NEED_MOTIF
+ − 779 XmString string
+ − 780 #else
+ − 781 char *string
+ − 782 #endif
+ − 783 )
+ − 784 {
+ − 785 #ifdef NEED_MOTIF
+ − 786 XmStringDraw (XtDisplay (mw), window,
+ − 787 mw->menu.font_list,
+ − 788 string, gc,
+ − 789 x, y,
+ − 790 1000, /* ???? width */
+ − 791 XmALIGNMENT_BEGINNING,
+ − 792 0, /* ???? layout_direction */
+ − 793 0);
+ − 794 #else
+ − 795 # ifdef USE_XFONTSET
+ − 796 XmbDrawString (XtDisplay (mw), window, mw->menu.font_set, gc,
+ − 797 x, y + mw->menu.font_ascent, string, strlen (string));
+ − 798 # else
+ − 799 XDrawString (XtDisplay (mw), window, gc,
+ − 800 x, y + mw->menu.font_ascent, string, strlen (string));
+ − 801 # endif /* USE_XFONTSET */
+ − 802
+ − 803 #endif
+ − 804 }
+ − 805
+ − 806 static int
+ − 807 string_draw_range (
+ − 808 XlwMenuWidget mw,
+ − 809 Window window,
+ − 810 int x, int y,
+ − 811 GC gc,
+ − 812 char *string,
+ − 813 int start,
+ − 814 int end
+ − 815 )
+ − 816 {
+ − 817 #ifdef NEED_MOTIF
+ − 818 Dimension width, height;
+ − 819 XmString newstring;
+ − 820 int c;
+ − 821
+ − 822 if (end <= start)
+ − 823 return 0;
+ − 824 c = string[end];
+ − 825 string[end] = '\0';
+ − 826 newstring = XmStringLtoRCreate (&string[start], XmFONTLIST_DEFAULT_TAG);
+ − 827 XmStringDraw (
+ − 828 XtDisplay (mw), window,
+ − 829 mw->menu.font_list,
+ − 830 newstring, gc,
+ − 831 x, y,
+ − 832 1000, /* ???? width */
+ − 833 XmALIGNMENT_BEGINNING,
+ − 834 0, /* ???? layout_direction */
+ − 835 0
+ − 836 );
+ − 837 XmStringExtent (mw->menu.font_list, newstring, &width, &height);
+ − 838 XmStringFree (newstring);
+ − 839 string[end] = c;
+ − 840 return width;
+ − 841 #else
+ − 842 # ifdef USE_XFONTSET
+ − 843 XRectangle ri, rl;
+ − 844
+ − 845 if (end <= start)
+ − 846 return 0;
+ − 847 XmbDrawString (
+ − 848 XtDisplay (mw), window, mw->menu.font_set, gc,
+ − 849 x, y + mw->menu.font_ascent, &string[start], end - start);
+ − 850 XmbTextExtents (
+ − 851 mw->menu.font_set, &string[start], end - start, &ri, &rl);
+ − 852 return rl.width;
+ − 853 # else
+ − 854 XCharStruct xcs;
+ − 855 int drop;
+ − 856
+ − 857 if (end <= start)
+ − 858 return 0;
+ − 859 XDrawString (
+ − 860 XtDisplay (mw), window, gc,
+ − 861 x, y + mw->menu.font_ascent, &string[start], end - start);
+ − 862 XTextExtents (
+ − 863 mw->menu.font, &string[start], end - start,
+ − 864 &drop, &drop, &drop, &xcs);
+ − 865 return xcs.width;
+ − 866 # endif
+ − 867 #endif
+ − 868 }
+ − 869
+ − 870 static void
+ − 871 string_draw_u (XlwMenuWidget mw,
+ − 872 Window window,
+ − 873 int x, int y,
+ − 874 GC gc,
+ − 875 #ifdef NEED_MOTIF
+ − 876 XmString string
+ − 877 #else
+ − 878 char *string
+ − 879 #endif
+ − 880 )
+ − 881 {
+ − 882 int i, s = 0;
+ − 883 char *chars;
+ − 884
+ − 885 #ifdef NEED_MOTIF
+ − 886 chars = "";
+ − 887 if (!XmStringGetLtoR (string, XmFONTLIST_DEFAULT_TAG, &chars))
+ − 888 chars = "";
+ − 889 #else
+ − 890 chars = string;
+ − 891 #endif
+ − 892 for (i=0; chars[i]; ++i) {
+ − 893 if (chars[i] == '%' && chars[i+1] == '_') {
+ − 894 int w;
+ − 895
+ − 896 x += string_draw_range (mw, window, x, y, gc, chars, s, i);
+ − 897 w = string_draw_range (mw, window, x, y, gc, chars, i+2, i+3);
+ − 898
+ − 899 /* underline next character */
+ − 900 XDrawLine (XtDisplay (mw), window, gc, x - 1,
+ − 901 y + mw->menu.font_ascent + 1,
+ − 902 x + w - 1, y + mw->menu.font_ascent + 1 );
+ − 903 x += w;
+ − 904 s = i + 3;
+ − 905 i += 2;
+ − 906 }
+ − 907 }
+ − 908 x += string_draw_range (mw, window, x, y, gc, chars, s, i);
+ − 909 #ifdef NEED_MOTIF
+ − 910 XtFree (chars);
+ − 911 #endif
+ − 912 }
+ − 913
+ − 914 static void
+ − 915 binding_draw (XlwMenuWidget mw, Window w, int x, int y, GC gc, char *value)
+ − 916 {
+ − 917 #ifdef NEED_MOTIF
+ − 918 XmString xm_value = XmStringCreateLtoR(value, XmSTRING_DEFAULT_CHARSET);
+ − 919 string_draw (mw, w, x, y, gc, xm_value);
+ − 920 XmStringFree (xm_value);
+ − 921 #else
+ − 922 string_draw (mw, w, x, y, gc, value);
+ − 923 #endif
+ − 924 }
+ − 925
+ − 926 /* Low level code for drawing 3-D edges. */
+ − 927 static void
+ − 928 shadow_rectangle_draw (Display *dpy,
+ − 929 Window window,
+ − 930 GC top_gc,
+ − 931 GC bottom_gc,
+ − 932 int x, int y,
+ − 933 unsigned int width,
+ − 934 unsigned int height,
+ − 935 unsigned int thickness)
+ − 936 {
+ − 937 XPoint points [4];
+ − 938
+ − 939 if (!thickness)
+ − 940 return;
+ − 941
+ − 942 points [0].x = x;
+ − 943 points [0].y = y;
+ − 944 points [1].x = x + width;
+ − 945 points [1].y = y;
+ − 946 points [2].x = x + width - thickness;
+ − 947 points [2].y = y + thickness;
+ − 948 points [3].x = x;
+ − 949 points [3].y = y + thickness;
+ − 950 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ − 951 points [0].x = x;
+ − 952 points [0].y = y + thickness;
+ − 953 points [1].x = x;
+ − 954 points [1].y = y + height;
+ − 955 points [2].x = x + thickness;
+ − 956 points [2].y = y + height - thickness;
+ − 957 points [3].x = x + thickness;
+ − 958 points [3].y = y + thickness;
+ − 959 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ − 960 points [0].x = x + width;
+ − 961 points [0].y = y;
+ − 962 points [1].x = x + width - thickness;
+ − 963 points [1].y = y + thickness;
+ − 964 points [2].x = x + width - thickness;
+ − 965 points [2].y = y + height - thickness;
+ − 966 points [3].x = x + width;
+ − 967 points [3].y = y + height - thickness;
+ − 968 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
+ − 969 points [0].x = x;
+ − 970 points [0].y = y + height;
+ − 971 points [1].x = x + width;
+ − 972 points [1].y = y + height;
+ − 973 points [2].x = x + width;
+ − 974 points [2].y = y + height - thickness;
+ − 975 points [3].x = x + thickness;
+ − 976 points [3].y = y + height - thickness;
+ − 977 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
+ − 978 }
+ − 979
+ − 980 typedef enum e_shadow_type
+ − 981 {
+ − 982 /* these are Motif compliant */
+ − 983 SHADOW_BACKGROUND,
+ − 984 SHADOW_OUT,
+ − 985 SHADOW_IN,
+ − 986 SHADOW_ETCHED_OUT,
+ − 987 SHADOW_ETCHED_IN,
+ − 988 SHADOW_ETCHED_OUT_DASH,
+ − 989 SHADOW_ETCHED_IN_DASH,
+ − 990 SHADOW_SINGLE_LINE,
+ − 991 SHADOW_DOUBLE_LINE,
+ − 992 SHADOW_SINGLE_DASHED_LINE,
+ − 993 SHADOW_DOUBLE_DASHED_LINE,
+ − 994 SHADOW_NO_LINE,
+ − 995 /* these are all non-Motif */
+ − 996 SHADOW_DOUBLE_ETCHED_OUT,
+ − 997 SHADOW_DOUBLE_ETCHED_IN,
+ − 998 SHADOW_DOUBLE_ETCHED_OUT_DASH,
+ − 999 SHADOW_DOUBLE_ETCHED_IN_DASH
+ − 1000 } shadow_type;
+ − 1001
+ − 1002 static void
+ − 1003 shadow_draw (XlwMenuWidget mw,
+ − 1004 Window window,
+ − 1005 int x, int y,
+ − 1006 unsigned int width,
+ − 1007 unsigned int height,
+ − 1008 shadow_type type)
+ − 1009 {
+ − 1010 Display *dpy = XtDisplay (mw);
+ − 1011 GC top_gc;
+ − 1012 GC bottom_gc;
+ − 1013 int thickness = mw->menu.shadow_thickness;
+ − 1014 #if 0
+ − 1015 XPoint points [4];
+ − 1016 #endif /* 0 */
+ − 1017 Boolean etched = False;
+ − 1018
+ − 1019 switch (type)
+ − 1020 {
+ − 1021 case SHADOW_BACKGROUND:
+ − 1022 top_gc = bottom_gc = mw->menu.background_gc;
+ − 1023 break;
+ − 1024 case SHADOW_ETCHED_IN:
+ − 1025 top_gc = mw->menu.shadow_bottom_gc;
+ − 1026 bottom_gc = mw->menu.shadow_top_gc;
+ − 1027 etched = True;
+ − 1028 break;
+ − 1029 case SHADOW_ETCHED_OUT:
+ − 1030 top_gc = mw->menu.shadow_top_gc;
+ − 1031 bottom_gc = mw->menu.shadow_bottom_gc;
+ − 1032 etched = True;
+ − 1033 break;
+ − 1034 case SHADOW_IN:
+ − 1035 top_gc = mw->menu.shadow_bottom_gc;
+ − 1036 bottom_gc = mw->menu.shadow_top_gc;
+ − 1037 break;
+ − 1038 case SHADOW_OUT:
+ − 1039 default:
+ − 1040 top_gc = mw->menu.shadow_top_gc;
+ − 1041 bottom_gc = mw->menu.shadow_bottom_gc;
+ − 1042 break;
+ − 1043 }
+ − 1044
+ − 1045 if (etched)
+ − 1046 {
+ − 1047 unsigned int half = thickness/2;
+ − 1048 shadow_rectangle_draw (dpy,
+ − 1049 window,
+ − 1050 top_gc,
+ − 1051 top_gc,
+ − 1052 x, y,
+ − 1053 width - half, height - half,
+ − 1054 thickness - half);
+ − 1055 shadow_rectangle_draw (dpy,
+ − 1056 window,
+ − 1057 bottom_gc,
+ − 1058 bottom_gc,
+ − 1059 x + half, y + half,
+ − 1060 width - half , height - half,
+ − 1061 half);
+ − 1062 }
+ − 1063 else
+ − 1064 {
+ − 1065 shadow_rectangle_draw (dpy,
+ − 1066 window,
+ − 1067 top_gc,
+ − 1068 bottom_gc,
+ − 1069 x, y,
+ − 1070 width, height,
+ − 1071 thickness);
+ − 1072 }
+ − 1073 }
+ − 1074
+ − 1075 static void
+ − 1076 arrow_decoration_draw (XlwMenuWidget mw,
+ − 1077 Window window,
+ − 1078 int x, int y,
+ − 1079 unsigned int width,
+ − 1080 Boolean raised)
+ − 1081 {
+ − 1082 Display *dpy = XtDisplay (mw);
+ − 1083 GC top_gc;
+ − 1084 GC bottom_gc;
+ − 1085 GC select_gc;
+ − 1086 int thickness = mw->menu.shadow_thickness;
+ − 1087 XPoint points [4];
+ − 1088 int half_width;
+ − 1089 int length = (int)((double)width * 0.87);
+ − 1090 int thick_med = (int)((double)thickness * 1.73);
+ − 1091
+ − 1092 if (width & 0x1)
+ − 1093 half_width = width/2 + 1;
+ − 1094 else
+ − 1095 half_width = width/2;
+ − 1096
+ − 1097 select_gc = mw->menu.background_gc;
+ − 1098
+ − 1099 if (raised)
+ − 1100 {
+ − 1101 top_gc = mw->menu.shadow_bottom_gc;
+ − 1102 bottom_gc = mw->menu.shadow_top_gc;
+ − 1103 }
+ − 1104 else
+ − 1105 {
+ − 1106 top_gc = mw->menu.shadow_top_gc;
+ − 1107 bottom_gc = mw->menu.shadow_bottom_gc;
+ − 1108 }
+ − 1109
+ − 1110 /* Fill internal area. We do this first so that the borders have a
+ − 1111 nice sharp edge. */
+ − 1112 points [0].x = x + thickness;
+ − 1113 points [0].y = y + thickness;
+ − 1114 points [1].x = x + length - thickness;
+ − 1115 points [1].y = y + half_width;
+ − 1116 points [2].x = x + length - thickness;
+ − 1117 points [2].y = y + half_width + thickness;
+ − 1118 points [3].x = x + thickness;
+ − 1119 points [3].y = y + width - thickness;
+ − 1120
+ − 1121 XFillPolygon (dpy,
+ − 1122 window,
+ − 1123 select_gc,
+ − 1124 points,
+ − 1125 4,
+ − 1126 Convex,
+ − 1127 CoordModeOrigin);
+ − 1128
+ − 1129 /* left border */
+ − 1130 points [0].x = x;
+ − 1131 points [0].y = y;
+ − 1132 points [1].x = x + thickness;
+ − 1133 points [1].y = y + thick_med;
+ − 1134 points [2].x = x + thickness;
+ − 1135 points [2].y = y + width - thick_med;
+ − 1136 points [3].x = x;
+ − 1137 points [3].y = y + width;
+ − 1138
+ − 1139 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ − 1140
+ − 1141 /* top border */
+ − 1142 points [0].x = x;
+ − 1143 points [0].y = y + width;
+ − 1144 points [1].x = x + length;
+ − 1145 points [1].y = y + half_width;
+ − 1146 points [2].x = x + length - (thickness + thickness);
+ − 1147 points [2].y = y + half_width;
+ − 1148 points [3].x = x + thickness;
+ − 1149 points [3].y = y + width - thick_med;
+ − 1150
+ − 1151 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
+ − 1152
+ − 1153 /* bottom shadow */
+ − 1154 points [0].x = x;
+ − 1155 points [0].y = y;
+ − 1156 points [1].x = x + length;
+ − 1157 points [1].y = y + half_width;
+ − 1158 points [2].x = x + length - (thickness + thickness);
+ − 1159 points [2].y = y + half_width;
+ − 1160 points [3].x = x + thickness;
+ − 1161 points [3].y = y + thick_med;
+ − 1162
+ − 1163 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ − 1164 }
+ − 1165
+ − 1166 static void
+ − 1167 toggle_decoration_draw (XlwMenuWidget mw,
+ − 1168 Window window,
+ − 1169 int x, int y,
+ − 1170 unsigned int width,
+ − 1171 Boolean set)
+ − 1172 {
+ − 1173 Display *dpy = XtDisplay (mw);
+ − 1174 int thickness = mw->menu.shadow_thickness;
+ − 1175 shadow_type type;
+ − 1176 GC select_gc = mw->menu.select_gc;
+ − 1177
+ − 1178 if (set)
+ − 1179 type = SHADOW_IN;
+ − 1180 else
+ − 1181 type = SHADOW_OUT;
+ − 1182
+ − 1183 /* Fill internal area. */
+ − 1184 if (set)
+ − 1185 XFillRectangle (dpy,
+ − 1186 window,
+ − 1187 select_gc,
+ − 1188 x + thickness,
+ − 1189 y + thickness,
+ − 1190 width - (2*thickness),
+ − 1191 width - (2*thickness));
+ − 1192
+ − 1193 shadow_draw (mw, window, x, y, width, width, type);
+ − 1194 }
+ − 1195
+ − 1196 static void
+ − 1197 radio_decoration_draw (XlwMenuWidget mw,
+ − 1198 Window window,
+ − 1199 int x, int y,
+ − 1200 unsigned int width,
+ − 1201 Boolean enabled)
+ − 1202 {
+ − 1203 Display *dpy = XtDisplay (mw);
+ − 1204 GC top_gc;
+ − 1205 GC bottom_gc;
+ − 1206 GC select_gc = mw->menu.select_gc;
+ − 1207 int thickness = mw->menu.shadow_thickness;
+ − 1208 XPoint points[6];
+ − 1209 int half_width;
+ − 1210 #if 0
+ − 1211 int npoints;
+ − 1212 #endif /* 0 */
+ − 1213
+ − 1214 if (width & 0x1)
+ − 1215 width++;
+ − 1216
+ − 1217 half_width = width/2;
+ − 1218
+ − 1219 if (enabled)
+ − 1220 {
+ − 1221 top_gc = mw->menu.shadow_bottom_gc;
+ − 1222 bottom_gc = mw->menu.shadow_top_gc;
+ − 1223 }
+ − 1224 else
+ − 1225 {
+ − 1226 top_gc = mw->menu.shadow_top_gc;
+ − 1227 bottom_gc = mw->menu.shadow_bottom_gc;
+ − 1228 }
+ − 1229
+ − 1230 #if 1
+ − 1231 /* Draw the bottom first, just in case the regions overlap.
+ − 1232 The top should cast the longer shadow. */
+ − 1233 points [0].x = x; /* left corner */
+ − 1234 points [0].y = y + half_width;
+ − 1235 points [1].x = x + half_width; /* bottom corner */
+ − 1236 points [1].y = y + width;
+ − 1237 points [2].x = x + half_width; /* bottom inside corner */
+ − 1238 points [2].y = y + width - thickness;
+ − 1239 points [3].x = x + thickness; /* left inside corner */
+ − 1240 points [3].y = y + half_width;
+ − 1241
+ − 1242 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
+ − 1243
+ − 1244 points [0].x = x + half_width; /* bottom corner */
+ − 1245 points [0].y = y + width;
+ − 1246 points [1].x = x + width; /* right corner */
+ − 1247 points [1].y = y + half_width;
+ − 1248 points [2].x = x + width - thickness; /* right inside corner */
+ − 1249 points [2].y = y + half_width;
+ − 1250 points [3].x = x + half_width; /* bottom inside corner */
+ − 1251 points [3].y = y + width - thickness;
+ − 1252
+ − 1253 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
+ − 1254
+ − 1255 points [0].x = x; /* left corner */
+ − 1256 points [0].y = y + half_width;
+ − 1257 points [1].x = x + half_width; /* top corner */
+ − 1258 points [1].y = y;
+ − 1259 points [2].x = x + half_width; /* top inside corner */
+ − 1260 points [2].y = y + thickness;
+ − 1261 points [3].x = x + thickness; /* left inside corner */
+ − 1262 points [3].y = y + half_width;
+ − 1263
+ − 1264 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ − 1265
+ − 1266 points [0].x = x + half_width; /* top corner */
+ − 1267 points [0].y = y;
+ − 1268 points [1].x = x + width; /* right corner */
+ − 1269 points [1].y = y + half_width;
+ − 1270 points [2].x = x + width - thickness; /* right inside corner */
+ − 1271 points [2].y = y + half_width;
+ − 1272 points [3].x = x + half_width; /* top inside corner */
+ − 1273 points [3].y = y + thickness;
+ − 1274
+ − 1275 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ − 1276 #else
+ − 1277 /* Draw the bottom first, just in case the regions overlap.
+ − 1278 The top should cast the longer shadow. */
+ − 1279 npoints = 0;
+ − 1280 points [npoints].x = x; /* left corner */
+ − 1281 points [npoints++].y = y + half_width;
+ − 1282 points [npoints].x = x + half_width; /* bottom corner */
+ − 1283 points [npoints++].y = y + width;
+ − 1284 points [npoints].x = x + width; /* right corner */
+ − 1285 points [npoints++].y = y + half_width;
+ − 1286 points [npoints].x = x + width - thickness; /* right inside corner */
+ − 1287 points [npoints++].y = y + half_width;
+ − 1288 points [npoints].x = x + half_width; /* bottom inside corner */
+ − 1289 points [npoints++].y = y + width - thickness;
+ − 1290 points [npoints].x = x + thickness; /* left inside corner */
+ − 1291 points [npoints++].y = y + half_width;
+ − 1292
+ − 1293 XFillPolygon (dpy, window, bottom_gc,
+ − 1294 points, npoints, Nonconvex, CoordModeOrigin);
+ − 1295
+ − 1296 npoints = 0;
+ − 1297
+ − 1298 points [npoints].x = x; /* left corner */
+ − 1299 points [npoints++].y = y + half_width;
+ − 1300 points [npoints].x = x + half_width; /* top corner */
+ − 1301 points [npoints++].y = y;
+ − 1302 points [npoints].x = x + width; /* right corner */
+ − 1303 points [npoints++].y = y + half_width;
+ − 1304 points [npoints].x = x + width - thickness; /* right inside corner */
+ − 1305 points [npoints++].y = y + half_width;
+ − 1306 points [npoints].x = x + half_width; /* top inside corner */
+ − 1307 points [npoints++].y = y + thickness;
+ − 1308 points [npoints].x = x + thickness; /* left inside corner */
+ − 1309 points [npoints++].y = y + half_width;
+ − 1310
+ − 1311 XFillPolygon (dpy, window, top_gc, points, npoints, Nonconvex,
+ − 1312 CoordModeOrigin);
+ − 1313 #endif
+ − 1314
+ − 1315
+ − 1316 /* Fill internal area. */
+ − 1317 if (enabled)
+ − 1318 {
+ − 1319 points [0].x = x + thickness;
+ − 1320 points [0].y = y + half_width;
+ − 1321 points [1].x = x + half_width;
+ − 1322 points [1].y = y + thickness;
+ − 1323 points [2].x = x + width - thickness;
+ − 1324 points [2].y = y + half_width;
+ − 1325 points [3].x = x + half_width;
+ − 1326 points [3].y = y + width - thickness;
+ − 1327 XFillPolygon (dpy,
+ − 1328 window,
+ − 1329 select_gc,
+ − 1330 points,
+ − 1331 4,
+ − 1332 Convex,
+ − 1333 CoordModeOrigin);
+ − 1334 }
+ − 1335 }
+ − 1336
+ − 1337 static void
+ − 1338 separator_decoration_draw (XlwMenuWidget mw,
+ − 1339 Window window,
+ − 1340 int x, int y,
+ − 1341 unsigned int width,
+ − 1342 Boolean vertical,
+ − 1343 shadow_type type)
+ − 1344 {
+ − 1345 Display *dpy = XtDisplay (mw);
+ − 1346 GC top_gc;
+ − 1347 GC bottom_gc;
+ − 1348 unsigned int offset = 0;
+ − 1349 unsigned int num_separators = 1;
+ − 1350 unsigned int top_line_thickness = 0;
+ − 1351 unsigned int bottom_line_thickness = 0;
+ − 1352 Boolean dashed = False;
+ − 1353
+ − 1354 switch (type)
+ − 1355 {
+ − 1356 case SHADOW_NO_LINE: /* nothing to do */
+ − 1357 return;
+ − 1358 case SHADOW_DOUBLE_LINE:
+ − 1359 num_separators = 2;
+ − 1360 case SHADOW_SINGLE_LINE:
+ − 1361 top_gc = bottom_gc = mw->menu.foreground_gc;
+ − 1362 top_line_thickness = 1;
+ − 1363 break;
+ − 1364 case SHADOW_DOUBLE_DASHED_LINE:
+ − 1365 num_separators = 2;
+ − 1366 case SHADOW_SINGLE_DASHED_LINE:
+ − 1367 top_gc = bottom_gc = mw->menu.foreground_gc;
+ − 1368 top_line_thickness = 1;
+ − 1369 dashed = True;
+ − 1370 break;
+ − 1371 case SHADOW_DOUBLE_ETCHED_OUT_DASH:
+ − 1372 num_separators = 2;
+ − 1373 case SHADOW_ETCHED_OUT_DASH:
+ − 1374 top_gc = mw->menu.shadow_top_gc;
+ − 1375 bottom_gc = mw->menu.shadow_bottom_gc;
+ − 1376 top_line_thickness = mw->menu.shadow_thickness/2;
+ − 1377 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
+ − 1378 dashed = True;
+ − 1379 break;
+ − 1380 case SHADOW_DOUBLE_ETCHED_IN_DASH:
+ − 1381 num_separators = 2;
+ − 1382 case SHADOW_ETCHED_IN_DASH:
+ − 1383 top_gc = mw->menu.shadow_bottom_gc;
+ − 1384 bottom_gc = mw->menu.shadow_top_gc;
+ − 1385 top_line_thickness = mw->menu.shadow_thickness/2;
+ − 1386 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
+ − 1387 dashed = True;
+ − 1388 break;
+ − 1389 case SHADOW_DOUBLE_ETCHED_OUT:
+ − 1390 num_separators = 2;
+ − 1391 case SHADOW_ETCHED_OUT:
+ − 1392 top_gc = mw->menu.shadow_top_gc;
+ − 1393 bottom_gc = mw->menu.shadow_bottom_gc;
+ − 1394 top_line_thickness = mw->menu.shadow_thickness/2;
+ − 1395 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
+ − 1396 break;
+ − 1397 case SHADOW_DOUBLE_ETCHED_IN:
+ − 1398 num_separators = 2;
+ − 1399 case SHADOW_ETCHED_IN:
+ − 1400 default:
+ − 1401 top_gc = mw->menu.shadow_bottom_gc;
+ − 1402 bottom_gc = mw->menu.shadow_top_gc;
+ − 1403 top_line_thickness = mw->menu.shadow_thickness/2;
+ − 1404 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
+ − 1405 break;
+ − 1406 }
+ − 1407
+ − 1408 if (dashed)
+ − 1409 {
+ − 1410 XGCValues values;
+ − 1411 values.line_style = LineOnOffDash;
+ − 1412 if (top_line_thickness > 0)
+ − 1413 XChangeGC (dpy, top_gc, GCLineStyle, &values);
+ − 1414 if (bottom_line_thickness > 0 && bottom_gc != top_gc)
+ − 1415 XChangeGC (dpy, bottom_gc, GCLineStyle, &values);
+ − 1416 }
+ − 1417
+ − 1418 while (num_separators--)
+ − 1419 {
+ − 1420 unsigned int i;
+ − 1421 for (i = 0; i < top_line_thickness; i++)
+ − 1422 XDrawLine (dpy, window, top_gc, x, y + i, x + width, y + i);
+ − 1423
+ − 1424 for (i = 0; i < bottom_line_thickness; i++)
+ − 1425 XDrawLine (dpy, window, bottom_gc,
+ − 1426 x, y + top_line_thickness + offset + i,
+ − 1427 x + width, y + top_line_thickness + offset + i);
+ − 1428 y += (top_line_thickness + offset + bottom_line_thickness + 1);
+ − 1429 }
+ − 1430
+ − 1431 if (dashed)
+ − 1432 {
+ − 1433 XGCValues values;
+ − 1434 values.line_style = LineSolid;
+ − 1435 if (top_line_thickness > 0)
+ − 1436 XChangeGC (dpy, top_gc, GCLineStyle, &values);
+ − 1437 if (bottom_line_thickness > 0 && bottom_gc != top_gc)
+ − 1438 XChangeGC (dpy, bottom_gc, GCLineStyle, &values);
+ − 1439 }
+ − 1440 }
+ − 1441
+ − 1442 #define SLOPPY_TYPES 0 /* 0=off, 1=error check, 2=easy to please */
+ − 1443 #if SLOPPY_TYPES
+ − 1444 #if SLOPPY_TYPES < 2
+ − 1445
+ − 1446 static char *wv_types[] =
+ − 1447 {
+ − 1448 "UNSPECIFIED",
+ − 1449 "BUTTON",
+ − 1450 "TOGGLE",
+ − 1451 "RADIO",
+ − 1452 "TEXT",
+ − 1453 "SEPARATOR",
+ − 1454 "CASCADE",
+ − 1455 "PUSHRIGHT",
+ − 1456 "INCREMENTAL"
+ − 1457 };
+ − 1458
+ − 1459 static void
+ − 1460 print_widget_value (widget_value *wv, int just_one, int depth)
+ − 1461 {
+ − 1462 char d [200];
+ − 1463 int i;
+ − 1464 for (i = 0; i < depth; i++)
+ − 1465 d[i] = ' ';
+ − 1466 d[depth]=0;
+ − 1467 if (!wv)
+ − 1468 {
+ − 1469 printf ("%s(null widget value pointer)\n", d);
+ − 1470 return;
+ − 1471 }
+ − 1472 printf ("%stype: %s\n", d, wv_types [wv->type]);
+ − 1473 #if 0
+ − 1474 printf ("%sname: %s\n", d, (wv->name ? wv->name : "(null)"));
+ − 1475 #else
+ − 1476 if (wv->name) printf ("%sname: %s\n", d, wv->name);
+ − 1477 #endif
+ − 1478 if (wv->value) printf ("%svalue: %s\n", d, wv->value);
+ − 1479 if (wv->key) printf ("%skey: %s\n", d, wv->key);
+ − 1480 printf ("%senabled: %d\n", d, wv->enabled);
+ − 1481 if (wv->contents)
+ − 1482 {
+ − 1483 printf ("\n%scontents: \n", d);
+ − 1484 print_widget_value (wv->contents, 0, depth + 5);
+ − 1485 }
+ − 1486 if (!just_one && wv->next)
+ − 1487 {
+ − 1488 printf ("\n");
+ − 1489 print_widget_value (wv->next, 0, depth);
+ − 1490 }
+ − 1491 }
+ − 1492 #endif /* SLOPPY_TYPES < 2 */
+ − 1493
+ − 1494 static Boolean
+ − 1495 all_dashes_p (char *s)
+ − 1496 {
+ − 1497 char *p;
+ − 1498 if (!s || s[0] == '\0')
+ − 1499 return False;
+ − 1500 for (p = s; *p == '-'; p++);
+ − 1501
+ − 1502 if (*p == '!' || *p == '\0')
+ − 1503 return True;
+ − 1504 return False;
+ − 1505 }
+ − 1506 #endif /* SLOPPY_TYPES */
+ − 1507
+ − 1508 static widget_value_type
+ − 1509 menu_item_type (widget_value *val)
+ − 1510 {
+ − 1511 if (val->type != UNSPECIFIED_TYPE)
+ − 1512 return val->type;
+ − 1513 #if SLOPPY_TYPES
+ − 1514 else if (all_dashes_p (val->name))
+ − 1515 return SEPARATOR_TYPE;
+ − 1516 else if (val->name && val->name[0] == '\0') /* push right */
+ − 1517 return PUSHRIGHT_TYPE;
+ − 1518 else if (val->contents) /* cascade */
+ − 1519 return CASCADE_TYPE;
+ − 1520 else if (val->call_data) /* push button */
+ − 1521 return BUTTON_TYPE;
+ − 1522 else
+ − 1523 return TEXT_TYPE;
+ − 1524 #else
442
+ − 1525 else
428
+ − 1526 abort();
+ − 1527 return UNSPECIFIED_TYPE; /* Not reached */
+ − 1528 #endif
+ − 1529 }
+ − 1530
+ − 1531 static void
+ − 1532 label_button_size (XlwMenuWidget mw,
+ − 1533 widget_value *val,
+ − 1534 Boolean in_menubar,
+ − 1535 unsigned int *toggle_width,
+ − 1536 unsigned int *label_width,
+ − 1537 unsigned int *bindings_width,
+ − 1538 unsigned int *height)
+ − 1539 {
+ − 1540 *height = (mw->menu.font_ascent + mw->menu.font_descent +
+ − 1541 2 * mw->menu.vertical_margin +
+ − 1542 2 * mw->menu.shadow_thickness);
+ − 1543 /* no left column decoration */
430
+ − 1544 *toggle_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness;
428
+ − 1545
+ − 1546 *label_width = string_width_u (mw, resource_widget_value (mw, val));
+ − 1547 *bindings_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness;
+ − 1548 }
+ − 1549
+ − 1550 static void
+ − 1551 label_button_draw (XlwMenuWidget mw,
+ − 1552 widget_value *val,
+ − 1553 Boolean in_menubar,
+ − 1554 Boolean highlighted,
+ − 1555 Window window,
+ − 1556 int x, int y,
+ − 1557 unsigned int width,
+ − 1558 unsigned int height,
+ − 1559 unsigned int label_offset,
+ − 1560 unsigned int binding_tab)
+ − 1561 {
+ − 1562 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
+ − 1563 GC gc;
+ − 1564
+ − 1565 if (!label_offset)
+ − 1566 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
+ − 1567
+ − 1568 if (highlighted && (in_menubar || val->contents))
+ − 1569 gc = mw->menu.highlight_gc;
+ − 1570 else if (in_menubar || val->contents)
+ − 1571 gc = mw->menu.foreground_gc;
+ − 1572 else
+ − 1573 gc = mw->menu.title_gc;
+ − 1574
+ − 1575 /* Draw the label string. */
+ − 1576 string_draw_u (mw,
+ − 1577 window,
+ − 1578 x + label_offset, y + y_offset,
+ − 1579 gc,
+ − 1580 resource_widget_value (mw, val));
+ − 1581 }
+ − 1582
+ − 1583 static void
+ − 1584 push_button_size (XlwMenuWidget mw,
+ − 1585 widget_value *val,
+ − 1586 Boolean in_menubar,
+ − 1587 unsigned int *toggle_width,
+ − 1588 unsigned int *label_width,
+ − 1589 unsigned int *bindings_width,
+ − 1590 unsigned int *height)
+ − 1591 {
+ − 1592 /* inherit */
+ − 1593 label_button_size (mw, val, in_menubar,
+ − 1594 toggle_width, label_width, bindings_width,
+ − 1595 height);
+ − 1596
+ − 1597 /* key bindings to display? */
+ − 1598 if (!in_menubar && val->key)
+ − 1599 {
+ − 1600 int w;
+ − 1601 #ifdef NEED_MOTIF
+ − 1602 XmString key = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
+ − 1603 w = string_width (mw, key);
+ − 1604 XmStringFree (key);
+ − 1605 #else
+ − 1606 char *key = val->key;
+ − 1607 w = string_width (mw, key);
+ − 1608 #endif
+ − 1609 *bindings_width += w + mw->menu.column_spacing;
+ − 1610 }
+ − 1611 }
+ − 1612
+ − 1613 static void
+ − 1614 push_button_draw (XlwMenuWidget mw,
+ − 1615 widget_value *val,
+ − 1616 Boolean in_menubar,
+ − 1617 Boolean highlighted,
+ − 1618 Window window,
+ − 1619 int x, int y,
+ − 1620 unsigned int width,
+ − 1621 unsigned int height,
+ − 1622 unsigned int label_offset,
+ − 1623 unsigned int binding_offset)
+ − 1624 {
+ − 1625 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
+ − 1626 GC gc;
+ − 1627 shadow_type type;
+ − 1628 Boolean menu_pb = in_menubar && (menu_item_type (val) == BUTTON_TYPE);
+ − 1629
+ − 1630 /* Draw the label string. */
+ − 1631 if (!label_offset)
+ − 1632 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
+ − 1633
+ − 1634 if (highlighted)
+ − 1635 {
+ − 1636 if (val->enabled)
+ − 1637 gc = mw->menu.highlight_gc;
+ − 1638 else
+ − 1639 gc = mw->menu.inactive_gc;
+ − 1640 }
+ − 1641 else if (menu_pb)
+ − 1642 {
+ − 1643 if (val->enabled)
+ − 1644 gc = mw->menu.button_gc;
+ − 1645 else
+ − 1646 gc = mw->menu.inactive_button_gc;
+ − 1647 }
+ − 1648 else
+ − 1649 {
+ − 1650 if (val->enabled)
+ − 1651 gc = mw->menu.foreground_gc;
+ − 1652 else
+ − 1653 gc = mw->menu.inactive_gc;
+ − 1654 }
+ − 1655
+ − 1656 string_draw_u (mw,
+ − 1657 window,
+ − 1658 x + label_offset, y + y_offset,
+ − 1659 gc,
+ − 1660 resource_widget_value (mw, val));
+ − 1661
+ − 1662 /* Draw the keybindings */
+ − 1663 if (val->key)
+ − 1664 {
+ − 1665 if (!binding_offset)
+ − 1666 {
+ − 1667 unsigned int s_width =
+ − 1668 string_width (mw, resource_widget_value (mw, val));
+ − 1669 binding_offset = label_offset + s_width + mw->menu.shadow_thickness;
+ − 1670 }
+ − 1671 binding_draw (mw, window,
+ − 1672 x + binding_offset + mw->menu.column_spacing,
+ − 1673 y + y_offset, gc, val->key);
+ − 1674 }
+ − 1675
+ − 1676 /* Draw the shadow */
+ − 1677 if (menu_pb)
+ − 1678 {
+ − 1679 if (highlighted)
+ − 1680 type = SHADOW_OUT;
+ − 1681 else
+ − 1682 type = (val->selected ? SHADOW_ETCHED_OUT : SHADOW_ETCHED_IN);
+ − 1683 }
+ − 1684 else
+ − 1685 {
+ − 1686 if (highlighted)
+ − 1687 type = SHADOW_OUT;
+ − 1688 else
+ − 1689 type = SHADOW_BACKGROUND;
+ − 1690 }
+ − 1691
+ − 1692 shadow_draw (mw, window, x, y, width, height, type);
+ − 1693 }
+ − 1694
+ − 1695 static unsigned int
+ − 1696 arrow_decoration_height (XlwMenuWidget mw)
+ − 1697 {
+ − 1698 int result = (mw->menu.font_ascent + mw->menu.font_descent) / 2;
+ − 1699
+ − 1700 result += 2 * mw->menu.shadow_thickness;
+ − 1701
+ − 1702 if (result > (mw->menu.font_ascent + mw->menu.font_descent))
+ − 1703 result = mw->menu.font_ascent + mw->menu.font_descent;
+ − 1704
+ − 1705 return result;
+ − 1706 }
+ − 1707
+ − 1708 static void
+ − 1709 cascade_button_size (XlwMenuWidget mw,
+ − 1710 widget_value *val,
+ − 1711 Boolean in_menubar,
+ − 1712 unsigned int *toggle_width,
+ − 1713 unsigned int *label_width,
+ − 1714 unsigned int *arrow_width,
+ − 1715 unsigned int *height)
+ − 1716 {
+ − 1717 /* inherit */
+ − 1718 label_button_size (mw, val, in_menubar,
+ − 1719 toggle_width, label_width, arrow_width,
+ − 1720 height);
+ − 1721 /* we have a pull aside arrow */
+ − 1722 if (!in_menubar)
+ − 1723 {
+ − 1724 *arrow_width += arrow_decoration_height (mw) + mw->menu.column_spacing;
+ − 1725 }
+ − 1726 }
+ − 1727
+ − 1728 static void
+ − 1729 cascade_button_draw (XlwMenuWidget mw,
+ − 1730 widget_value *val,
+ − 1731 Boolean in_menubar,
+ − 1732 Boolean highlighted,
+ − 1733 Window window,
+ − 1734 int x, int y,
+ − 1735 unsigned int width,
+ − 1736 unsigned int height,
+ − 1737 unsigned int label_offset,
+ − 1738 unsigned int binding_offset)
+ − 1739 {
+ − 1740 shadow_type type;
+ − 1741
+ − 1742 /* Draw the label string. */
+ − 1743 label_button_draw (mw, val, in_menubar, highlighted,
+ − 1744 window, x, y, width, height, label_offset,
+ − 1745 binding_offset);
+ − 1746
+ − 1747 /* Draw the pull aside arrow */
+ − 1748 if (!in_menubar && val->contents)
+ − 1749 {
+ − 1750 int y_offset;
+ − 1751 unsigned int arrow_height = arrow_decoration_height (mw);
+ − 1752
+ − 1753 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin +
+ − 1754 (mw->menu.font_ascent+mw->menu.font_descent - arrow_height)/2;
+ − 1755
+ − 1756 if (!binding_offset)
+ − 1757 {
+ − 1758 unsigned int s_width =
+ − 1759 string_width (mw, resource_widget_value (mw, val));
+ − 1760
+ − 1761 if (!label_offset)
+ − 1762 label_offset = mw->menu.shadow_thickness +
+ − 1763 mw->menu.horizontal_margin;
+ − 1764
+ − 1765 binding_offset = label_offset + s_width + mw->menu.shadow_thickness;
+ − 1766 }
+ − 1767
+ − 1768 arrow_decoration_draw (mw,
+ − 1769 window,
+ − 1770 x + binding_offset + mw->menu.column_spacing,
+ − 1771 y + y_offset,
+ − 1772 arrow_height,
+ − 1773 highlighted);
+ − 1774 }
+ − 1775
+ − 1776 /* Draw the shadow */
+ − 1777 if (highlighted)
+ − 1778 type = SHADOW_OUT;
+ − 1779 else
+ − 1780 type = SHADOW_BACKGROUND;
+ − 1781
+ − 1782 shadow_draw (mw, window, x, y, width, height, type);
+ − 1783 }
+ − 1784
+ − 1785 static unsigned int
+ − 1786 toggle_decoration_height (XlwMenuWidget mw)
+ − 1787 {
+ − 1788 int rv;
+ − 1789 if (mw->menu.indicator_size > 0)
+ − 1790 rv = mw->menu.indicator_size;
+ − 1791 else
+ − 1792 rv = mw->menu.font_ascent;
+ − 1793
+ − 1794 if (rv > (mw->menu.font_ascent + mw->menu.font_descent))
+ − 1795 rv = mw->menu.font_ascent + mw->menu.font_descent;
+ − 1796
+ − 1797 /* radio button can't be smaller than its border or a filling
+ − 1798 error will occur. */
+ − 1799 if (rv < 2 * mw->menu.shadow_thickness)
+ − 1800 rv = 2 * mw->menu.shadow_thickness;
+ − 1801
+ − 1802 return rv;
+ − 1803 }
+ − 1804
+ − 1805 static void
+ − 1806 toggle_button_size (XlwMenuWidget mw,
+ − 1807 widget_value *val,
+ − 1808 Boolean in_menubar,
+ − 1809 unsigned int *toggle_width,
+ − 1810 unsigned int *label_width,
+ − 1811 unsigned int *bindings_width,
+ − 1812 unsigned int *height)
+ − 1813 {
+ − 1814 /* inherit */
+ − 1815 push_button_size (mw, val, in_menubar,
+ − 1816 toggle_width, label_width, bindings_width,
+ − 1817 height);
+ − 1818 /* we have a toggle */
+ − 1819 *toggle_width += toggle_decoration_height (mw) + mw->menu.column_spacing;
+ − 1820 }
+ − 1821
+ − 1822 static void
+ − 1823 toggle_button_draw (XlwMenuWidget mw,
+ − 1824 widget_value *val,
+ − 1825 Boolean in_menubar,
+ − 1826 Boolean highlighted,
+ − 1827 Window window,
+ − 1828 int x, int y,
+ − 1829 unsigned int width,
+ − 1830 unsigned int height,
+ − 1831 unsigned int label_tab,
+ − 1832 unsigned int binding_tab)
+ − 1833 {
+ − 1834 int x_offset;
+ − 1835 int y_offset;
+ − 1836 unsigned int t_height = toggle_decoration_height (mw);
+ − 1837
+ − 1838 /* Draw a toggle. */
+ − 1839 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
+ − 1840 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
+ − 1841 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - t_height)/2;
+ − 1842
+ − 1843 toggle_decoration_draw (mw, window, x + x_offset, y + y_offset,
+ − 1844 t_height, val->selected);
+ − 1845
+ − 1846 /* Draw the pushbutton parts. */
+ − 1847 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width,
+ − 1848 height, label_tab, binding_tab);
+ − 1849 }
+ − 1850
+ − 1851 static unsigned int
+ − 1852 radio_decoration_height (XlwMenuWidget mw)
+ − 1853 {
+ − 1854 return toggle_decoration_height (mw);
+ − 1855 }
+ − 1856
+ − 1857 static void
+ − 1858 radio_button_draw (XlwMenuWidget mw,
+ − 1859 widget_value *val,
+ − 1860 Boolean in_menubar,
+ − 1861 Boolean highlighted,
+ − 1862 Window window,
+ − 1863 int x, int y,
+ − 1864 unsigned int width,
+ − 1865 unsigned int height,
+ − 1866 unsigned int label_tab,
+ − 1867 unsigned int binding_tab)
+ − 1868 {
+ − 1869 int x_offset;
+ − 1870 int y_offset;
+ − 1871 unsigned int r_height = radio_decoration_height (mw);
+ − 1872
+ − 1873 /* Draw a toggle. */
+ − 1874 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
+ − 1875 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
+ − 1876 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - r_height)/2;
+ − 1877
+ − 1878 radio_decoration_draw (mw, window, x + x_offset, y + y_offset, r_height,
+ − 1879 val->selected);
+ − 1880
+ − 1881 /* Draw the pushbutton parts. */
+ − 1882 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width,
+ − 1883 height, label_tab, binding_tab);
+ − 1884 }
+ − 1885
+ − 1886 static struct _shadow_names
+ − 1887 {
442
+ − 1888 const char * name;
428
+ − 1889 shadow_type type;
+ − 1890 } shadow_names[] =
+ − 1891 {
+ − 1892 /* Motif */
+ − 1893 { "singleLine", SHADOW_SINGLE_LINE },
+ − 1894 { "doubleLine", SHADOW_DOUBLE_LINE },
+ − 1895 { "singleDashedLine", SHADOW_SINGLE_DASHED_LINE },
+ − 1896 { "doubleDashedLine", SHADOW_DOUBLE_DASHED_LINE },
+ − 1897 { "noLine", SHADOW_NO_LINE },
+ − 1898 { "shadowEtchedIn", SHADOW_ETCHED_IN },
+ − 1899 { "shadowEtchedOut", SHADOW_ETCHED_OUT },
+ − 1900 { "shadowEtchedInDash", SHADOW_ETCHED_IN_DASH },
+ − 1901 { "shadowEtchedOutDash", SHADOW_ETCHED_OUT_DASH },
+ − 1902 /* non-Motif */
+ − 1903 { "shadowDoubleEtchedIn", SHADOW_DOUBLE_ETCHED_IN },
+ − 1904 { "shadowDoubleEtchedOut", SHADOW_DOUBLE_ETCHED_OUT },
+ − 1905 { "shadowDoubleEtchedInDash", SHADOW_DOUBLE_ETCHED_IN_DASH },
+ − 1906 { "shadowDoubleEtchedOutDash", SHADOW_DOUBLE_ETCHED_OUT_DASH }
+ − 1907 };
+ − 1908
+ − 1909 static shadow_type
+ − 1910 separator_type (char *name)
+ − 1911 {
+ − 1912 if (name)
+ − 1913 {
+ − 1914 int i;
+ − 1915 for (i = 0; i < (int) (XtNumber (shadow_names)); i++ )
+ − 1916 {
+ − 1917 if (strcmp (name, shadow_names[i].name) == 0)
+ − 1918 return shadow_names[i].type;
+ − 1919 }
+ − 1920 }
+ − 1921 return SHADOW_BACKGROUND;
+ − 1922 }
+ − 1923
+ − 1924 static unsigned int
+ − 1925 separator_decoration_height (XlwMenuWidget mw, widget_value *val)
+ − 1926 {
+ − 1927
+ − 1928 switch (separator_type (val->value))
+ − 1929 {
+ − 1930 case SHADOW_NO_LINE:
+ − 1931 case SHADOW_SINGLE_LINE:
+ − 1932 case SHADOW_SINGLE_DASHED_LINE:
+ − 1933 return 1;
+ − 1934 case SHADOW_DOUBLE_LINE:
+ − 1935 case SHADOW_DOUBLE_DASHED_LINE:
+ − 1936 return 3;
+ − 1937 case SHADOW_DOUBLE_ETCHED_OUT:
+ − 1938 case SHADOW_DOUBLE_ETCHED_IN:
+ − 1939 case SHADOW_DOUBLE_ETCHED_OUT_DASH:
+ − 1940 case SHADOW_DOUBLE_ETCHED_IN_DASH:
+ − 1941 return (1 + 2 * mw->menu.shadow_thickness);
+ − 1942 case SHADOW_ETCHED_OUT:
+ − 1943 case SHADOW_ETCHED_IN:
+ − 1944 default:
+ − 1945 return mw->menu.shadow_thickness;
+ − 1946 }
+ − 1947 }
+ − 1948
+ − 1949 static void
+ − 1950 separator_size (XlwMenuWidget mw,
+ − 1951 widget_value *val,
+ − 1952 Boolean in_menubar,
+ − 1953 unsigned int *toggle_width,
+ − 1954 unsigned int *label_width,
+ − 1955 unsigned int *rest_width,
+ − 1956 unsigned int *height)
+ − 1957 {
+ − 1958 *height = separator_decoration_height (mw, val);
+ − 1959 *label_width = 1;
+ − 1960 *toggle_width = *rest_width = 0;
+ − 1961 }
+ − 1962
+ − 1963 static void
+ − 1964 separator_draw (XlwMenuWidget mw,
+ − 1965 widget_value *val,
+ − 1966 Boolean in_menubar,
+ − 1967 Boolean highlighted,
+ − 1968 Window window,
+ − 1969 int x, int y,
+ − 1970 unsigned int width,
+ − 1971 unsigned int height,
+ − 1972 unsigned int label_tab,
+ − 1973 unsigned int binding_tab)
+ − 1974 {
+ − 1975 unsigned int sep_width;
+ − 1976
+ − 1977 if (in_menubar)
+ − 1978 sep_width = height;
+ − 1979 else
+ − 1980 sep_width = width;
+ − 1981
+ − 1982 separator_decoration_draw (mw,
+ − 1983 window,
+ − 1984 x,
+ − 1985 y,
+ − 1986 sep_width,
+ − 1987 in_menubar,
+ − 1988 separator_type(val->value));
+ − 1989 }
+ − 1990
+ − 1991 static void
+ − 1992 pushright_size (XlwMenuWidget mw,
+ − 1993 widget_value *val,
+ − 1994 Boolean in_menubar,
+ − 1995 unsigned int *toggle_width,
+ − 1996 unsigned int *label_width,
+ − 1997 unsigned int *rest_width,
+ − 1998 unsigned int *height)
+ − 1999 {
+ − 2000 *height = *label_width = *toggle_width = *rest_width = 0;
+ − 2001 }
+ − 2002
+ − 2003 static void
+ − 2004 size_menu_item (XlwMenuWidget mw,
+ − 2005 widget_value *val,
+ − 2006 int horizontal,
+ − 2007 unsigned int *toggle_width,
+ − 2008 unsigned int *label_width,
+ − 2009 unsigned int *rest_width,
+ − 2010 unsigned int *height)
+ − 2011 {
+ − 2012 void (*function_ptr) (XlwMenuWidget _mw,
+ − 2013 widget_value *_val,
+ − 2014 Boolean _in_menubar,
+ − 2015 unsigned int *_toggle_width,
+ − 2016 unsigned int *_label_width,
+ − 2017 unsigned int *_rest_width,
+ − 2018 unsigned int *_height);
+ − 2019
+ − 2020 switch (menu_item_type (val))
+ − 2021 {
+ − 2022 case TOGGLE_TYPE:
+ − 2023 case RADIO_TYPE:
+ − 2024 function_ptr = toggle_button_size;
+ − 2025 break;
+ − 2026 case SEPARATOR_TYPE:
+ − 2027 function_ptr = separator_size;
+ − 2028 break;
+ − 2029 case INCREMENTAL_TYPE:
+ − 2030 case CASCADE_TYPE:
+ − 2031 function_ptr = cascade_button_size;
+ − 2032 break;
+ − 2033 case BUTTON_TYPE:
+ − 2034 function_ptr = push_button_size;
+ − 2035 break;
+ − 2036 case PUSHRIGHT_TYPE:
+ − 2037 function_ptr = pushright_size;
+ − 2038 break;
+ − 2039 case TEXT_TYPE:
+ − 2040 default:
+ − 2041 function_ptr = label_button_size;
+ − 2042 break;
+ − 2043 }
+ − 2044
+ − 2045 (*function_ptr) (mw,
+ − 2046 val,
+ − 2047 horizontal,
+ − 2048 toggle_width,
+ − 2049 label_width,
+ − 2050 rest_width,
+ − 2051 height);
+ − 2052 }
+ − 2053
+ − 2054 static void
+ − 2055 display_menu_item (XlwMenuWidget mw,
+ − 2056 widget_value *val,
+ − 2057 window_state *ws,
+ − 2058 XPoint *where,
+ − 2059 Boolean highlighted,
+ − 2060 Boolean horizontal,
+ − 2061 Boolean just_compute)
+ − 2062 {
+ − 2063
+ − 2064 int x = where->x /* + mw->menu.shadow_thickness */ ;
+ − 2065 int y = where->y /* + mw->menu.shadow_thickness */ ;
+ − 2066 unsigned int toggle_width;
+ − 2067 unsigned int label_width;
+ − 2068 unsigned int binding_width;
+ − 2069 unsigned int width;
+ − 2070 unsigned int height;
+ − 2071 unsigned int label_tab;
+ − 2072 unsigned int binding_tab;
+ − 2073 void (*function_ptr) (XlwMenuWidget _mw,
+ − 2074 widget_value *_val,
+ − 2075 Boolean _in_menubar,
+ − 2076 Boolean _highlighted,
+ − 2077 Window _window,
+ − 2078 int _x, int _y,
+ − 2079 unsigned int _width,
+ − 2080 unsigned int _height,
+ − 2081 unsigned int _label_tab,
+ − 2082 unsigned int _binding_tab);
+ − 2083
+ − 2084 size_menu_item (mw, val, horizontal,
+ − 2085 &toggle_width, &label_width, &binding_width, &height);
+ − 2086
+ − 2087 if (horizontal)
+ − 2088 {
+ − 2089 width = toggle_width + label_width + binding_width;
+ − 2090 height = ws->height - 2 * mw->menu.shadow_thickness;
+ − 2091 }
+ − 2092 else
+ − 2093 {
+ − 2094 width = ws->width - 2 * mw->menu.shadow_thickness;
+ − 2095 toggle_width = ws->toggle_width;
+ − 2096 label_width = ws->label_width;
+ − 2097 }
+ − 2098
+ − 2099 where->x += width;
+ − 2100 where->y += height;
+ − 2101
+ − 2102 if (just_compute)
+ − 2103 return;
+ − 2104
+ − 2105 label_tab = toggle_width;
+ − 2106 binding_tab = toggle_width + label_width;
+ − 2107
+ − 2108 switch (menu_item_type (val))
+ − 2109 {
+ − 2110 case TOGGLE_TYPE:
+ − 2111 function_ptr = toggle_button_draw;
+ − 2112 break;
+ − 2113 case RADIO_TYPE:
+ − 2114 function_ptr = radio_button_draw;
+ − 2115 break;
+ − 2116 case SEPARATOR_TYPE:
+ − 2117 function_ptr = separator_draw;
+ − 2118 break;
+ − 2119 case INCREMENTAL_TYPE:
+ − 2120 case CASCADE_TYPE:
+ − 2121 function_ptr = cascade_button_draw;
+ − 2122 break;
+ − 2123 case BUTTON_TYPE:
+ − 2124 function_ptr = push_button_draw;
+ − 2125 break;
+ − 2126 case TEXT_TYPE:
+ − 2127 function_ptr = label_button_draw;
+ − 2128 break;
+ − 2129 default: /* do no drawing */
+ − 2130 return;
+ − 2131 }
+ − 2132
+ − 2133 (*function_ptr) (mw,
+ − 2134 val,
+ − 2135 horizontal,
+ − 2136 highlighted,
+ − 2137 ws->window,
+ − 2138 x, y,
+ − 2139 width, height,
+ − 2140 label_tab,
+ − 2141 binding_tab);
+ − 2142 }
+ − 2143
+ − 2144 static void
+ − 2145 size_menu (XlwMenuWidget mw, int level)
+ − 2146 {
+ − 2147 unsigned int toggle_width;
+ − 2148 unsigned int label_width;
+ − 2149 unsigned int rest_width;
+ − 2150 unsigned int height;
+ − 2151 unsigned int max_toggle_width = 0;
+ − 2152 unsigned int max_label_width = 0;
+ − 2153 unsigned int max_rest_width = 0;
+ − 2154 unsigned int max_height = 0;
+ − 2155 int horizontal_p = mw->menu.horizontal && (level == 0);
+ − 2156 widget_value* val;
+ − 2157 window_state* ws;
+ − 2158
+ − 2159 if (level >= mw->menu.old_depth)
+ − 2160 abort ();
+ − 2161
+ − 2162 ws = &mw->menu.windows [level];
+ − 2163
+ − 2164 for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
+ − 2165 {
+ − 2166 size_menu_item (mw,
+ − 2167 val,
+ − 2168 horizontal_p,
+ − 2169 &toggle_width,
+ − 2170 &label_width,
+ − 2171 &rest_width,
+ − 2172 &height);
+ − 2173 if (horizontal_p)
+ − 2174 {
+ − 2175 max_label_width += toggle_width + label_width + rest_width;
+ − 2176 if (height > max_height)
+ − 2177 max_height = height;
+ − 2178 }
+ − 2179 else
+ − 2180 {
+ − 2181 if (max_toggle_width < toggle_width)
+ − 2182 max_toggle_width = toggle_width;
+ − 2183 if (max_label_width < label_width)
+ − 2184 max_label_width = label_width;
+ − 2185 if (max_rest_width < rest_width)
+ − 2186 max_rest_width = rest_width;
+ − 2187 max_height += height;
+ − 2188 }
+ − 2189 }
+ − 2190
+ − 2191 ws->height = max_height;
+ − 2192 ws->width = max_label_width + max_rest_width + max_toggle_width;
+ − 2193 ws->toggle_width = max_toggle_width;
+ − 2194 ws->label_width = max_label_width;
+ − 2195
+ − 2196 ws->width += 2 * mw->menu.shadow_thickness;
+ − 2197 ws->height += 2 * mw->menu.shadow_thickness;
+ − 2198 }
+ − 2199
+ − 2200 static void
+ − 2201 display_menu (XlwMenuWidget mw, int level, Boolean just_compute_p,
+ − 2202 XPoint *highlighted_pos, XPoint *hit, widget_value **hit_return,
+ − 2203 widget_value *this, widget_value *that)
+ − 2204 {
+ − 2205 widget_value *val;
+ − 2206 widget_value *following_item;
+ − 2207 window_state *ws;
+ − 2208 XPoint where;
+ − 2209 int horizontal_p = mw->menu.horizontal && (level == 0);
+ − 2210 int highlighted_p;
+ − 2211 int just_compute_this_one_p;
+ − 2212
+ − 2213 if (level >= mw->menu.old_depth)
+ − 2214 abort ();
+ − 2215
+ − 2216 if (level < mw->menu.old_depth - 1)
+ − 2217 following_item = mw->menu.old_stack [level + 1];
+ − 2218 else
+ − 2219 {
+ − 2220 if (lw_menu_accelerate
+ − 2221 && level == mw->menu.old_depth - 1
+ − 2222 && mw->menu.old_stack [level]->type == CASCADE_TYPE)
+ − 2223 just_compute_p = True;
+ − 2224 following_item = NULL;
+ − 2225 }
+ − 2226
+ − 2227 #if SLOPPY_TYPES == 1
+ − 2228 puts("===================================================================");
+ − 2229 print_widget_value (following_item, 1, 0);
+ − 2230 #endif
+ − 2231
+ − 2232 if (hit)
+ − 2233 *hit_return = NULL;
+ − 2234
+ − 2235 where.x = mw->menu.shadow_thickness;
+ − 2236 where.y = mw->menu.shadow_thickness;
+ − 2237
+ − 2238 ws = &mw->menu.windows [level];
+ − 2239 for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
+ − 2240 {
+ − 2241 XPoint start;
+ − 2242
+ − 2243 highlighted_p = (val == following_item);
+ − 2244 /* If this is the partition (the dummy item which says that menus
+ − 2245 after this should be flushright) then figure out how big the
+ − 2246 following items are. This means we walk down the tail of the
+ − 2247 list twice, but that's no big deal - it's short.
+ − 2248 */
+ − 2249 if (horizontal_p && (menu_item_type (val) == PUSHRIGHT_TYPE))
+ − 2250 {
+ − 2251 widget_value *rest;
+ − 2252 XPoint flushright_size;
+ − 2253 int new_x;
+ − 2254 flushright_size.x = 0;
+ − 2255 flushright_size.y = 0;
+ − 2256 for (rest = val; rest; rest = rest->next)
+ − 2257 display_menu_item (mw, rest, ws, &flushright_size,
+ − 2258 highlighted_p, horizontal_p, True);
+ − 2259 new_x = ws->width - (flushright_size.x + mw->menu.shadow_thickness);
+ − 2260 if (new_x > where.x)
+ − 2261 where.x = new_x;
+ − 2262 /* We know what we need; don't draw this item. */
+ − 2263 continue;
+ − 2264 }
+ − 2265
+ − 2266 if (highlighted_p && highlighted_pos)
+ − 2267 {
+ − 2268 if (horizontal_p)
+ − 2269 highlighted_pos->x = where.x;
+ − 2270 else
+ − 2271 highlighted_pos->y = where.y;
+ − 2272 }
+ − 2273
+ − 2274 just_compute_this_one_p =
+ − 2275 just_compute_p || ((this || that) && val != this && val != that);
+ − 2276
+ − 2277 start.x = where.x;
+ − 2278 start.y = where.y;
+ − 2279 display_menu_item (mw, val, ws, &where, highlighted_p, horizontal_p,
+ − 2280 just_compute_this_one_p);
+ − 2281
+ − 2282 if (highlighted_p && highlighted_pos)
+ − 2283 {
+ − 2284 if (horizontal_p)
+ − 2285 highlighted_pos->y = ws->height;
+ − 2286 else
+ − 2287 highlighted_pos->x = ws->width;
+ − 2288 }
+ − 2289
+ − 2290 if (hit && !*hit_return)
+ − 2291 {
+ − 2292 if (horizontal_p && hit->x > start.x && hit->x <= where.x)
+ − 2293 *hit_return = val;
+ − 2294 else if (!horizontal_p && hit->y > start.y && hit->y <= where.y)
+ − 2295 *hit_return = val;
+ − 2296 }
+ − 2297
+ − 2298 if (horizontal_p)
+ − 2299 where.y = mw->menu.shadow_thickness;
+ − 2300 else
+ − 2301 where.x = mw->menu.shadow_thickness;
+ − 2302 }
+ − 2303
+ − 2304 /* Draw slab edges around menu */
+ − 2305 if (!just_compute_p)
+ − 2306 shadow_draw(mw, ws->window, 0, 0, ws->width, ws->height, SHADOW_OUT);
+ − 2307 }
+ − 2308
+ − 2309 /* Motion code */
+ − 2310 static void
+ − 2311 set_new_state (XlwMenuWidget mw, widget_value *val, int level)
+ − 2312 {
+ − 2313 int i;
+ − 2314
+ − 2315 mw->menu.new_depth = 0;
+ − 2316 for (i = 0; i < level; i++)
+ − 2317 push_new_stack (mw, mw->menu.old_stack [i]);
+ − 2318 if (val)
+ − 2319 push_new_stack (mw, val);
+ − 2320 }
+ − 2321
+ − 2322 static void
+ − 2323 make_windows_if_needed (XlwMenuWidget mw, int n)
+ − 2324 {
+ − 2325 int i;
+ − 2326 int start_at;
+ − 2327 XSetWindowAttributes xswa;
+ − 2328 Widget p;
446
+ − 2329 unsigned long mask;
428
+ − 2330 int depth;
+ − 2331 Visual *visual;
+ − 2332 window_state *windows;
+ − 2333 Window root;
+ − 2334
+ − 2335 if (mw->menu.windows_length >= n)
+ − 2336 return;
+ − 2337
+ − 2338 root = RootWindowOfScreen (XtScreen(mw));
+ − 2339 /* grab the visual and depth from the nearest shell ancestor */
+ − 2340 visual = CopyFromParent;
+ − 2341 depth = CopyFromParent;
+ − 2342 p = XtParent(mw);
+ − 2343 while (visual == CopyFromParent && p)
+ − 2344 {
+ − 2345 if (XtIsShell(p))
+ − 2346 {
+ − 2347 visual = ((ShellWidget)p)->shell.visual;
+ − 2348 depth = p->core.depth;
+ − 2349 }
+ − 2350 p = XtParent(p);
+ − 2351 }
+ − 2352
+ − 2353 xswa.save_under = True;
+ − 2354 xswa.override_redirect = True;
+ − 2355 xswa.background_pixel = mw->core.background_pixel;
+ − 2356 xswa.border_pixel = mw->core.border_pixel;
+ − 2357 xswa.event_mask = (ExposureMask | ButtonMotionMask
+ − 2358 | ButtonReleaseMask | ButtonPressMask);
+ − 2359 xswa.cursor = mw->menu.cursor_shape;
+ − 2360 xswa.colormap = mw->core.colormap;
+ − 2361 mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel
+ − 2362 | CWEventMask | CWCursor | CWColormap;
+ − 2363
+ − 2364 if (mw->menu.use_backing_store)
+ − 2365 {
+ − 2366 xswa.backing_store = Always;
+ − 2367 mask |= CWBackingStore;
+ − 2368 }
+ − 2369
+ − 2370 if (!mw->menu.windows)
+ − 2371 {
+ − 2372 mw->menu.windows =
+ − 2373 (window_state *) XtMalloc (n * sizeof (window_state));
+ − 2374 start_at = 0;
+ − 2375 }
+ − 2376 else
+ − 2377 {
+ − 2378 mw->menu.windows =
+ − 2379 (window_state *) XtRealloc ((char *) mw->menu.windows,
+ − 2380 n * sizeof (window_state));
+ − 2381 start_at = mw->menu.windows_length;
+ − 2382 }
+ − 2383 mw->menu.windows_length = n;
+ − 2384
+ − 2385 windows = mw->menu.windows;
+ − 2386
+ − 2387 for (i = start_at; i < n; i++)
+ − 2388 {
+ − 2389 windows [i].x = 0;
+ − 2390 windows [i].y = 0;
+ − 2391 windows [i].width = 1;
+ − 2392 windows [i].height = 1;
+ − 2393 windows [i].window =
+ − 2394 XCreateWindow (XtDisplay (mw),
+ − 2395 root,
+ − 2396 0, 0, 1, 1,
+ − 2397 0, depth, CopyFromParent, visual, mask, &xswa);
+ − 2398 }
+ − 2399 }
+ − 2400
+ − 2401 /* Make the window fit in the screen */
+ − 2402 static void
+ − 2403 fit_to_screen (XlwMenuWidget mw, window_state *ws, window_state *previous_ws,
+ − 2404 Boolean horizontal_p)
+ − 2405 {
+ − 2406 int screen_width = WidthOfScreen (XtScreen (mw));
+ − 2407 int screen_height = HeightOfScreen (XtScreen (mw));
+ − 2408
+ − 2409 if (ws->x < 0)
+ − 2410 ws->x = 0;
+ − 2411 else if ((int) (ws->x + ws->width) > screen_width)
+ − 2412 {
+ − 2413 if (!horizontal_p)
+ − 2414 ws->x = previous_ws->x - ws->width;
+ − 2415 else
+ − 2416 {
+ − 2417 ws->x = screen_width - ws->width;
+ − 2418
+ − 2419 /* This check is to make sure we cut off the right side
+ − 2420 instead of the left side if the menu is wider than the
+ − 2421 screen. */
+ − 2422 if (ws->x < 0)
+ − 2423 ws->x = 0;
+ − 2424 }
+ − 2425 }
+ − 2426 if (ws->y < 0)
+ − 2427 ws->y = 0;
+ − 2428 else if ((int) (ws->y + ws->height) > screen_height)
+ − 2429 {
+ − 2430 if (horizontal_p)
+ − 2431 {
+ − 2432 /* A pulldown must either be entirely above or below the menubar.
+ − 2433 If we're here, the pulldown doesn't fit below the menubar, so
+ − 2434 let's determine if it will fit above the menubar.
+ − 2435 Only put it above if there is more room above than below.
+ − 2436 Note shadow_thickness offset to allow for slab surround.
+ − 2437 */
+ − 2438 if (ws->y > (screen_height / 2))
+ − 2439 ws->y = previous_ws->y - ws->height + mw->menu.shadow_thickness;
+ − 2440 }
+ − 2441 else
+ − 2442 {
+ − 2443 ws->y = screen_height - ws->height;
+ − 2444 /* if it's taller than the screen, display the topmost part
+ − 2445 that will fit, beginning at the top of the screen. */
+ − 2446 if (ws->y < 0)
+ − 2447 ws->y = 0;
+ − 2448 }
+ − 2449 }
+ − 2450 }
+ − 2451
+ − 2452 /* Updates old_stack from new_stack and redisplays. */
+ − 2453 static void
+ − 2454 remap_menubar (XlwMenuWidget mw)
+ − 2455 {
+ − 2456 int i;
+ − 2457 int last_same;
+ − 2458 XPoint selection_position;
+ − 2459 int old_depth = mw->menu.old_depth;
+ − 2460 int new_depth = mw->menu.new_depth;
+ − 2461 widget_value **old_stack;
+ − 2462 widget_value **new_stack;
+ − 2463 window_state *windows;
+ − 2464 widget_value *old_selection;
+ − 2465 widget_value *new_selection;
+ − 2466
+ − 2467 /* Check that enough windows and old_stack are ready. */
+ − 2468 make_windows_if_needed (mw, new_depth);
+ − 2469 make_old_stack_space (mw, new_depth);
+ − 2470 windows = mw->menu.windows;
+ − 2471 old_stack = mw->menu.old_stack;
+ − 2472 new_stack = mw->menu.new_stack;
+ − 2473
+ − 2474 /* compute the last identical different entry */
+ − 2475 for (i = 1; i < old_depth && i < new_depth; i++)
+ − 2476 if (old_stack [i] != new_stack [i])
+ − 2477 break;
+ − 2478 last_same = i - 1;
+ − 2479
+ − 2480 if (lw_menu_accelerate
+ − 2481 && last_same
+ − 2482 && last_same == old_depth - 1
+ − 2483 && old_stack [last_same]->contents)
+ − 2484 last_same--;
+ − 2485
+ − 2486 /* Memorize the previously selected item to be able to refresh it */
+ − 2487 old_selection = last_same + 1 < old_depth ? old_stack [last_same + 1] : NULL;
+ − 2488 new_selection = last_same + 1 < new_depth ? new_stack [last_same + 1] : NULL;
+ − 2489
+ − 2490 /* updates old_state from new_state. It has to be done now because
+ − 2491 display_menu (called below) uses the old_stack to know what to display. */
+ − 2492 for (i = last_same + 1; i < new_depth; i++)
+ − 2493 old_stack [i] = new_stack [i];
+ − 2494
+ − 2495 mw->menu.old_depth = new_depth;
+ − 2496
442
+ − 2497 /* refresh the last selection */
428
+ − 2498 selection_position.x = 0;
+ − 2499 selection_position.y = 0;
+ − 2500 display_menu (mw, last_same, new_selection == old_selection,
+ − 2501 &selection_position, NULL, NULL, old_selection, new_selection);
+ − 2502
+ − 2503 /* Now popup the new menus */
+ − 2504 for (i = last_same + 1; i < new_depth && new_stack [i]->contents; i++)
+ − 2505 {
+ − 2506 window_state *previous_ws = &windows [i - 1];
+ − 2507 window_state *ws = &windows [i];
+ − 2508
+ − 2509 if (lw_menu_accelerate && i == new_depth - 1)
+ − 2510 break;
+ − 2511
+ − 2512 ws->x = previous_ws->x + selection_position.x;
+ − 2513 ws->y = previous_ws->y + selection_position.y;
+ − 2514
+ − 2515 /* take into account the slab around the new menu */
+ − 2516 ws->y -= mw->menu.shadow_thickness;
+ − 2517
+ − 2518 {
+ − 2519 widget_value *val = mw->menu.old_stack [i];
+ − 2520 if (val->contents->type == INCREMENTAL_TYPE)
+ − 2521 {
+ − 2522 /* okay, we're now doing a lisp callback to incrementally generate
+ − 2523 more of the menu. */
+ − 2524 XtCallCallbackList ((Widget)mw,
+ − 2525 mw->menu.open,
+ − 2526 (XtPointer)val->contents);
+ − 2527 }
+ − 2528 }
+ − 2529
+ − 2530 size_menu (mw, i);
+ − 2531
+ − 2532 fit_to_screen (mw, ws, previous_ws, mw->menu.horizontal && i == 1);
+ − 2533
+ − 2534 XClearWindow (XtDisplay (mw), ws->window);
+ − 2535 XMoveResizeWindow (XtDisplay (mw), ws->window, ws->x, ws->y,
+ − 2536 ws->width, ws->height);
+ − 2537 XMapRaised (XtDisplay (mw), ws->window);
+ − 2538 display_menu (mw, i, False, &selection_position, NULL, NULL, NULL, NULL);
+ − 2539 }
+ − 2540
+ − 2541 /* unmap the menus that popped down */
+ − 2542
+ − 2543 last_same = new_depth;
+ − 2544 if (lw_menu_accelerate
+ − 2545 && last_same > 1
+ − 2546 && new_stack [last_same - 1]->contents)
+ − 2547 last_same--;
+ − 2548
+ − 2549 for (i = last_same - 1; i < old_depth; i++)
+ − 2550 if (i >= last_same || !new_stack [i]->contents)
+ − 2551 XUnmapWindow (XtDisplay (mw), windows [i].window);
+ − 2552 }
+ − 2553
+ − 2554 static Boolean
+ − 2555 motion_event_is_in_menu (XlwMenuWidget mw, XMotionEvent *ev, int level,
+ − 2556 XPoint *relative_pos)
+ − 2557 {
+ − 2558 window_state *ws = &mw->menu.windows [level];
+ − 2559 int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness;
+ − 2560 int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness;
+ − 2561 relative_pos->x = ev->x_root - x;
+ − 2562 relative_pos->y = ev->y_root - y;
+ − 2563 return (x < ev->x_root && ev->x_root < (int) (x + ws->width) &&
+ − 2564 y < ev->y_root && ev->y_root < (int) (y + ws->height));
+ − 2565 }
+ − 2566
+ − 2567 static Boolean
+ − 2568 map_event_to_widget_value (XlwMenuWidget mw, XMotionEvent *ev,
+ − 2569 widget_value **val_ptr, int *level,
+ − 2570 Boolean *inside_menu)
+ − 2571 {
+ − 2572 int i;
+ − 2573 XPoint relative_pos;
+ − 2574 window_state* ws;
+ − 2575
+ − 2576 *val_ptr = NULL;
+ − 2577 *inside_menu = False;
+ − 2578
+ − 2579 /* Find the window */
+ − 2580 #if 1
+ − 2581 for (i = mw->menu.old_depth - 1; i >= 0; i--)
+ − 2582 #else
+ − 2583 for (i = 0; i <= mw->menu.old_depth - 1; i++)
+ − 2584 #endif
+ − 2585 {
+ − 2586 ws = &mw->menu.windows [i];
+ − 2587 if (ws && motion_event_is_in_menu (mw, ev, i, &relative_pos))
+ − 2588 {
+ − 2589 *inside_menu = True; /* special logic for menubar below... */
+ − 2590 if ((ev->type == ButtonPress) ||
+ − 2591 (ev->state != 0))
+ − 2592 {
+ − 2593 display_menu (mw, i, True, NULL, &relative_pos,
+ − 2594 val_ptr, NULL, NULL);
+ − 2595 if (*val_ptr)
+ − 2596 {
+ − 2597 *level = i + 1;
+ − 2598 *inside_menu = True;
+ − 2599 return True;
+ − 2600 }
+ − 2601 else if (mw->menu.horizontal || i == 0)
+ − 2602 {
+ − 2603 /* if we're clicking on empty part of the menubar, then
+ − 2604 unpost the stay-up menu */
+ − 2605 *inside_menu = False;
+ − 2606 }
+ − 2607 }
+ − 2608 }
+ − 2609 }
+ − 2610 return False;
+ − 2611 }
+ − 2612
+ − 2613 /* Procedures */
+ − 2614 static void
+ − 2615 make_drawing_gcs (XlwMenuWidget mw)
+ − 2616 {
+ − 2617 XGCValues xgcv;
+ − 2618 unsigned long flags = (GCFont | GCForeground | GCBackground);
+ − 2619
+ − 2620 #ifdef NEED_MOTIF
+ − 2621 xgcv.font = default_font_of_font_list (mw->menu.font_list)->fid;
+ − 2622 #else
+ − 2623 xgcv.font = mw->menu.font->fid;
+ − 2624 #endif
+ − 2625
+ − 2626 xgcv.foreground = mw->core.background_pixel;
+ − 2627 xgcv.background = mw->menu.foreground;
+ − 2628 mw->menu.background_gc = XtGetGC ((Widget) mw, flags, &xgcv);
+ − 2629
+ − 2630 xgcv.foreground = mw->menu.foreground;
+ − 2631 xgcv.background = mw->core.background_pixel;
+ − 2632 mw->menu.foreground_gc = XtGetGC ((Widget) mw, flags, &xgcv);
+ − 2633
+ − 2634 if (mw->menu.select_color != (Pixel)-1)
+ − 2635 {
+ − 2636 xgcv.foreground = mw->menu.select_color;
+ − 2637 }
+ − 2638 else
+ − 2639 {
+ − 2640 Display *dpy = XtDisplay(mw);
+ − 2641 if (CellsOfScreen(DefaultScreenOfDisplay(dpy)) <= 2)
+ − 2642 { /* mono */
+ − 2643 xgcv.foreground = mw->menu.foreground;
+ − 2644 }
+ − 2645 else
+ − 2646 { /* color */
+ − 2647 XColor xcolor;
+ − 2648 Colormap cmap = mw->core.colormap;
+ − 2649 xcolor.pixel = mw->core.background_pixel;
+ − 2650 XQueryColor (dpy, cmap, &xcolor);
+ − 2651 xcolor.red = (xcolor.red * 17) / 20;
+ − 2652 xcolor.green = (xcolor.green * 17) / 20;
+ − 2653 xcolor.blue = (xcolor.blue * 17) / 20;
+ − 2654 if (allocate_nearest_color (dpy, cmap, &xcolor))
+ − 2655 xgcv.foreground = xcolor.pixel;
+ − 2656 }
+ − 2657 }
+ − 2658 xgcv.background = mw->core.background_pixel;
+ − 2659 mw->menu.select_gc = XtGetGC ((Widget)mw, flags, &xgcv);
+ − 2660
+ − 2661 xgcv.foreground = mw->menu.foreground;
+ − 2662 xgcv.background = mw->core.background_pixel;
+ − 2663 xgcv.fill_style = FillStippled;
+ − 2664 xgcv.stipple = mw->menu.gray_pixmap;
+ − 2665 mw->menu.inactive_gc = XtGetGC ((Widget)mw,
+ − 2666 (flags | GCFillStyle | GCStipple),
+ − 2667 &xgcv);
+ − 2668
+ − 2669 xgcv.foreground = mw->menu.highlight_foreground;
+ − 2670 xgcv.background = mw->core.background_pixel;
+ − 2671 mw->menu.highlight_gc = XtGetGC ((Widget)mw, flags, &xgcv);
+ − 2672
+ − 2673 xgcv.foreground = mw->menu.title_foreground;
+ − 2674 xgcv.background = mw->core.background_pixel;
+ − 2675 mw->menu.title_gc = XtGetGC ((Widget)mw, flags, &xgcv);
+ − 2676
+ − 2677 xgcv.foreground = mw->menu.button_foreground;
+ − 2678 xgcv.background = mw->core.background_pixel;
+ − 2679 mw->menu.button_gc = XtGetGC ((Widget)mw, flags, &xgcv);
+ − 2680
+ − 2681 xgcv.fill_style = FillStippled;
+ − 2682 xgcv.stipple = mw->menu.gray_pixmap;
+ − 2683 mw->menu.inactive_button_gc = XtGetGC ((Widget)mw,
+ − 2684 (flags | GCFillStyle | GCStipple),
+ − 2685 &xgcv);
+ − 2686 }
+ − 2687
+ − 2688 static void
+ − 2689 release_drawing_gcs (XlwMenuWidget mw)
+ − 2690 {
+ − 2691 XtReleaseGC ((Widget) mw, mw->menu.foreground_gc);
+ − 2692 XtReleaseGC ((Widget) mw, mw->menu.button_gc);
+ − 2693 XtReleaseGC ((Widget) mw, mw->menu.highlight_gc);
+ − 2694 XtReleaseGC ((Widget) mw, mw->menu.title_gc);
+ − 2695 XtReleaseGC ((Widget) mw, mw->menu.inactive_gc);
+ − 2696 XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
+ − 2697 XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+ − 2698 XtReleaseGC ((Widget) mw, mw->menu.select_gc);
+ − 2699 /* let's get some segvs if we try to use these... */
+ − 2700 mw->menu.foreground_gc = (GC) -1;
+ − 2701 mw->menu.button_gc = (GC) -1;
+ − 2702 mw->menu.highlight_gc = (GC) -1;
+ − 2703 mw->menu.title_gc = (GC) -1;
+ − 2704 mw->menu.inactive_gc = (GC) -1;
+ − 2705 mw->menu.inactive_button_gc = (GC) -1;
+ − 2706 mw->menu.background_gc = (GC) -1;
+ − 2707 mw->menu.select_gc = (GC) -1;
+ − 2708 }
+ − 2709
+ − 2710 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
+ − 2711 ? ((unsigned long) (x)) : ((unsigned long) (y)))
+ − 2712
+ − 2713 static void
+ − 2714 make_shadow_gcs (XlwMenuWidget mw)
+ − 2715 {
+ − 2716 XGCValues xgcv;
+ − 2717 unsigned long pm = 0;
+ − 2718 Display *dpy = XtDisplay ((Widget) mw);
+ − 2719 Colormap cmap = mw->core.colormap;
+ − 2720 XColor topc, botc;
+ − 2721 int top_frobbed = 0, bottom_frobbed = 0;
+ − 2722
+ − 2723 if (mw->menu.top_shadow_color == (Pixel) (-1))
+ − 2724 mw->menu.top_shadow_color = mw->core.background_pixel;
+ − 2725 if (mw->menu.bottom_shadow_color == (Pixel) (-1))
+ − 2726 mw->menu.bottom_shadow_color = mw->menu.foreground;
+ − 2727
+ − 2728 if (mw->menu.top_shadow_color == mw->core.background_pixel ||
+ − 2729 mw->menu.top_shadow_color == mw->menu.foreground)
+ − 2730 {
+ − 2731 topc.pixel = mw->core.background_pixel;
+ − 2732 XQueryColor (dpy, cmap, &topc);
+ − 2733 /* don't overflow/wrap! */
+ − 2734 topc.red = MINL (65535, topc.red * 1.2);
+ − 2735 topc.green = MINL (65535, topc.green * 1.2);
+ − 2736 topc.blue = MINL (65535, topc.blue * 1.2);
+ − 2737 if (allocate_nearest_color (dpy, cmap, &topc))
+ − 2738 {
+ − 2739 if (topc.pixel == mw->core.background_pixel)
+ − 2740 {
+ − 2741 XFreeColors( dpy, cmap, &topc.pixel, 1, 0);
+ − 2742 topc.red = MINL (65535, topc.red + 0x8000);
+ − 2743 topc.green = MINL (65535, topc.green + 0x8000);
+ − 2744 topc.blue = MINL (65535, topc.blue + 0x8000);
+ − 2745 if (allocate_nearest_color (dpy, cmap, &topc))
+ − 2746 {
+ − 2747 mw->menu.top_shadow_color = topc.pixel;
+ − 2748 }
+ − 2749 }
+ − 2750 else
+ − 2751 {
+ − 2752 mw->menu.top_shadow_color = topc.pixel;
+ − 2753 }
+ − 2754
+ − 2755 top_frobbed = 1;
+ − 2756 }
+ − 2757 }
+ − 2758 if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
+ − 2759 mw->menu.bottom_shadow_color == mw->core.background_pixel)
+ − 2760 {
+ − 2761 botc.pixel = mw->core.background_pixel;
+ − 2762 XQueryColor (dpy, cmap, &botc);
+ − 2763 botc.red = (botc.red * 3) / 5;
+ − 2764 botc.green = (botc.green * 3) / 5;
+ − 2765 botc.blue = (botc.blue * 3) / 5;
+ − 2766 if (allocate_nearest_color (dpy, cmap, &botc))
+ − 2767 {
+ − 2768 if (botc.pixel == mw->core.background_pixel)
+ − 2769 {
+ − 2770 XFreeColors (dpy, cmap, &botc.pixel, 1, 0);
+ − 2771 botc.red = MINL (65535, botc.red + 0x4000);
+ − 2772 botc.green = MINL (65535, botc.green + 0x4000);
+ − 2773 botc.blue = MINL (65535, botc.blue + 0x4000);
+ − 2774 if (allocate_nearest_color (dpy, cmap, &botc))
+ − 2775 {
+ − 2776 mw->menu.bottom_shadow_color = botc.pixel;
+ − 2777 }
+ − 2778 }
+ − 2779 else
+ − 2780 {
+ − 2781 mw->menu.bottom_shadow_color = botc.pixel;
+ − 2782 }
+ − 2783
+ − 2784 bottom_frobbed = 1;
+ − 2785 }
+ − 2786 }
+ − 2787
+ − 2788 if (top_frobbed && bottom_frobbed)
+ − 2789 {
+ − 2790 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
+ − 2791 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
+ − 2792 if (bot_avg > top_avg)
+ − 2793 {
+ − 2794 Pixel tmp = mw->menu.top_shadow_color;
+ − 2795 mw->menu.top_shadow_color = mw->menu.bottom_shadow_color;
+ − 2796 mw->menu.bottom_shadow_color = tmp;
+ − 2797 }
+ − 2798 else if (topc.pixel == botc.pixel)
+ − 2799 {
+ − 2800 if (botc.pixel == mw->menu.foreground)
+ − 2801 mw->menu.top_shadow_color = mw->core.background_pixel;
+ − 2802 else
+ − 2803 mw->menu.bottom_shadow_color = mw->menu.foreground;
+ − 2804 }
+ − 2805 }
+ − 2806
+ − 2807 if (!mw->menu.top_shadow_pixmap &&
+ − 2808 mw->menu.top_shadow_color == mw->core.background_pixel)
+ − 2809 {
+ − 2810 mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
+ − 2811 mw->menu.top_shadow_color = mw->menu.foreground;
+ − 2812 }
+ − 2813 if (!mw->menu.bottom_shadow_pixmap &&
+ − 2814 mw->menu.bottom_shadow_color == mw->core.background_pixel)
+ − 2815 {
+ − 2816 mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
+ − 2817 mw->menu.bottom_shadow_color = mw->menu.foreground;
+ − 2818 }
+ − 2819
+ − 2820 xgcv.fill_style = FillOpaqueStippled;
+ − 2821 xgcv.foreground = mw->menu.top_shadow_color;
+ − 2822 xgcv.background = mw->core.background_pixel;
+ − 2823 /* xgcv.stipple = mw->menu.top_shadow_pixmap; gtb */
+ − 2824 if (mw->menu.top_shadow_pixmap &&
+ − 2825 mw->menu.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
+ − 2826 xgcv.stipple = mw->menu.top_shadow_pixmap;
+ − 2827 else
+ − 2828 xgcv.stipple = 0;
+ − 2829 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
+ − 2830 mw->menu.shadow_top_gc =
+ − 2831 XtGetGC((Widget)mw, GCForeground|GCBackground|pm, &xgcv);
+ − 2832
+ − 2833 xgcv.foreground = mw->menu.bottom_shadow_color;
+ − 2834 /* xgcv.stipple = mw->menu.bottom_shadow_pixmap; gtb */
+ − 2835 if (mw->menu.bottom_shadow_pixmap &&
+ − 2836 mw->menu.bottom_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
+ − 2837 xgcv.stipple = mw->menu.bottom_shadow_pixmap;
+ − 2838 else
+ − 2839 xgcv.stipple = 0;
+ − 2840 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
+ − 2841 mw->menu.shadow_bottom_gc =
+ − 2842 XtGetGC ((Widget)mw, GCForeground|GCBackground|pm, &xgcv);
+ − 2843 }
+ − 2844
+ − 2845
+ − 2846 static void
+ − 2847 release_shadow_gcs (XlwMenuWidget mw)
+ − 2848 {
+ − 2849 XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
+ − 2850 XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
+ − 2851 }
+ − 2852
+ − 2853
+ − 2854 static void
+ − 2855 extract_font_extents (XlwMenuWidget mw)
+ − 2856 {
+ − 2857 #ifdef NEED_MOTIF
+ − 2858 /* Find the maximal ascent/descent of the fonts in the font list
+ − 2859 so that all menu items can be the same height... */
+ − 2860 mw->menu.font_ascent = 0;
+ − 2861 mw->menu.font_descent = 0;
+ − 2862
+ − 2863 {
+ − 2864 XmFontContext context;
+ − 2865 #if (XmVersion >= 1002)
+ − 2866 XmFontListEntry fontentry;
+ − 2867 #else
+ − 2868 XmStringCharSet charset;
+ − 2869 #endif
+ − 2870 XFontStruct *font;
+ − 2871
+ − 2872 if (! XmFontListInitFontContext (&context, mw->menu.font_list))
+ − 2873 abort ();
+ − 2874 #if (XmVersion >= 1002)
+ − 2875 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more
+ − 2876 specifically, in _XmGetFirstFont()) that can cause a null pointer to be
+ − 2877 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the
+ − 2878 newer equivalent, instead. Also, it supports font sets, and the
+ − 2879 older function doesn't. */
+ − 2880 while ((fontentry = XmFontListNextEntry (context)))
+ − 2881 {
+ − 2882 XmFontType rettype;
+ − 2883
+ − 2884 XtPointer one_of_them = XmFontListEntryGetFont (fontentry, &rettype);
+ − 2885 if (rettype == XmFONT_IS_FONTSET)
+ − 2886 {
+ − 2887 XFontSet fontset = (XFontSet) one_of_them;
+ − 2888 XFontStruct **fontstruct_list;
+ − 2889 char **fontname_list;
+ − 2890 int fontcount = XFontsOfFontSet (fontset, &fontstruct_list,
+ − 2891 &fontname_list);
+ − 2892 while (--fontcount >= 0)
+ − 2893 {
+ − 2894 font = fontstruct_list[fontcount];
+ − 2895 if (font->ascent > (int) mw->menu.font_ascent)
+ − 2896 mw->menu.font_ascent = font->ascent;
+ − 2897 if (font->descent > (int) mw->menu.font_descent)
+ − 2898 mw->menu.font_descent = font->descent;
+ − 2899 }
+ − 2900 }
+ − 2901 else /* XmFONT_IS_FONT */
+ − 2902 {
+ − 2903 font = (XFontStruct *) one_of_them;
+ − 2904 if (font->ascent > (int) mw->menu.font_ascent)
+ − 2905 mw->menu.font_ascent = font->ascent;
+ − 2906 if (font->descent > (int) mw->menu.font_descent)
+ − 2907 mw->menu.font_descent = font->descent;
+ − 2908 }
+ − 2909 }
+ − 2910 #else /* motif 1.1 */
+ − 2911 while (XmFontListGetNextFont (context, &charset, &font))
+ − 2912 {
+ − 2913 if (font->ascent > (int) mw->menu.font_ascent)
+ − 2914 mw->menu.font_ascent = font->ascent;
+ − 2915 if (font->descent > (int) mw->menu.font_descent)
+ − 2916 mw->menu.font_descent = font->descent;
+ − 2917 XtFree (charset);
+ − 2918 }
+ − 2919 #endif /* Motif version */
+ − 2920 XmFontListFreeFontContext (context);
+ − 2921 }
+ − 2922 #else /* Not Motif */
+ − 2923 # ifdef USE_XFONTSET
+ − 2924 XFontStruct **fontstruct_list;
+ − 2925 char **fontname_list;
+ − 2926 XFontStruct *font;
+ − 2927 int fontcount = XFontsOfFontSet(mw->menu.font_set, &fontstruct_list,
+ − 2928 &fontname_list);
+ − 2929 mw->menu.font_ascent = 0;
+ − 2930 mw->menu.font_descent = 0;
+ − 2931 # if 0 /* nasty, personal debug, Kazz */
+ − 2932 fprintf(stderr, "fontSet count is %d\n", fontcount);
+ − 2933 # endif
+ − 2934 while (--fontcount >= 0) {
+ − 2935 font = fontstruct_list[fontcount];
+ − 2936 if (font->ascent > (int) mw->menu.font_ascent)
+ − 2937 mw->menu.font_ascent = font->ascent;
+ − 2938 if (font->descent > (int) mw->menu.font_descent)
+ − 2939 mw->menu.font_descent = font->descent;
+ − 2940 }
+ − 2941 # else /* ! USE_XFONTSET */
+ − 2942 mw->menu.font_ascent = mw->menu.font->ascent;
+ − 2943 mw->menu.font_descent = mw->menu.font->descent;
+ − 2944 # endif
+ − 2945 #endif /* NEED_MOTIF */
+ − 2946 }
+ − 2947
+ − 2948 #ifdef NEED_MOTIF
+ − 2949 static XFontStruct *
+ − 2950 default_font_of_font_list (XmFontList font_list)
+ − 2951 {
+ − 2952 XFontStruct *font = 0;
+ − 2953 # if 0
+ − 2954 /* Xm/Label.c does this: */
+ − 2955 _XmFontListGetDefaultFont (font_list, &font);
+ − 2956 # else /* !0 */
+ − 2957 {
+ − 2958 XmFontContext context;
+ − 2959 #if (XmVersion >= 1002)
+ − 2960 XmFontListEntry fontentry;
+ − 2961 XmFontType rettype;
+ − 2962 XtPointer one_of_them;
+ − 2963 #else
+ − 2964 XmStringCharSet charset;
+ − 2965 #endif
+ − 2966
+ − 2967 if (! XmFontListInitFontContext (&context, font_list))
+ − 2968 abort ();
+ − 2969 #if (XmVersion >= 1002)
+ − 2970 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more
+ − 2971 specifically, in _XmGetFirstFont()) that can cause a null pointer to be
+ − 2972 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the
+ − 2973 newer equivalent, instead. */
+ − 2974 fontentry = XmFontListNextEntry (context);
+ − 2975 one_of_them = XmFontListEntryGetFont (fontentry, &rettype);
+ − 2976 if (rettype == XmFONT_IS_FONTSET)
+ − 2977 {
+ − 2978 XFontSet fontset = (XFontSet) one_of_them;
+ − 2979 XFontStruct **fontstruct_list;
+ − 2980 char **fontname_list;
+ − 2981 (void) XFontsOfFontSet (fontset, &fontstruct_list, &fontname_list);
+ − 2982 font = fontstruct_list[0];
+ − 2983 }
+ − 2984 else /* XmFONT_IS_FONT */
+ − 2985 {
+ − 2986 font = (XFontStruct *) one_of_them;
+ − 2987 }
+ − 2988 #else
+ − 2989 if (! XmFontListGetNextFont (context, &charset, &font))
+ − 2990 abort ();
+ − 2991 XtFree (charset);
+ − 2992 #endif
+ − 2993 XmFontListFreeFontContext (context);
+ − 2994 }
+ − 2995 # endif /* !0 */
+ − 2996
+ − 2997 if (! font) abort ();
+ − 2998 return font;
+ − 2999 }
+ − 3000 #endif /* NEED_MOTIF */
+ − 3001
+ − 3002 static void
+ − 3003 XlwMenuInitialize (Widget request, Widget new, ArgList args,
+ − 3004 Cardinal *num_args)
+ − 3005 {
+ − 3006 /* Get the GCs and the widget size */
+ − 3007 XlwMenuWidget mw = (XlwMenuWidget)new;
+ − 3008 Window window = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw)));
+ − 3009 Display *display = XtDisplay (mw);
+ − 3010
+ − 3011 /* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */
+ − 3012 mw->menu.cursor = mw->menu.cursor_shape;
+ − 3013
+ − 3014 mw->menu.gray_pixmap =
+ − 3015 XCreatePixmapFromBitmapData (display, window, (char *) gray_bits,
+ − 3016 gray_width, gray_height, 1, 0, 1);
+ − 3017
+ − 3018 #ifdef NEED_MOTIF
442
+ − 3019 /* #### Even if it's a kludge!!!, we should consider doing the same for
+ − 3020 X Font Sets. */
428
+ − 3021 /* The menu.font_list slot came from the *fontList resource (Motif standard.)
+ − 3022 The menu.font_list_2 slot came from the *font resource, for backward
+ − 3023 compatibility with older versions of this code, and consistency with the
442
+ − 3024 rest of emacs. If both font and fontList are specified, we use fontList.
428
+ − 3025 If only one is specified, we use that. If neither are specified, we
+ − 3026 use the "fallback" value. What a kludge!!!
+ − 3027
+ − 3028 Note that this has the bug that a more general wildcard like "*fontList:"
+ − 3029 will override a more specific resource like "Emacs*menubar.font:". But
+ − 3030 I can't think of a way around that.
+ − 3031 */
+ − 3032 if (mw->menu.font_list) /* if *fontList is specified, use that */
+ − 3033 ;
+ − 3034 else if (mw->menu.font_list_2) /* else if *font is specified, use that */
+ − 3035 mw->menu.font_list = mw->menu.font_list_2;
+ − 3036 else /* otherwise use default */
+ − 3037 mw->menu.font_list = mw->menu.fallback_font_list;
+ − 3038 #endif
+ − 3039
+ − 3040 make_drawing_gcs (mw);
+ − 3041 make_shadow_gcs (mw);
+ − 3042 extract_font_extents (mw);
+ − 3043
+ − 3044 mw->menu.popped_up = False;
+ − 3045 mw->menu.pointer_grabbed = False;
+ − 3046 mw->menu.next_release_must_exit = False;
+ − 3047
+ − 3048 mw->menu.old_depth = 1;
+ − 3049 mw->menu.old_stack = XtNew (widget_value*);
+ − 3050 mw->menu.old_stack_length = 1;
+ − 3051 mw->menu.old_stack [0] = mw->menu.contents;
+ − 3052
+ − 3053 mw->menu.new_depth = 0;
+ − 3054 mw->menu.new_stack = 0;
+ − 3055 mw->menu.new_stack_length = 0;
+ − 3056 push_new_stack (mw, mw->menu.contents);
+ − 3057
+ − 3058 mw->menu.windows = XtNew (window_state);
+ − 3059 mw->menu.windows_length = 1;
+ − 3060 mw->menu.windows [0].x = 0;
+ − 3061 mw->menu.windows [0].y = 0;
+ − 3062 mw->menu.windows [0].width = 0;
+ − 3063 mw->menu.windows [0].height = 0;
+ − 3064 size_menu (mw, 0);
+ − 3065
+ − 3066 mw->core.width = mw->menu.windows [0].width;
+ − 3067 mw->core.height = mw->menu.windows [0].height;
+ − 3068 }
+ − 3069
+ − 3070 static void
+ − 3071 XlwMenuClassInitialize (void)
+ − 3072 {
+ − 3073 initialize_massaged_resource_char();
+ − 3074 }
+ − 3075
+ − 3076 static void
+ − 3077 XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
+ − 3078 {
+ − 3079 XlwMenuWidget mw = (XlwMenuWidget)w;
+ − 3080 XSetWindowAttributes xswa;
446
+ − 3081 unsigned long mask;
428
+ − 3082
+ − 3083 (*xlwMenuWidgetClass->core_class.superclass->core_class.realize)
+ − 3084 (w, valueMask, attributes);
+ − 3085
+ − 3086 xswa.save_under = True;
+ − 3087 xswa.cursor = mw->menu.cursor_shape;
+ − 3088 mask = CWSaveUnder | CWCursor;
+ − 3089 if (mw->menu.use_backing_store)
+ − 3090 {
+ − 3091 xswa.backing_store = Always;
+ − 3092 mask |= CWBackingStore;
+ − 3093 }
+ − 3094 XChangeWindowAttributes (XtDisplay (w), XtWindow (w), mask, &xswa);
+ − 3095
+ − 3096 mw->menu.windows [0].window = XtWindow (w);
+ − 3097 mw->menu.windows [0].x = w->core.x;
+ − 3098 mw->menu.windows [0].y = w->core.y;
+ − 3099 mw->menu.windows [0].width = w->core.width;
+ − 3100 mw->menu.windows [0].height = w->core.height;
+ − 3101 }
+ − 3102
+ − 3103 /* Only the toplevel menubar/popup is a widget so it's the only one that
+ − 3104 receives expose events through Xt. So we repaint all the other panes
+ − 3105 when receiving an Expose event. */
+ − 3106 static void
+ − 3107 XlwMenuRedisplay (Widget w, XEvent *ev, Region region)
+ − 3108 {
+ − 3109 XlwMenuWidget mw = (XlwMenuWidget)w;
+ − 3110 int i;
+ − 3111
+ − 3112 if (mw->core.being_destroyed) return;
+ − 3113
+ − 3114 for (i = 0; i < mw->menu.old_depth; i++)
+ − 3115 display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL);
+ − 3116 set_new_state (mw, NULL, mw->menu.old_depth); /* #### - ??? */
+ − 3117 remap_menubar (mw); /* #### - do these two lines do anything? */
+ − 3118 }
+ − 3119
+ − 3120 static void
+ − 3121 XlwMenuDestroy (Widget w)
+ − 3122 {
+ − 3123 int i;
+ − 3124 XlwMenuWidget mw = (XlwMenuWidget) w;
+ − 3125
+ − 3126 if (mw->menu.pointer_grabbed)
+ − 3127 {
+ − 3128 XtUngrabPointer (w, CurrentTime);
+ − 3129 mw->menu.pointer_grabbed = False;
+ − 3130 }
+ − 3131
+ − 3132 release_drawing_gcs (mw);
+ − 3133 release_shadow_gcs (mw);
+ − 3134
+ − 3135 /* this doesn't come from the resource db but is created explicitly
+ − 3136 so we must free it ourselves. */
+ − 3137 XFreePixmap (XtDisplay (mw), mw->menu.gray_pixmap);
+ − 3138 mw->menu.gray_pixmap = (Pixmap) -1;
+ − 3139
+ − 3140 /* Don't free mw->menu.contents because that comes from our creator.
+ − 3141 The `*_stack' elements are just pointers into `contents' so leave
+ − 3142 that alone too. But free the stacks themselves. */
+ − 3143 if (mw->menu.old_stack) XtFree ((char *) mw->menu.old_stack);
+ − 3144 if (mw->menu.new_stack) XtFree ((char *) mw->menu.new_stack);
+ − 3145
+ − 3146 /* Remember, you can't free anything that came from the resource
+ − 3147 database. This includes:
+ − 3148 mw->menu.cursor
+ − 3149 mw->menu.top_shadow_pixmap
+ − 3150 mw->menu.bottom_shadow_pixmap
+ − 3151 mw->menu.font
+ − 3152 mw->menu.font_set
+ − 3153 Also the color cells of top_shadow_color, bottom_shadow_color,
+ − 3154 foreground, and button_foreground will never be freed until this
+ − 3155 client exits. Nice, eh?
+ − 3156 */
+ − 3157
+ − 3158 /* start from 1 because the one in slot 0 is w->core.window */
+ − 3159 for (i = 1; i < mw->menu.windows_length; i++)
+ − 3160 XDestroyWindow (XtDisplay (mw), mw->menu.windows [i].window);
+ − 3161 if (mw->menu.windows)
+ − 3162 XtFree ((char *) mw->menu.windows);
+ − 3163 }
+ − 3164
+ − 3165 static Boolean
+ − 3166 XlwMenuSetValues (Widget current, Widget request, Widget new, ArgList args,
+ − 3167 Cardinal *num_args)
+ − 3168 {
+ − 3169 XlwMenuWidget oldmw = (XlwMenuWidget)current;
+ − 3170 XlwMenuWidget newmw = (XlwMenuWidget)new;
+ − 3171 Boolean redisplay = False;
+ − 3172 int i;
+ − 3173
+ − 3174 if (newmw->menu.contents
+ − 3175 && newmw->menu.contents->contents
+ − 3176 && newmw->menu.contents->contents->change >= VISIBLE_CHANGE)
+ − 3177 redisplay = True;
+ − 3178
+ − 3179 if (newmw->core.background_pixel != oldmw->core.background_pixel
+ − 3180 || newmw->menu.foreground != oldmw->menu.foreground
+ − 3181 /* For the XEditResource protocol, which may want to change the font. */
+ − 3182 #ifdef NEED_MOTIF
+ − 3183 || newmw->menu.font_list != oldmw->menu.font_list
+ − 3184 || newmw->menu.font_list_2 != oldmw->menu.font_list_2
+ − 3185 || newmw->menu.fallback_font_list != oldmw->menu.fallback_font_list
+ − 3186 #else
+ − 3187 || newmw->menu.font != oldmw->menu.font
+ − 3188 #endif
+ − 3189 )
+ − 3190 {
+ − 3191 release_drawing_gcs (newmw);
+ − 3192 make_drawing_gcs (newmw);
+ − 3193 redisplay = True;
+ − 3194
+ − 3195 for (i = 0; i < oldmw->menu.windows_length; i++)
+ − 3196 {
+ − 3197 XSetWindowBackground (XtDisplay (oldmw),
+ − 3198 oldmw->menu.windows [i].window,
+ − 3199 newmw->core.background_pixel);
+ − 3200 /* clear windows and generate expose events */
+ − 3201 XClearArea (XtDisplay (oldmw), oldmw->menu.windows[i].window,
+ − 3202 0, 0, 0, 0, True);
+ − 3203 }
+ − 3204 }
+ − 3205
+ − 3206 return redisplay;
+ − 3207 }
+ − 3208
+ − 3209 static void
+ − 3210 XlwMenuResize (Widget w)
+ − 3211 {
+ − 3212 XlwMenuWidget mw = (XlwMenuWidget)w;
+ − 3213
+ − 3214 mw->menu.windows [0].width = mw->core.width;
+ − 3215 mw->menu.windows [0].height = mw->core.height;
+ − 3216 }
+ − 3217
+ − 3218 /* Action procedures */
+ − 3219 static void
+ − 3220 handle_single_motion_event (XlwMenuWidget mw, XMotionEvent *ev,
+ − 3221 Boolean select_p)
+ − 3222 {
+ − 3223 widget_value *val;
+ − 3224 Boolean stay_up;
+ − 3225 int level;
+ − 3226
+ − 3227 if (!map_event_to_widget_value (mw, ev, &val, &level, &stay_up))
+ − 3228 {
+ − 3229 /* we wind up here when: (a) the event is in the menubar, (b) the
+ − 3230 event isn't in the menubar or any of the panes, (c) the event is on
+ − 3231 a disabled menu item */
+ − 3232 pop_new_stack_if_no_contents (mw);
+ − 3233 if (select_p && !stay_up) {
+ − 3234 /* pop down all menus and exit */
+ − 3235 mw->menu.next_release_must_exit = True;
+ − 3236 set_new_state(mw, (val = NULL), 1);
+ − 3237 }
+ − 3238 }
+ − 3239 else
+ − 3240 {
+ − 3241 /* we wind up here when: (a) the event pops up a pull_right menu,
+ − 3242 (b) a menu item that is not disabled is highlighted */
+ − 3243 if (select_p && mw->menu.bounce_down
+ − 3244 && close_to_reference_time((Widget)mw,
+ − 3245 mw->menu.menu_bounce_time,
+ − 3246 (XEvent *)ev))
+ − 3247 {
+ − 3248 /* motion can cause more than one event. Don't bounce right back
+ − 3249 up if we've just bounced down. */
+ − 3250 val = NULL;
+ − 3251 }
+ − 3252 else if (select_p && mw->menu.bounce_down &&
+ − 3253 mw->menu.last_selected_val &&
+ − 3254 (mw->menu.last_selected_val == val))
+ − 3255 {
+ − 3256 val = NULL; /* assigned to mw->last_selected_val below */
+ − 3257 mw->menu.menu_bounce_time = ev->time;
+ − 3258 /* popdown last menu if we're selecting the same menu item as we did
+ − 3259 last time and the XlwMenu.bounceDown resource is set, if the
+ − 3260 item is on the menubar itself, then exit. */
+ − 3261 if (level == (mw->menu.popped_up ? 0 : 1))
+ − 3262 mw->menu.next_release_must_exit = True;
+ − 3263 }
+ − 3264 else
+ − 3265 mw->menu.menu_bounce_time = 0;
+ − 3266 set_new_state (mw, val, level);
+ − 3267 }
+ − 3268 mw->menu.last_selected_val = val;
+ − 3269 remap_menubar (mw);
+ − 3270
+ − 3271 /* Sync with the display. Makes it feel better on X terms. */
+ − 3272 XFlush (XtDisplay (mw));
+ − 3273 }
+ − 3274
+ − 3275 static void
+ − 3276 handle_motion_event (XlwMenuWidget mw, XMotionEvent *ev,
+ − 3277 Boolean select_p)
+ − 3278 {
+ − 3279 int x = ev->x_root;
+ − 3280 int y = ev->y_root;
+ − 3281 unsigned int state = ev->state;
+ − 3282 XMotionEvent *event= ev, dummy;
+ − 3283
+ − 3284 /* allow motion events to be generated again */
+ − 3285 dummy.window = ev->window;
+ − 3286 if (ev->is_hint
+ − 3287 && XQueryPointer (XtDisplay (mw), dummy.window,
+ − 3288 &dummy.root, &dummy.subwindow,
+ − 3289 &dummy.x_root, &dummy.y_root,
+ − 3290 &dummy.x, &dummy.y,
+ − 3291 &dummy.state)
+ − 3292 && dummy.state == state
+ − 3293 && (dummy.x_root != x || dummy.y_root != y))
+ − 3294 {
+ − 3295 /* don't handle the event twice or that breaks bounce_down. --Stig */
+ − 3296 dummy.type = ev->type;
+ − 3297 event = &dummy;
+ − 3298 }
+ − 3299
+ − 3300 lw_menu_accelerate = False;
+ − 3301 handle_single_motion_event (mw, event, select_p);
+ − 3302 }
+ − 3303
+ − 3304 Time x_focus_timestamp_really_sucks_fix_me_better;
+ − 3305
+ − 3306 static void
+ − 3307 Start (Widget w, XEvent *ev, String *params, Cardinal *num_params)
+ − 3308 {
+ − 3309 XlwMenuWidget mw = (XlwMenuWidget)w;
+ − 3310
+ − 3311 lw_menubar_widget = w;
+ − 3312
+ − 3313 lw_menu_active = True;
+ − 3314
+ − 3315 if (!mw->menu.pointer_grabbed)
+ − 3316 {
+ − 3317 mw->menu.menu_post_time = ev->xbutton.time;
+ − 3318 mw->menu.menu_bounce_time = 0;
+ − 3319 mw->menu.next_release_must_exit = True;
+ − 3320 mw->menu.last_selected_val = NULL;
+ − 3321 x_focus_timestamp_really_sucks_fix_me_better =
+ − 3322 ((XButtonPressedEvent*)ev)->time;
+ − 3323 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
+ − 3324
+ − 3325 /* notes the absolute position of the menubar window */
+ − 3326 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
+ − 3327 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
+ − 3328
+ − 3329 XtGrabPointer ((Widget)mw, False,
+ − 3330 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
+ − 3331 GrabModeAsync, GrabModeAsync,
+ − 3332 None, mw->menu.cursor_shape,
+ − 3333 ((XButtonPressedEvent*)ev)->time);
+ − 3334 mw->menu.pointer_grabbed = True;
+ − 3335 }
+ − 3336
+ − 3337 /* handles the down like a move, slots are mostly compatible */
+ − 3338 handle_motion_event (mw, &ev->xmotion, True);
+ − 3339 }
+ − 3340
+ − 3341 static void
+ − 3342 Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params)
+ − 3343 {
+ − 3344 XlwMenuWidget mw = (XlwMenuWidget)w;
+ − 3345 handle_motion_event (mw, &ev->xmotion, False);
+ − 3346 }
+ − 3347
+ − 3348 static void
+ − 3349 Select (Widget w, XEvent *ev, String *params, Cardinal *num_params)
+ − 3350 {
+ − 3351 XlwMenuWidget mw = (XlwMenuWidget)w;
+ − 3352 widget_value *selected_item = mw->menu.old_stack [mw->menu.old_depth - 1];
+ − 3353
+ − 3354 lw_menu_accelerate = False;
+ − 3355
+ − 3356 /* If user releases the button quickly, without selecting anything,
+ − 3357 after the initial down-click that brought the menu up,
+ − 3358 do nothing. */
+ − 3359 if ((selected_item == 0 || selected_item->call_data == 0)
+ − 3360 && (!mw->menu.next_release_must_exit
+ − 3361 || close_to_reference_time(w, mw->menu.menu_post_time, ev)))
+ − 3362 {
+ − 3363 mw->menu.next_release_must_exit = False;
+ − 3364 return;
+ − 3365 }
+ − 3366
+ − 3367 /* pop down everything */
+ − 3368 mw->menu.new_depth = 1;
+ − 3369 remap_menubar (mw);
+ − 3370
+ − 3371 /* Destroy() only gets called for popup menus. Menubar widgets aren't
+ − 3372 destroyed when their menu panes get nuked. */
+ − 3373 if (mw->menu.pointer_grabbed)
+ − 3374 {
+ − 3375 XtUngrabPointer ((Widget)w, ev->xmotion.time);
+ − 3376 mw->menu.pointer_grabbed = False;
+ − 3377 }
+ − 3378
+ − 3379 if (mw->menu.popped_up)
+ − 3380 {
+ − 3381 mw->menu.popped_up = False;
+ − 3382 XtPopdown (XtParent (mw));
+ − 3383 }
+ − 3384
+ − 3385 lw_menu_active = False;
+ − 3386
+ − 3387 x_focus_timestamp_really_sucks_fix_me_better =
+ − 3388 ((XButtonPressedEvent*)ev)->time;
+ − 3389
+ − 3390 /* callback */
+ − 3391 XtCallCallbackList ((Widget) mw, mw->menu.select, (XtPointer) selected_item);
+ − 3392 }
+ − 3393
+ − 3394 /* Action procedures for keyboard accelerators */
+ − 3395
+ − 3396 /* set the menu */
+ − 3397 void
+ − 3398 xlw_set_menu (Widget w, widget_value *val)
+ − 3399 {
+ − 3400 lw_menubar_widget = w;
+ − 3401 set_new_state ((XlwMenuWidget)w, val, 1);
+ − 3402 }
+ − 3403
+ − 3404 /* prepare the menu structure via the call-backs */
+ − 3405 void
+ − 3406 xlw_map_menu (Time t)
+ − 3407 {
+ − 3408 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
+ − 3409
+ − 3410 lw_menu_accelerate = True;
+ − 3411
+ − 3412 if (!mw->menu.pointer_grabbed)
+ − 3413 {
+ − 3414 XWindowAttributes ret;
+ − 3415 Window parent,root;
+ − 3416 Window *waste;
+ − 3417 unsigned int num_waste;
+ − 3418
+ − 3419 lw_menu_active = True;
+ − 3420
+ − 3421 mw->menu.menu_post_time = t;
+ − 3422 mw->menu.menu_bounce_time = 0;
+ − 3423
+ − 3424 mw->menu.next_release_must_exit = True;
+ − 3425 mw->menu.last_selected_val = NULL;
+ − 3426
+ − 3427 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
+ − 3428
+ − 3429 /* do this for keyboards too! */
+ − 3430 /* notes the absolute position of the menubar window */
+ − 3431 /*
+ − 3432 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
+ − 3433 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
+ − 3434 */
+ − 3435
+ − 3436 /* get the geometry of the menubar */
+ − 3437
+ − 3438 /* there has to be a better way than this. */
+ − 3439
+ − 3440 mw->menu.windows [0].x = 0;
+ − 3441 mw->menu.windows [0].y = 0;
+ − 3442
+ − 3443 parent = XtWindow (lw_menubar_widget);
+ − 3444 do
+ − 3445 {
+ − 3446 XGetWindowAttributes (XtDisplay (lw_menubar_widget), parent, &ret);
+ − 3447 mw->menu.windows [0].x += ret.x;
+ − 3448 mw->menu.windows [0].y += ret.y;
+ − 3449
+ − 3450 if (parent)
+ − 3451 XQueryTree (XtDisplay (lw_menubar_widget), parent, &root, &parent, &waste,
+ − 3452 &num_waste);
+ − 3453 if (waste)
+ − 3454 {
+ − 3455 XFree (waste);
+ − 3456 }
+ − 3457 }
+ − 3458 while (parent != root);
+ − 3459
+ − 3460 XtGrabPointer ((Widget)mw, False,
+ − 3461 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
+ − 3462 GrabModeAsync, GrabModeAsync,
+ − 3463 None, mw->menu.cursor_shape, t);
+ − 3464 mw->menu.pointer_grabbed = True;
+ − 3465 }
+ − 3466 }
+ − 3467
+ − 3468 /* display the stupid menu already */
+ − 3469 void
+ − 3470 xlw_display_menu (Time t)
+ − 3471 {
+ − 3472 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
+ − 3473
+ − 3474 lw_menu_accelerate = True;
+ − 3475
+ − 3476 remap_menubar (mw);
+ − 3477
+ − 3478 /* Sync with the display. Makes it feel better on X terms. */
+ − 3479 XFlush (XtDisplay (mw));
+ − 3480 }
+ − 3481
+ − 3482 /* push a sub menu */
+ − 3483 void
+ − 3484 xlw_push_menu (widget_value *val)
+ − 3485 {
+ − 3486 push_new_stack ((XlwMenuWidget)lw_menubar_widget, val);
+ − 3487 }
+ − 3488
+ − 3489 /* pop a sub menu */
+ − 3490 int
+ − 3491 xlw_pop_menu (void)
+ − 3492 {
+ − 3493 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0)
+ − 3494 ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth --;
+ − 3495 else
+ − 3496 return 0;
+ − 3497 return 1;
+ − 3498 }
+ − 3499
+ − 3500 void
+ − 3501 xlw_kill_menus (widget_value *val)
+ − 3502 {
+ − 3503 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
+ − 3504
+ − 3505 lw_menu_accelerate = False;
+ − 3506
+ − 3507 mw->menu.new_depth = 1;
+ − 3508 remap_menubar (mw);
+ − 3509
+ − 3510 if (mw->menu.pointer_grabbed)
+ − 3511 {
+ − 3512 XtUngrabPointer (lw_menubar_widget, CurrentTime);
+ − 3513 mw->menu.pointer_grabbed = False;
+ − 3514 }
+ − 3515
+ − 3516 lw_menu_active = False;
+ − 3517 XtCallCallbackList (lw_menubar_widget, mw->menu.select, (XtPointer)val);
+ − 3518 }
+ − 3519
+ − 3520 /* set the menu item */
+ − 3521 void
+ − 3522 xlw_set_item (widget_value *val)
+ − 3523 {
+ − 3524 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0)
+ − 3525 ((XlwMenuWidget) lw_menubar_widget)->menu.new_depth --;
+ − 3526 push_new_stack ((XlwMenuWidget) lw_menubar_widget, val);
+ − 3527 }
+ − 3528
+ − 3529 /* get either the current entry or a list of all entries in the current submenu */
+ − 3530 widget_value *
+ − 3531 xlw_get_entries (int allp)
+ − 3532 {
+ − 3533 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
+ − 3534 if (allp)
+ − 3535 {
+ − 3536 if (mw->menu.new_depth >= 2)
+ − 3537 return mw->menu.new_stack [mw->menu.new_depth - 2]->contents;
+ − 3538 else
+ − 3539 return mw->menu.new_stack[0];
+ − 3540 }
+ − 3541 else
+ − 3542 if (mw->menu.new_depth >= 1)
+ − 3543 return mw->menu.new_stack [mw->menu.new_depth - 1];
+ − 3544
+ − 3545 return NULL;
+ − 3546 }
+ − 3547
+ − 3548 int
+ − 3549 xlw_menu_level (void)
+ − 3550 {
+ − 3551 return ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth;
+ − 3552 }
+ − 3553
+ − 3554
+ − 3555 /* Special code to pop-up a menu */
+ − 3556 void
+ − 3557 xlw_pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event)
+ − 3558 {
+ − 3559 int x = event->x_root;
+ − 3560 int y = event->y_root;
+ − 3561 int w;
+ − 3562 int h;
+ − 3563 int borderwidth = mw->menu.shadow_thickness;
+ − 3564 Screen* screen = XtScreen (mw);
+ − 3565
+ − 3566 mw->menu.menu_post_time = event->time;
+ − 3567 mw->menu.menu_bounce_time = 0;
+ − 3568 mw->menu.next_release_must_exit = True;
+ − 3569 mw->menu.last_selected_val = NULL;
+ − 3570
+ − 3571 XtCallCallbackList ((Widget) mw, mw->menu.open, NULL);
+ − 3572
+ − 3573 size_menu (mw, 0);
+ − 3574
+ − 3575 w = mw->menu.windows [0].width;
+ − 3576 h = mw->menu.windows [0].height;
+ − 3577
+ − 3578 x -= borderwidth;
+ − 3579 y -= borderwidth;
+ − 3580
+ − 3581 if (x < borderwidth)
+ − 3582 x = borderwidth;
+ − 3583
+ − 3584 if (x > WidthOfScreen (screen) - w - 2 * borderwidth)
+ − 3585 x = WidthOfScreen (screen) - w - 2 * borderwidth;
+ − 3586
+ − 3587 if (y < borderwidth)
+ − 3588 y = borderwidth;
+ − 3589
+ − 3590 if (y > HeightOfScreen (screen) - h - 2 * borderwidth)
+ − 3591 y = HeightOfScreen (screen) - h - 2 * borderwidth;
+ − 3592
+ − 3593 mw->menu.popped_up = True;
+ − 3594 XtConfigureWidget (XtParent (mw), x, y, w, h,
+ − 3595 XtParent (mw)->core.border_width);
+ − 3596 XtPopup (XtParent (mw), XtGrabExclusive);
+ − 3597 display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+ − 3598 if (!mw->menu.pointer_grabbed)
+ − 3599 {
+ − 3600 XtGrabPointer ((Widget)mw, False,
+ − 3601 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
+ − 3602 GrabModeAsync, GrabModeAsync,
+ − 3603 None, mw->menu.cursor_shape, event->time);
+ − 3604 mw->menu.pointer_grabbed = True;
+ − 3605 }
+ − 3606
+ − 3607 mw->menu.windows [0].x = x + borderwidth;
+ − 3608 mw->menu.windows [0].y = y + borderwidth;
+ − 3609
+ − 3610 handle_motion_event (mw, (XMotionEvent *) event, True);
+ − 3611 }
+ − 3612
+ − 3613 /* #### unused */
+ − 3614 #if 0
+ − 3615 /*
+ − 3616 * This is a horrible function which should not be needed.
+ − 3617 * use it to put the resize method back the way the XlwMenu
+ − 3618 * class initializer put it. Motif screws with this when
+ − 3619 * the XlwMenu class gets instantiated.
+ − 3620 */
+ − 3621 void
+ − 3622 xlw_unmunge_class_resize (Widget w)
+ − 3623 {
+ − 3624 if (w->core.widget_class->core_class.resize != XlwMenuResize)
+ − 3625 w->core.widget_class->core_class.resize = XlwMenuResize;
+ − 3626 }
+ − 3627 #endif /* 0 */
+ − 3628