pcb 4.1.1
An interactive printed circuit board layout editor.

menu.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <ctype.h>
00009 #include <unistd.h>
00010 
00011 #include "xincludes.h"
00012 
00013 #include "global.h"
00014 #include "data.h"
00015 #include "error.h"
00016 #include "misc.h"
00017 #include "pcb-printf.h"
00018 
00019 #include "hid.h"
00020 #include "../hidint.h"
00021 #include "hid/common/hid_resource.h"
00022 #include "resource.h"
00023 #include "lesstif.h"
00024 #include "mymem.h"
00025 #include "layerflags.h"
00026 
00027 #include "pcb-menu.h"
00028 
00029 #ifdef HAVE_LIBDMALLOC
00030 #include <dmalloc.h>
00031 #endif
00032 
00033 #ifndef R_OK
00034 /* Common value for systems that don't define it.  */
00035 #define R_OK 4
00036 #endif
00037 
00038 static Colormap cmap;
00039 
00040 static Arg args[30];
00041 static int n;
00042 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
00043 
00044 static void note_accelerator (char *acc, Resource * node);
00045 static void note_widget_flag (Widget w, char *type, char *name);
00046 
00047 static const char getxy_syntax[] =
00048 "GetXY()";
00049 
00050 static const char getxy_help[] =
00051 "Get a coordinate.";
00052 
00076 /* %start-doc actions GetXY
00077 
00078 Prompts the user for a coordinate, if one is not already selected.
00079 
00080 %end-doc */
00081 
00082 static int
00083 GetXY (int argc, char **argv, Coord x, Coord y)
00084 {
00085   return 0;
00086 }
00087 
00088 static const char debug_syntax[] =
00089 "Debug(...)";
00090 
00091 static const char debug_help[] =
00092 "Debug action.";
00093 
00094 /* %start-doc actions Debug
00095 
00096 This action exists to help debug scripts; it simply prints all its
00097 arguments to stdout.
00098 
00099 %end-doc */
00100 
00101 static const char debugxy_syntax[] =
00102 "DebugXY(...)";
00103 
00104 static const char debugxy_help[] =
00105 "Debug action, with coordinates";
00106 
00107 /* %start-doc actions DebugXY
00108 
00109 Like @code{Debug}, but requires a coordinate.  If the user hasn't yet
00110 indicated a location on the board, the user will be prompted to click
00111 on one.
00112 
00113 %end-doc */
00114 
00115 static int
00116 Debug (int argc, char **argv, Coord x, Coord y)
00117 {
00118   int i;
00119   printf ("Debug:");
00120   for (i = 0; i < argc; i++)
00121     printf (" [%d] `%s'", i, argv[i]);
00122   pcb_printf (" x,y %$mD\n", x, y);
00123   for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
00124     {
00125       printf("0x%08x %s (%s)\n",
00126              PCB->Data->Layer[i].Type,
00127              PCB->Data->Layer[i].Name,
00128              layertype_to_string (PCB->Data->Layer[i].Type));
00129     }
00130   return 0;
00131 }
00132 
00133 static const char return_syntax[] =
00134 "Return(0|1)";
00135 
00136 static const char return_help[] =
00137 "Simulate a passing or failing action.";
00138 
00139 /* %start-doc actions Return
00140 
00141 This is for testing.  If passed a 0, does nothing and succeeds.  If
00142 passed a 1, does nothing but pretends to fail.
00143 
00144 %end-doc */
00145 
00146 static int
00147 Return (int argc, char **argv, Coord x, Coord y)
00148 {
00149   if (argc < 1)
00150     return 0;
00151   else if (argc == 1)
00152     return atoi (argv[0]);
00153 
00154   return 1;
00155 }
00156 
00157 static const char dumpkeys_syntax[] =
00158 "DumpKeys()";
00159 
00160 static const char dumpkeys_help[] =
00161 "Dump Lesstif key bindings.";
00162 
00163 /* %start-doc actions DumpKeys
00164 
00165 Causes the list of key bindings (from @code{pcb-menu.res}) to be
00166 dumped to stdout.  This is most useful when invoked from the command
00167 line like this:
00168 
00169 @example
00170 pcb --action-string DumpKeys
00171 @end example
00172 
00173 %end-doc */
00174 
00175 static int do_dump_keys = 0;
00176 static int
00177 DumpKeys (int argc, char **argv, Coord x, Coord y)
00178 {
00179   do_dump_keys = 1;
00180   return 0;
00181 }
00182 
00183 /*-----------------------------------------------------------------------------*/
00184 
00185 #define LB_SILK (MAX_LAYER + BOTTOM_SILK_LAYER)
00186 #define LB_RATS (MAX_LAYER + 1)
00187 #define LB_NUMPICK (LB_RATS+1)
00188 /* more */
00189 #define LB_PINS (MAX_ALL_LAYER)
00190 #define LB_VIAS (MAX_ALL_LAYER + 1)
00191 #define LB_BACK (MAX_ALL_LAYER + 2)
00192 #define LB_MASK (MAX_ALL_LAYER + 3)
00193 #define LB_NUM  (MAX_ALL_LAYER + 4)
00194 
00195 typedef struct
00196 {
00197   Widget w[LB_NUM];
00198   int is_pick;
00199 } LayerButtons;
00200 
00201 static LayerButtons *layer_button_list = 0;
00202 static int num_layer_buttons = 0;
00203 static int fg_colors[LB_NUM];
00204 static int bg_color;
00205 
00206 extern Widget lesstif_m_layer;
00207 
00208 static int
00209 LayersChanged (int argc, char **argv, Coord x, Coord y)
00210 {
00211   int l, i, set;
00212   char *name;
00213   int current_layer;
00214 
00215   if (!layer_button_list)
00216     return 0;
00217   if (PCB && PCB->Data)
00218     {
00219       DataType *d = PCB->Data;
00220       for (i = 0; i < MAX_LAYER; i++)
00221         fg_colors[i] = lesstif_parse_color (d->Layer[i].Color);
00222       fg_colors[LB_SILK] = lesstif_parse_color (PCB->ElementColor);
00223       fg_colors[LB_RATS] = lesstif_parse_color (PCB->RatColor);
00224       fg_colors[LB_PINS] = lesstif_parse_color (PCB->PinColor);
00225       fg_colors[LB_VIAS] = lesstif_parse_color (PCB->ViaColor);
00226       fg_colors[LB_BACK] =
00227         lesstif_parse_color (PCB->InvisibleObjectsColor);
00228       fg_colors[LB_MASK] = lesstif_parse_color (PCB->MaskColor);
00229       bg_color = lesstif_parse_color (Settings.BackgroundColor);
00230     }
00231   else
00232     {
00233       for (i = 0; i < MAX_LAYER; i++)
00234         fg_colors[i] = lesstif_parse_color (Settings.LayerColor[i]);
00235       fg_colors[LB_SILK] = lesstif_parse_color (Settings.ElementColor);
00236       fg_colors[LB_RATS] = lesstif_parse_color (Settings.RatColor);
00237       fg_colors[LB_PINS] = lesstif_parse_color (Settings.PinColor);
00238       fg_colors[LB_VIAS] = lesstif_parse_color (Settings.ViaColor);
00239       fg_colors[LB_BACK] =
00240         lesstif_parse_color (Settings.InvisibleObjectsColor);
00241       fg_colors[LB_MASK] = lesstif_parse_color (Settings.MaskColor);
00242       bg_color = lesstif_parse_color (Settings.BackgroundColor);
00243     }
00244 
00245   if (PCB->RatDraw)
00246     current_layer = LB_RATS;
00247   else if (PCB->SilkActive)
00248     current_layer = LB_SILK;
00249   else
00250     current_layer = LayerStack[0];
00251 
00252   for (l = 0; l < num_layer_buttons; l++)
00253     {
00254       LayerButtons *lb = layer_button_list + l;
00255       for (i = 0; i < (lb->is_pick ? LB_NUMPICK : LB_NUM); i++)
00256         {
00257           switch (i)
00258             {
00259             case LB_SILK:
00260               set = PCB->ElementOn;
00261               break;
00262             case LB_RATS:
00263               set = PCB->RatOn;
00264               break;
00265             case LB_PINS:
00266               set = PCB->PinOn;
00267               break;
00268             case LB_VIAS:
00269               set = PCB->ViaOn;
00270               break;
00271             case LB_BACK:
00272               set = PCB->InvisibleObjectsOn;
00273               break;
00274             case LB_MASK:
00275               set = TEST_FLAG (SHOWMASKFLAG, PCB);
00276               break;
00277             default:            /* layers */
00278               set = PCB->Data->Layer[i].On;
00279               break;
00280             }
00281 
00282           n = 0;
00283           if (i < MAX_LAYER && PCB->Data->Layer[i].Name)
00284             {
00285               XmString s = XmStringCreatePCB (PCB->Data->Layer[i].Name);
00286               stdarg (XmNlabelString, s);
00287             }
00288           if (!lb->is_pick)
00289             {
00290               if (set)
00291                 {
00292                   stdarg (XmNforeground, bg_color);
00293                   stdarg (XmNbackground, fg_colors[i]);
00294                 }
00295               else
00296                 {
00297                   stdarg (XmNforeground, fg_colors[i]);
00298                   stdarg (XmNbackground, bg_color);
00299                 }
00300               stdarg (XmNset, set);
00301             }
00302           else
00303             {
00304               stdarg (XmNforeground, bg_color);
00305               stdarg (XmNbackground, fg_colors[i]);
00306               stdarg (XmNset, current_layer == i ? True : False);
00307             }
00308           XtSetValues (lb->w[i], args, n);
00309 
00310           if (i >= max_copper_layer && i < MAX_LAYER)
00311             XtUnmanageChild(lb->w[i]);
00312           else
00313             XtManageChild(lb->w[i]);
00314         }
00315     }
00316   if (lesstif_m_layer)
00317     {
00318       switch (current_layer)
00319         {
00320         case LB_RATS:
00321           name = "Rats";
00322           break;
00323         case LB_SILK:
00324           name = "Silk";
00325           break;
00326         default:
00327           name = PCB->Data->Layer[current_layer].Name;
00328           break;
00329         }
00330       n = 0;
00331       stdarg (XmNbackground, fg_colors[current_layer]);
00332       stdarg (XmNforeground, bg_color);
00333       stdarg (XmNlabelString, XmStringCreatePCB (name));
00334       XtSetValues (lesstif_m_layer, args, n);
00335     }
00336 
00337   lesstif_update_layer_groups ();
00338 
00339   return 0;
00340 }
00341 
00342 static void
00343 show_one_layer_button (int layer, int set)
00344 {
00345   int l;
00346   n = 0;
00347   if (set)
00348     {
00349       stdarg (XmNforeground, bg_color);
00350       stdarg (XmNbackground, fg_colors[layer]);
00351     }
00352   else
00353     {
00354       stdarg (XmNforeground, fg_colors[layer]);
00355       stdarg (XmNbackground, bg_color);
00356     }
00357   stdarg (XmNset, set);
00358 
00359   for (l = 0; l < num_layer_buttons; l++)
00360     {
00361       LayerButtons *lb = layer_button_list + l;
00362       if (!lb->is_pick)
00363         XtSetValues (lb->w[layer], args, n);
00364     }
00365 }
00366 
00367 static void
00368 layer_button_callback (Widget w, int layer, XmPushButtonCallbackStruct * pbcs)
00369 {
00370   int l, set;
00371   switch (layer)
00372     {
00373     case LB_SILK:
00374       set = PCB->ElementOn = !PCB->ElementOn;
00375       PCB->Data->SILKLAYER.On = set;
00376       PCB->Data->BACKSILKLAYER.On = set;
00377       break;
00378     case LB_RATS:
00379       set = PCB->RatOn = !PCB->RatOn;
00380       break;
00381     case LB_PINS:
00382       set = PCB->PinOn = !PCB->PinOn;
00383       break;
00384     case LB_VIAS:
00385       set = PCB->ViaOn = !PCB->ViaOn;
00386       break;
00387     case LB_BACK:
00388       set = PCB->InvisibleObjectsOn = !PCB->InvisibleObjectsOn;
00389       break;
00390     case LB_MASK:
00391       TOGGLE_FLAG (SHOWMASKFLAG, PCB);
00392       set = TEST_FLAG (SHOWMASKFLAG, PCB);
00393       break;
00394     default:                    /* layers */
00395       set = PCB->Data->Layer[layer].On = !PCB->Data->Layer[layer].On;
00396       break;
00397     }
00398 
00399   show_one_layer_button (layer, set);
00400   if (layer < max_copper_layer)
00401     {
00402       int i;
00403       int group = GetLayerGroupNumberByNumber (layer);
00404       for (i = 0; i < PCB->LayerGroups.Number[group]; i++)
00405         {
00406           l = PCB->LayerGroups.Entries[group][i];
00407           if (l != layer && l < max_copper_layer)
00408             {
00409               show_one_layer_button (l, set);
00410               PCB->Data->Layer[l].On = set;
00411             }
00412         }
00413     }
00414   lesstif_invalidate_all ();
00415 }
00416 
00417 static void
00418 layerpick_button_callback (Widget w, int layer,
00419                            XmPushButtonCallbackStruct * pbcs)
00420 {
00421   int l, i;
00422   char *name;
00423   PCB->RatDraw = (layer == LB_RATS);
00424   PCB->SilkActive = (layer == LB_SILK);
00425   if (layer < max_copper_layer)
00426     ChangeGroupVisibility (layer, 1, 1);
00427   for (l = 0; l < num_layer_buttons; l++)
00428     {
00429       LayerButtons *lb = layer_button_list + l;
00430       if (!lb->is_pick)
00431         continue;
00432       for (i = 0; i < LB_NUMPICK; i++)
00433         XmToggleButtonSetState (lb->w[i], layer == i, False);
00434     }
00435   switch (layer)
00436     {
00437     case LB_RATS:
00438       name = "Rats";
00439       break;
00440     case LB_SILK:
00441       name = "Silk";
00442       break;
00443     default:
00444       name = PCB->Data->Layer[layer].Name;
00445       break;
00446     }
00447   n = 0;
00448   stdarg (XmNbackground, fg_colors[layer]);
00449   stdarg (XmNforeground, bg_color);
00450   stdarg (XmNlabelString, XmStringCreatePCB (name));
00451   XtSetValues (lesstif_m_layer, args, n);
00452   lesstif_invalidate_all ();
00453 }
00454 
00455 static const char selectlayer_syntax[] =
00456 "SelectLayer(1..MAXLAYER|Silk|Rats)";
00457 
00458 static const char selectlayer_help[] =
00459 "Select which layer is the current layer.";
00460 
00461 /* %start-doc actions SelectLayer
00462 
00463 The specified layer becomes the currently active layer.  It is made
00464 visible if it is not already visible
00465 
00466 %end-doc */
00467 
00468 static int
00469 SelectLayer (int argc, char **argv, Coord x, Coord y)
00470 {
00471   int i;
00472   int newl = -1;
00473   if (argc == 0)
00474     return 1;
00475 
00476   for (i = 0; i < max_copper_layer; ++i)
00477     if (strcasecmp (argv[0], PCB->Data->Layer[i].Name) == 0)
00478       newl = i;
00479 
00480   if (strcasecmp (argv[0], "silk") == 0)
00481     newl = LB_SILK;
00482   else if (strcasecmp (argv[0], "rats") == 0)
00483     newl = LB_RATS;
00484   else if (newl == -1)
00485     newl = atoi (argv[0]) - 1;
00486   layerpick_button_callback (0, newl, 0);
00487   return 0;
00488 }
00489 
00490 static const char toggleview_syntax[] =
00491 "ToggleView(1..MAXLAYER)\n"
00492 "ToggleView(layername)\n"
00493 "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)";
00494 
00495 static const char toggleview_help[] =
00496 "Toggle the visibility of the specified layer or layer group.";
00497 
00498 /* %start-doc actions ToggleView
00499 
00500 If you pass an integer, that layer is specified by index (the first
00501 layer is @code{1}, etc).  If you pass a layer name, that layer is
00502 specified by name.  When a layer is specified, the visibility of the
00503 layer group containing that layer is toggled.
00504 
00505 If you pass a special layer name, the visibility of those components
00506 (silk, rats, etc) is toggled.  Note that if you have a layer named
00507 the same as a special layer, the layer is chosen over the special layer.
00508 
00509 %end-doc */
00510 
00511 static int
00512 ToggleView (int argc, char **argv, Coord x, Coord y)
00513 {
00514   int i, l;
00515 
00516   if (argc == 0)
00517     return 1;
00518   if (isdigit ((int) argv[0][0]))
00519     {
00520       l = atoi (argv[0]) - 1;
00521       layer_button_callback (0, l, 0);
00522     }
00523   else if (strcmp (argv[0], "Silk") == 0)
00524     layer_button_callback (0, LB_SILK, 0);
00525   else if (strcmp (argv[0], "Rats") == 0)
00526     layer_button_callback (0, LB_RATS, 0);
00527   else if (strcmp (argv[0], "Pins") == 0)
00528     layer_button_callback (0, LB_PINS, 0);
00529   else if (strcmp (argv[0], "Vias") == 0)
00530     layer_button_callback (0, LB_VIAS, 0);
00531   else if (strcmp (argv[0], "Mask") == 0)
00532     layer_button_callback (0, LB_MASK, 0);
00533   else if (strcmp (argv[0], "BackSide") == 0)
00534     layer_button_callback (0, LB_BACK, 0);
00535   else
00536     {
00537       l = -1;
00538       for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
00539         if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0)
00540           {
00541             l = i;
00542             break;
00543           }
00544       if (l == -1)
00545         return 1;
00546       layer_button_callback (0, l, 0);
00547     }
00548   return 0;
00549 }
00550 
00551 static void
00552 insert_layerview_buttons (Widget menu)
00553 {
00554   int i, s;
00555   LayerButtons *lb;
00556 
00557   num_layer_buttons++;
00558   s = num_layer_buttons * sizeof (LayerButtons);
00559   if (layer_button_list)
00560     layer_button_list = (LayerButtons *) realloc (layer_button_list, s);
00561   else
00562     layer_button_list = (LayerButtons *) malloc (s);
00563   lb = layer_button_list + num_layer_buttons - 1;
00564 
00565   for (i = 0; i < LB_NUM; i++)
00566     {
00567       static char namestr[] = "Label ";
00568       char *name = namestr;
00569       int accel_idx = i;
00570       Widget btn;
00571       name[5] = 'A' + i;
00572       switch (i)
00573         {
00574         case LB_SILK:
00575           name = "Silk";
00576           accel_idx = max_copper_layer;
00577           break;
00578         case LB_RATS:
00579           name = "Rat Lines";
00580           accel_idx = max_copper_layer + 1;
00581           break;
00582         case LB_PINS:
00583           name = "Pins/Pads";
00584           break;
00585         case LB_VIAS:
00586           name = "Vias";
00587           break;
00588         case LB_BACK:
00589           name = "Far Side";
00590           break;
00591         case LB_MASK:
00592           name = "Solder Mask";
00593           break;
00594         }
00595       n = 0;
00596       if (accel_idx < 9)
00597         {
00598           char buf[20], av[30];
00599           Resource *ar;
00600           XmString as;
00601           sprintf (buf, "Ctrl-%d", accel_idx + 1);
00602           as = XmStringCreatePCB (buf);
00603           stdarg (XmNacceleratorText, as);
00604           ar = resource_create (0);
00605           sprintf (av, "ToggleView(%d)", i + 1);
00606           resource_add_val (ar, 0, strdup (av), 0);
00607           resource_add_val (ar, 0, strdup (av), 0);
00608           ar->flags |= FLAG_V;
00609           sprintf (av, "Ctrl<Key>%d", accel_idx + 1);
00610           note_accelerator (av, ar);
00611           stdarg (XmNmnemonic, accel_idx + '1');
00612         }
00613       btn = XmCreateToggleButton (menu, name, args, n);
00614       XtManageChild (btn);
00615       XtAddCallback (btn, XmNvalueChangedCallback,
00616                      (XtCallbackProc) layer_button_callback, (XtPointer) (size_t) i);
00617       lb->w[i] = btn;
00618 
00619       if (i == LB_MASK)
00620         note_widget_flag (btn, XmNset, "showmask");
00621     }
00622   lb->is_pick = 0;
00623   LayersChanged (0, 0, 0, 0);
00624 }
00625 
00626 static void
00627 insert_layerpick_buttons (Widget menu)
00628 {
00629   int i, s;
00630   LayerButtons *lb;
00631 
00632   num_layer_buttons++;
00633   s = num_layer_buttons * sizeof (LayerButtons);
00634   if (layer_button_list)
00635     layer_button_list = (LayerButtons *) realloc (layer_button_list, s);
00636   else
00637     layer_button_list = (LayerButtons *) malloc (s);
00638   lb = layer_button_list + num_layer_buttons - 1;
00639 
00640   for (i = 0; i < LB_NUMPICK; i++)
00641     {
00642       static char namestr[] = "Label ";
00643       char *name = namestr;
00644       int accel_idx = i;
00645       char buf[20], av[30];
00646       Widget btn;
00647       name[5] = 'A' + i;
00648       switch (i)
00649         {
00650         case LB_SILK:
00651           name = "Silk";
00652           accel_idx = max_copper_layer;
00653           strcpy (av, "SelectLayer(Silk)");
00654           break;
00655         case LB_RATS:
00656           name = "Rat Lines";
00657           accel_idx = max_copper_layer + 1;
00658           strcpy (av, "SelectLayer(Rats)");
00659           break;
00660         default:
00661           sprintf (av, "SelectLayer(%d)", i + 1);
00662           break;
00663         }
00664       n = 0;
00665       if (accel_idx < 9)
00666         {
00667           Resource *ar;
00668           XmString as;
00669           ar = resource_create (0);
00670           resource_add_val (ar, 0, strdup (av), 0);
00671           resource_add_val (ar, 0, strdup (av), 0);
00672           ar->flags |= FLAG_V;
00673           sprintf (buf, "%d", i + 1);
00674           as = XmStringCreatePCB (buf);
00675           stdarg (XmNacceleratorText, as);
00676           sprintf (av, "<Key>%d", accel_idx + 1);
00677           note_accelerator (av, ar);
00678           stdarg (XmNmnemonic, accel_idx + '1');
00679         }
00680       stdarg (XmNindicatorType, XmONE_OF_MANY);
00681       btn = XmCreateToggleButton (menu, name, args, n);
00682       XtManageChild (btn);
00683       XtAddCallback (btn, XmNvalueChangedCallback,
00684                      (XtCallbackProc) layerpick_button_callback,
00685                      (XtPointer) (size_t) i);
00686       lb->w[i] = btn;
00687     }
00688   lb->is_pick = 1;
00689   LayersChanged (0, 0, 0, 0);
00690 }
00691 
00692 /*-----------------------------------------------------------------------------*/
00693 
00694 typedef struct
00695 {
00696   Widget w;
00697   const char *flagname;
00698   int oldval;
00699   char *xres;
00700 } WidgetFlagType;
00701 
00702 static WidgetFlagType *wflags = 0;
00703 static int n_wflags = 0;
00704 static int max_wflags = 0;
00705 
00706 static void
00707 note_widget_flag (Widget w, char *type, char *name)
00708 {
00709   if (n_wflags >= max_wflags)
00710     {
00711       max_wflags += 20;
00712       wflags = (WidgetFlagType *) realloc (wflags, max_wflags * sizeof (WidgetFlagType));
00713     }
00714   wflags[n_wflags].w = w;
00715   wflags[n_wflags].flagname = name;
00716   wflags[n_wflags].oldval = -1;
00717   wflags[n_wflags].xres = type;
00718   n_wflags++;
00719 }
00720 
00721 void
00722 lesstif_update_widget_flags ()
00723 {
00724   int i;
00725 
00726   for (i = 0; i < n_wflags; i++)
00727     {
00728       int v = hid_get_flag (wflags[i].flagname);
00729       Arg args[1];
00730       XtSetArg (args[0], wflags[i].xres, v ? 1 : 0);
00731       XtSetValues (wflags[i].w, args, 1);
00732       wflags[i].oldval = v;
00733     }
00734 }
00735 
00736 /*-----------------------------------------------------------------------------*/
00737 
00738 HID_Action lesstif_menu_action_list[] = {
00739   {"DumpKeys", 0, DumpKeys,
00740    dumpkeys_help, dumpkeys_syntax},
00741   {"Debug", 0, Debug,
00742    debug_help, debug_syntax},
00743   {"DebugXY", "Click X,Y for Debug", Debug,
00744    debugxy_help, debugxy_syntax},
00745   {"GetXY", "", GetXY,
00746    getxy_help, getxy_syntax},
00747   {"Return", 0, Return,
00748    return_help, return_syntax},
00749   {"LayersChanged", 0, LayersChanged,
00750    layerschanged_help, layerschanged_syntax},
00751   {"ToggleView", 0, ToggleView,
00752    toggleview_help, toggleview_syntax},
00753   {"SelectLayer", 0, SelectLayer,
00754    selectlayer_help, selectlayer_syntax}
00755 };
00756 
00757 REGISTER_ACTIONS (lesstif_menu_action_list)
00758 
00759 #if 0
00760 static void
00761 do_color (char *value, char *which)
00762 {
00763   XColor color;
00764   if (XParseColor (display, cmap, value, &color))
00765     if (XAllocColor (display, cmap, &color))
00766       {
00767         stdarg (which, color.pixel);
00768       }
00769 }
00770 #endif
00771 
00772 typedef struct ToggleItem
00773 {
00774   struct ToggleItem *next;
00775   Widget w;
00776   char *group, *item;
00777   XtCallbackProc callback;
00778   Resource *node;
00779 } ToggleItem;
00780 static ToggleItem *toggle_items = 0;
00781 
00782 static int need_xy = 0, have_xy = 0, action_x, action_y;
00783 
00784 static void
00785 radio_callback (Widget toggle, ToggleItem * me,
00786                 XmToggleButtonCallbackStruct * cbs)
00787 {
00788   if (!cbs->set)                /* uh uh, can't turn it off */
00789     XmToggleButtonSetState (toggle, 1, 0);
00790   else
00791     {
00792       ToggleItem *ti;
00793       for (ti = toggle_items; ti; ti = ti->next)
00794         if (strcmp (me->group, ti->group) == 0)
00795           {
00796             if (me->item == ti->item || strcmp (me->item, ti->item) == 0)
00797               XmToggleButtonSetState (ti->w, 1, 0);
00798             else
00799               XmToggleButtonSetState (ti->w, 0, 0);
00800           }
00801       me->callback (toggle, me->node, cbs);
00802     }
00803 }
00804 
00805 int
00806 lesstif_button_event (Widget w, XEvent * e)
00807 {
00808   have_xy = 1;
00809   action_x = e->xbutton.x;
00810   action_y = e->xbutton.y;
00811   if (!need_xy)
00812     return 0;
00813   if (w != work_area)
00814     return 1;
00815   return 0;
00816 }
00817 
00818 void
00819 lesstif_get_xy (const char *message)
00820 {
00821   XmString ls = XmStringCreatePCB ((char *)message);
00822 
00823   XtManageChild (m_click);
00824   n = 0;
00825   stdarg (XmNlabelString, ls);
00826   XtSetValues (m_click, args, n);
00827   //printf("need xy: msg `%s'\n", msg);
00828   need_xy = 1;
00829   XBell (display, 100);
00830   while (!have_xy)
00831     {
00832       XEvent e;
00833       XtAppNextEvent (app_context, &e);
00834       XtDispatchEvent (&e);
00835     }
00836   need_xy = 0;
00837   have_xy = 1;
00838   XtUnmanageChild (m_click);
00839 }
00840 
00841 void
00842 lesstif_get_coords (const char *msg, Coord *px, Coord *py)
00843 {
00844   if (!have_xy && msg)
00845     lesstif_get_xy (msg);
00846   if (have_xy)
00847     lesstif_coords_to_pcb (action_x, action_y, px, py);
00848 }
00849 
00850 static void
00851 callback (Widget w, Resource * node, XmPushButtonCallbackStruct * pbcs)
00852 {
00853   int vi;
00854   have_xy = 0;
00855   lesstif_show_crosshair (0);
00856   if (pbcs->event && pbcs->event->type == KeyPress)
00857     {
00858       Dimension wx, wy;
00859       Widget aw = XtWindowToWidget (display, pbcs->event->xkey.window);
00860       action_x = pbcs->event->xkey.x;
00861       action_y = pbcs->event->xkey.y;
00862       if (aw)
00863         {
00864           Widget p = work_area;
00865           while (p && p != aw)
00866             {
00867               n = 0;
00868               stdarg (XmNx, &wx);
00869               stdarg (XmNy, &wy);
00870               XtGetValues (p, args, n);
00871               action_x -= wx;
00872               action_y -= wy;
00873               p = XtParent (p);
00874             }
00875           if (p == aw)
00876             have_xy = 1;
00877         }
00878       //pcb_printf("have xy from %s: %$mD\n", XtName(aw), action_x, action_y);
00879     }
00880 
00881   lesstif_need_idle_proc ();
00882   for (vi = 1; vi < node->c; vi++)
00883     if (resource_type (node->v[vi]) == 10)
00884       if (hid_parse_actions (node->v[vi].value))
00885         return;
00886 }
00887 
00888 typedef struct acc_table_t
00889 {
00890   char mods;
00891   char key_char;
00892   union {
00893     /* If M_Multi is set in mods, these are used to chain to the next
00894        attribute table for multi-key accelerators.  */
00895     struct {
00896       int n_chain;
00897       struct acc_table_t *chain;
00898     } c;
00899     /* If M_Multi isn't set, these are used to map a single key to an
00900        event.  */
00901     struct {
00902       KeySym key;
00903       Resource *node;
00904     } a;
00905   } u;
00906 } acc_table_t;
00907 
00908 static acc_table_t *acc_table;
00909 static int acc_num = 0;
00910 
00911 static int
00912 acc_sort (const void *va, const void *vb)
00913 {
00914   acc_table_t *a = (acc_table_t *) va;
00915   acc_table_t *b = (acc_table_t *) vb;
00916   if (a->key_char != b->key_char)
00917     return a->key_char - b->key_char;
00918   if (!(a->mods & M_Multi))
00919     if (a->u.a.key != b->u.a.key)
00920       return a->u.a.key - b->u.a.key;
00921   return a->mods - b->mods;
00922 }
00923 
00924 static int
00925 DumpKeys2 ()
00926 {
00927   int i;
00928   char ch[2];
00929   printf ("in dumpkeys! %d\n", acc_num);
00930   qsort (acc_table, acc_num, sizeof (acc_table_t), acc_sort);
00931   ch[1] = 0;
00932   for (i = 0; i < acc_num; i++)
00933     {
00934       char mod[16];
00935       int vi;
00936       char *tabs = "";
00937 
00938       sprintf (mod, "%s%s%s",
00939                acc_table[i].mods & M_Alt ? "Alt-" : "",
00940                acc_table[i].mods & M_Ctrl ? "Ctrl-" : "",
00941                acc_table[i].mods & M_Shift ? "Shift-" : "");
00942       ch[0] = toupper ((int)  acc_table[i].key_char);
00943       printf ("%16s%s\t", mod,
00944               acc_table[i].key_char ? ch : XKeysymToString (acc_table[i].
00945                                                             u.a.key));
00946 
00947       for (vi = 1; vi < acc_table[i].u.a.node->c; vi++)
00948         if (resource_type (acc_table[i].u.a.node->v[vi]) == 10)
00949           {
00950             printf ("%s%s", tabs, acc_table[i].u.a.node->v[vi].value);
00951             tabs = "\n\t\t\t  ";
00952           }
00953 
00954       printf ("\n");
00955     }
00956   exit (0);
00957 }
00958 
00959 static acc_table_t *
00960 find_or_create_acc (char mods, char key, KeySym sym,
00961                     acc_table_t **table, int *n_ents)
00962 {
00963   int i, max;
00964   acc_table_t *a;
00965 
00966   if (*table)
00967     for (i=(*n_ents)-1; i>=0; i--)
00968       {
00969         a = & (*table)[i];
00970         if (a->mods == mods
00971             && a->key_char == key
00972             && (mods & M_Multi || a->u.a.key == sym))
00973           return a;
00974       }
00975 
00976   (*n_ents) ++;
00977   max = (*n_ents + 16) & ~15;
00978 
00979   if (*table)
00980     *table = (acc_table_t *) realloc (*table, max * sizeof (acc_table_t));
00981   else
00982     *table = (acc_table_t *) malloc (max * sizeof (acc_table_t));
00983 
00984   a = & ((*table)[(*n_ents)-1]);
00985   memset (a, 0, sizeof(acc_table_t));
00986 
00987   a->mods = mods;
00988   a->key_char = key;
00989   if (!(mods & M_Multi))
00990     a->u.a.key = sym;
00991 
00992   return a;
00993 }
00994 
00995 static void
00996 note_accelerator (char *acc, Resource * node)
00997 {
00998   char *orig_acc = acc;
00999   int mods = 0;
01000   acc_table_t *a;
01001   char key_char = 0;
01002   KeySym key = 0;
01003   int multi_key = 0;
01004 
01005   while (isalpha ((int) acc[0]))
01006     {
01007       if (strncmp (acc, "Shift", 5) == 0)
01008         {
01009           mods |= M_Shift;
01010           acc += 5;
01011         }
01012       else if (strncmp (acc, "Ctrl", 4) == 0)
01013         {
01014           mods |= M_Ctrl;
01015           acc += 4;
01016         }
01017       else if (strncmp (acc, "Alt", 3) == 0)
01018         {
01019           mods |= M_Alt;
01020           acc += 3;
01021         }
01022       else
01023         {
01024           printf ("Must be Shift/Ctrl/Alt: %s\n", acc);
01025           return;
01026         }
01027       while (*acc == ' ')
01028         acc++;
01029     }
01030   if (strncmp (acc, "<Keys>", 6) == 0)
01031     {
01032       multi_key = 1;
01033       acc ++;
01034     }
01035   else if (strncmp (acc, "<Key>", 5))
01036     {
01037       fprintf (stderr, "accelerator \"%s\" not <Key> or <Keys>\n", orig_acc);
01038       return;
01039     }
01040 
01041   /* We have a hard time specifying the Enter key the "usual" way.  */
01042   if (strcmp (acc, "<Key>Enter") == 0)
01043     acc = "<Key>\r";
01044 
01045   acc += 5;
01046   if (acc[0] && acc[1] == 0)
01047     {
01048       key_char = acc[0];
01049       a = find_or_create_acc (mods, key_char, 0, &acc_table, &acc_num);
01050     }
01051   else if (multi_key)
01052     {
01053       acc_table_t **ap = &acc_table;
01054       int *np = &acc_num;
01055 
01056       mods |= M_Multi;
01057       while (acc[0] && acc[1])
01058         {
01059           a = find_or_create_acc (mods, acc[0], 0, ap, np);
01060           ap = & (a->u.c.chain);
01061           np = & (a->u.c.n_chain);
01062           acc ++;
01063         }
01064       a = find_or_create_acc (mods & ~M_Multi, acc[0], 0, ap, np);
01065     }
01066   else
01067     {
01068       key = XStringToKeysym (acc);
01069       if (key == NoSymbol && !key_char)
01070         {
01071           printf ("no symbol for %s\n", acc);
01072           return;
01073         }
01074       a = find_or_create_acc (mods, 0, key, &acc_table, &acc_num);
01075     }
01076 
01077   a->u.a.node = node;
01078 }
01079 
01080 #if 0
01081 static void
01082 dump_multi (int ix, int ind, acc_table_t *a, int n)
01083 {
01084   int i = ix;
01085   while (n--)
01086     {
01087       if (a->mods & M_Multi)
01088         {
01089           printf("%*cacc[%d] mods %x char %c multi %p/%d\n",
01090                  ind, ' ',
01091                  i, a->mods, a->key_char,
01092                  a->u.c.chain, a->u.c.n_chain);
01093           dump_multi(0, ind+4, a->u.c.chain, a->u.c.n_chain);
01094         }
01095       else
01096         {
01097           printf("%*cacc[%d] mods %x char %c key %d node `%s'\n",
01098                  ind, ' ',
01099                  i, a->mods, a->key_char,
01100                  a->u.a.key, a->u.a.node->v[0].value);
01101         }
01102       a++;
01103       i++;
01104     }
01105 }
01106 #else
01107 #define dump_multi(x,a,b,c)
01108 #endif
01109 
01110 static acc_table_t *cur_table = 0;
01111 static int cur_ntable = 0;
01112 
01120 static int
01121 acc_sort_rev (const void *va, const void *vb)
01122 {
01123   acc_table_t *a = (acc_table_t *) va;
01124   acc_table_t *b = (acc_table_t *) vb;
01125   if (a->key_char != b->key_char)
01126     return a->key_char - b->key_char;
01127   if (!(a->mods & M_Multi))
01128     if (a->u.a.key != b->u.a.key)
01129       return a->u.a.key - b->u.a.key;
01130   return b->mods - a->mods;
01131 }
01132 
01133 int
01134 lesstif_key_event (XKeyEvent * e)
01135 {
01136   char buf[10], buf2[10];
01137   KeySym sym, sym2;
01138   int slen, slen2;
01139   int mods = 0;
01140   int i, vi;
01141   static int sorted = 0;
01142   acc_table_t *my_table = 0;
01143 
01144   if (!sorted)
01145     {
01146       sorted = 1;
01147       qsort (acc_table, acc_num, sizeof (acc_table_t), acc_sort_rev);
01148     }
01149 
01150   if (e->state & ShiftMask)
01151     mods |= M_Shift;
01152   if (e->state & ControlMask)
01153     mods |= M_Ctrl;
01154   if (e->state & Mod1Mask)
01155     mods |= M_Alt;
01156 
01157   e->state &= ~(ControlMask | Mod1Mask);
01158   slen = XLookupString (e, buf, sizeof (buf), &sym, NULL);
01159 
01160   if (e->state & ShiftMask)
01161     {
01162       e->state &= ~ShiftMask;
01163       slen2 = XLookupString (e, buf2, sizeof (buf2), &sym2, NULL);
01164     }
01165   else
01166     slen2 = slen;
01167 
01168   /* Ignore these.  */
01169   switch (sym)
01170     {
01171     case XK_Shift_L:
01172     case XK_Shift_R:
01173     case XK_Control_L:
01174     case XK_Control_R:
01175     case XK_Caps_Lock:
01176     case XK_Shift_Lock:
01177     case XK_Meta_L:
01178     case XK_Meta_R:
01179     case XK_Alt_L:
01180     case XK_Alt_R:
01181     case XK_Super_L:
01182     case XK_Super_R:
01183     case XK_Hyper_L:
01184     case XK_Hyper_R:
01185     case XK_ISO_Level3_Shift:
01186       return 1;
01187     }
01188 
01189   if (cur_table == 0)
01190     {
01191       cur_table  = acc_table;
01192       cur_ntable = acc_num;
01193     }
01194 
01195   //printf("\nmods %x key %d str `%s' in %p/%d\n", mods, (int)sym, buf, cur_table, cur_ntable);
01196 
01197 #define KM(m) ((m) & ~M_Multi)
01198   for (i = 0; i < cur_ntable; i++)
01199     {
01200       dump_multi (i, 0, cur_table+i, 1);
01201       if (KM(cur_table[i].mods) == mods)
01202         {
01203           if (sym == acc_table[i].u.a.key)
01204             break;
01205         }
01206       if (KM(cur_table[i].mods) == (mods & ~M_Shift))
01207         {
01208           if (slen == 1 && buf[0] == cur_table[i].key_char)
01209             break;
01210           if (sym == cur_table[i].u.a.key)
01211             break;
01212         }
01213       if (mods & M_Shift && KM(cur_table[i].mods) == mods)
01214         {
01215           if (slen2 == 1 && buf2[0] == cur_table[i].key_char)
01216             break;
01217           if (sym2 == acc_table[i].u.a.key)
01218             break;
01219         }
01220     }
01221 
01222   if (i == cur_ntable)
01223     {
01224       if (cur_table == acc_table)
01225         lesstif_log ("Key \"%s\" not tied to an action\n", buf);
01226       else
01227         lesstif_log ("Key \"%s\" not tied to a multi-key action\n", buf);
01228       cur_table = 0;
01229       return 0;
01230     }
01231   if (cur_table[i].mods & M_Multi)
01232     {
01233       cur_ntable = cur_table[i].u.c.n_chain;
01234       cur_table = cur_table[i].u.c.chain;
01235       dump_multi (0, 0, cur_table, cur_ntable);
01236       return 1;
01237     }
01238 
01239   if (e->window == XtWindow (work_area))
01240     {
01241       have_xy = 1;
01242       action_x = e->x;
01243       action_y = e->y;
01244     }
01245   else
01246     have_xy = 0;
01247 
01248   /* Parsing actions may not return until more user interaction
01249      happens, so remember which table we're scanning.  */
01250   my_table = cur_table;
01251   for (vi = 1; vi < my_table[i].u.a.node->c; vi++)
01252     if (resource_type (my_table[i].u.a.node->v[vi]) == 10)
01253       if (hid_parse_actions
01254           (my_table[i].u.a.node->v[vi].value))
01255         break;
01256   cur_table = 0;
01257   return 1;
01258 }
01259 
01260 static void
01261 add_resource_to_menu (Widget menu, Resource * node, XtCallbackProc callback)
01262 {
01263   int i, j;
01264   char *v;
01265   Widget sub, btn;
01266   Resource *r;
01267 
01268   for (i = 0; i < node->c; i++)
01269     switch (resource_type (node->v[i]))
01270       {
01271       case 101:         /* named subnode */
01272         n = 0;
01273         stdarg (XmNtearOffModel, XmTEAR_OFF_ENABLED);
01274         sub = XmCreatePulldownMenu (menu, node->v[i].name, args, n);
01275         XtSetValues (sub, args, n);
01276         n = 0;
01277         stdarg (XmNsubMenuId, sub);
01278         btn = XmCreateCascadeButton (menu, node->v[i].name, args, n);
01279         XtManageChild (btn);
01280         add_resource_to_menu (sub, node->v[i].subres, callback);
01281         break;
01282 
01283       case 1:                   /* unnamed subres */
01284         n = 0;
01285 #if 0
01286         if ((v = resource_value (node->v[i].subres, "fg")))
01287           {
01288             do_color (v, XmNforeground);
01289           }
01290         if ((v = resource_value (node->v[i].subres, "bg")))
01291           {
01292             do_color (v, XmNbackground);
01293           }
01294         if ((v = resource_value (node->v[i].subres, "font")))
01295           {
01296             XFontStruct *fs = XLoadQueryFont (display, v);
01297             if (fs)
01298               {
01299                 XmFontList fl =
01300                   XmFontListCreate (fs, XmSTRING_DEFAULT_CHARSET);
01301                 stdarg (XmNfontList, fl);
01302               }
01303           }
01304 #endif
01305         if ((v = resource_value (node->v[i].subres, "m")))
01306           {
01307             stdarg (XmNmnemonic, v);
01308           }
01309         if ((r = resource_subres (node->v[i].subres, "a")))
01310           {
01311             XmString as = XmStringCreatePCB (r->v[0].value);
01312             stdarg (XmNacceleratorText, as);
01313             //stdarg(XmNaccelerator, r->v[1].value);
01314             note_accelerator (r->v[1].value, node->v[i].subres);
01315           }
01316         v = "button";
01317         for (j = 0; j < node->v[i].subres->c; j++)
01318           if (resource_type (node->v[i].subres->v[j]) == 10)
01319             {
01320               v = node->v[i].subres->v[j].value;
01321               break;
01322             }
01323         stdarg (XmNlabelString, XmStringCreatePCB (v));
01324         if (node->v[i].subres->flags & FLAG_S)
01325           {
01326             int nn = n;
01327             stdarg (XmNtearOffModel, XmTEAR_OFF_ENABLED);
01328             sub = XmCreatePulldownMenu (menu, v, args + nn, n - nn);
01329             n = nn;
01330             stdarg (XmNsubMenuId, sub);
01331             btn = XmCreateCascadeButton (menu, "menubutton", args, n);
01332             XtManageChild (btn);
01333             add_resource_to_menu (sub, node->v[i].subres, callback);
01334           }
01335         else
01336           {
01337             Resource *radio = resource_subres (node->v[i].subres, "radio");
01338             char *checked = resource_value (node->v[i].subres, "checked");
01339             char *label = resource_value (node->v[i].subres, "sensitive");
01340             if (radio)
01341               {
01342                 ToggleItem *ti = (ToggleItem *) malloc (sizeof (ToggleItem));
01343                 ti->next = toggle_items;
01344                 ti->group = radio->v[0].value;
01345                 ti->item = radio->v[1].value;
01346                 ti->callback = callback;
01347                 ti->node = node->v[i].subres;
01348                 toggle_items = ti;
01349 
01350                 if (resource_value (node->v[i].subres, "set"))
01351                   {
01352                     stdarg (XmNset, True);
01353                   }
01354                 stdarg (XmNindicatorType, XmONE_OF_MANY);
01355                 btn = XmCreateToggleButton (menu, "menubutton", args, n);
01356                 ti->w = btn;
01357                 XtAddCallback (btn, XmNvalueChangedCallback,
01358                                (XtCallbackProc) radio_callback,
01359                                (XtPointer) ti);
01360               }
01361             else if (checked)
01362               {
01363                 if (strchr (checked, ','))
01364                   stdarg (XmNindicatorType, XmONE_OF_MANY);
01365                 else
01366                   stdarg (XmNindicatorType, XmN_OF_MANY);
01367                 btn = XmCreateToggleButton (menu, "menubutton", args, n);
01368                 XtAddCallback (btn, XmNvalueChangedCallback,
01369                                callback, (XtPointer) node->v[i].subres);
01370               }
01371             else if (label && strcmp (label, "false") == 0)
01372               {
01373                 stdarg (XmNalignment, XmALIGNMENT_BEGINNING);
01374                 btn = XmCreateLabel (menu, "menulabel", args, n);
01375               }
01376             else
01377               {
01378                 btn = XmCreatePushButton (menu, "menubutton", args, n);
01379                 XtAddCallback (btn, XmNactivateCallback,
01380                                callback, (XtPointer) node->v[i].subres);
01381               }
01382 
01383             for (j = 0; j < node->v[i].subres->c; j++)
01384               switch (resource_type (node->v[i].subres->v[j]))
01385                 {
01386                 case 110:       /* named value = X resource */
01387                   {
01388                     char *n = node->v[i].subres->v[j].name;
01389                     if (strcmp (n, "fg") == 0)
01390                       n = "foreground";
01391                     if (strcmp (n, "bg") == 0)
01392                       n = "background";
01393                     if (strcmp (n, "m") == 0
01394                         || strcmp (n, "a") == 0
01395                         || strcmp (n, "sensitive") == 0)
01396                       break;
01397                     if (strcmp (n, "checked") == 0)
01398                       {
01399                         note_widget_flag (btn, XmNset,
01400                                           node->v[i].subres->v[j].value);
01401                         break;
01402                       }
01403                     if (strcmp (n, "active") == 0)
01404                       {
01405                         note_widget_flag (btn, XmNsensitive,
01406                                           node->v[i].subres->v[j].value);
01407                         break;
01408                       }
01409                     XtVaSetValues (btn, XtVaTypedArg,
01410                                    n,
01411                                    XtRString,
01412                                    node->v[i].subres->v[j].value,
01413                                    strlen (node->v[i].subres->v[j].value) + 1,
01414                                    NULL);
01415                   }
01416                   break;
01417                 }
01418 
01419             XtManageChild (btn);
01420           }
01421         break;
01422 
01423       case 10:                  /* unnamed value */
01424         n = 0;
01425         if (node->v[i].value[0] == '@')
01426           {
01427             if (strcmp (node->v[i].value, "@layerview") == 0)
01428               insert_layerview_buttons (menu);
01429             if (strcmp (node->v[i].value, "@layerpick") == 0)
01430               insert_layerpick_buttons (menu);
01431             if (strcmp (node->v[i].value, "@routestyles") == 0)
01432               lesstif_insert_style_buttons (menu);
01433           }
01434         else if (strcmp (node->v[i].value, "-") == 0)
01435           {
01436             btn = XmCreateSeparator (menu, "sep", args, n);
01437             XtManageChild (btn);
01438           }
01439         else if (i > 0)
01440           {
01441             btn = XmCreatePushButton (menu, node->v[i].value, args, n);
01442             XtManageChild (btn);
01443           }
01444         break;
01445       }
01446 }
01447 
01448 extern char *lesstif_pcbmenu_path;
01449 
01450 Widget
01451 lesstif_menu (Widget parent, char *name, Arg * margs, int mn)
01452 {
01453   Widget mb = XmCreateMenuBar (parent, name, margs, mn);
01454   char *filename;
01455   Resource *r = 0, *bir;
01456   char *home_pcbmenu, *home;
01457   int screen;
01458   Resource *mr;
01459 
01460   display = XtDisplay (mb);
01461   screen = DefaultScreen (display);
01462   cmap = DefaultColormap (display, screen);
01463 
01464   /* homedir is set by the core */
01465   home = homedir;
01466   home_pcbmenu = NULL;
01467   if (home == NULL)
01468     {
01469       Message ("Warning:  could not determine home directory (from HOME)\n");
01470     }
01471   else 
01472     {
01473       home_pcbmenu = Concat (home, PCB_DIR_SEPARATOR_S, ".pcb", 
01474          PCB_DIR_SEPARATOR_S, "pcb-menu.res", NULL);
01475     }
01476 
01477   if (access ("pcb-menu.res", R_OK) == 0)
01478     filename = "pcb-menu.res";
01479   else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0))
01480     filename = home_pcbmenu;
01481   else if (access (lesstif_pcbmenu_path, R_OK) == 0)
01482     filename = lesstif_pcbmenu_path;
01483   else
01484     filename = 0;
01485 
01486   bir = resource_parse (0, pcb_menu_default);
01487   if (!bir)
01488     {
01489       fprintf (stderr, "Error: internal menu resource didn't parse\n");
01490       exit(1);
01491     }
01492 
01493   if (filename)
01494     r = resource_parse (filename, 0);
01495 
01496   if (!r)
01497     r = bir;
01498 
01499   if (home_pcbmenu != NULL)
01500     {
01501       free (home_pcbmenu);
01502     }
01503 
01504   mr = resource_subres (r, "MainMenu");
01505   if (!mr)
01506     mr = resource_subres (bir, "MainMenu");
01507   if (mr)
01508     add_resource_to_menu (mb, mr, (XtCallbackProc) callback);
01509 
01510   mr = resource_subres (r, "Mouse");
01511   if (!mr)
01512     mr = resource_subres (bir, "Mouse");
01513   if (mr)
01514     load_mouse_resource (mr);
01515 
01516 
01517   if (do_dump_keys)
01518     DumpKeys2 ();
01519 
01520   return mb;
01521 }
01522 
01523 void lesstif_uninit_menu (void)
01524 {
01526 }