pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 }