pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00034 #ifdef HAVE_CONFIG_H 00035 #include "config.h" 00036 #endif 00037 00038 #include <stdio.h> 00039 #include <stdlib.h> 00040 #include <time.h> 00041 #include <string.h> 00042 #include <math.h> 00043 #include <unistd.h> 00044 #include <signal.h> 00045 #include <sys/time.h> 00046 00047 #include "xincludes.h" 00048 00049 #include "global.h" 00050 #include "data.h" 00051 #include "action.h" 00052 #include "crosshair.h" 00053 #include "mymem.h" 00054 #include "misc.h" 00055 #include "pcb-printf.h" 00056 #include "resource.h" 00057 #include "clip.h" 00058 #include "error.h" 00059 00060 #include "hid.h" 00061 #include "hid_draw.h" 00062 #include "../hidint.h" 00063 #include "hid/common/hidnogui.h" 00064 #include "hid/common/draw_helpers.h" 00065 #include "hid/common/hid_resource.h" 00066 #include "lesstif.h" 00067 00068 #ifdef HAVE_LIBDMALLOC 00069 #include <dmalloc.h> 00070 #endif 00071 00072 #include <sys/poll.h> 00073 00074 #ifndef XtRDouble 00075 #define XtRDouble "Double" 00076 #endif 00077 00078 /* How big the viewport can be relative to the pcb size. */ 00079 #define MAX_ZOOM_SCALE 10 00080 #define UUNIT Settings.grid_unit->allow 00081 00082 typedef struct hid_gc_struct 00083 { 00084 HID *me_pointer; 00085 Pixel color; 00086 const char *colorname; 00087 int width; 00088 EndCapStyle cap; 00089 char xor_set; 00090 char erase; 00091 } hid_gc_struct; 00092 00093 static HID lesstif_hid; 00094 static HID_DRAW lesstif_graphics; 00095 00096 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented GUI function %s\n", __FUNCTION__), abort() 00097 00098 XtAppContext app_context; 00099 Widget appwidget; 00100 Display *display; 00101 static Window window = 0; 00102 static Cursor my_cursor = 0; 00103 static int old_cursor_mode = -1; 00104 static int over_point = 0; 00105 00106 /* The first is the "current" pixmap. The main_ is the real one we 00107 usually use, the mask_ are the ones for doing polygon masks. The 00108 pixmap is the saved pixels, the bitmap is for the "erase" color. 00109 We set pixmap to point to main_pixmap or mask_pixmap as needed. */ 00110 static Pixmap pixmap = 0; 00111 static Pixmap main_pixmap = 0; 00112 static Pixmap mask_pixmap = 0; 00113 static Pixmap mask_bitmap = 0; 00114 static enum mask_mode use_mask = HID_MASK_OFF; 00115 00116 static int use_xrender = 0; 00117 #ifdef HAVE_XRENDER 00118 static Picture main_picture; 00119 static Picture mask_picture; 00120 static Pixmap pale_pixmap; 00121 static Picture pale_picture; 00122 #endif /* HAVE_XRENDER */ 00123 00124 static int pixmap_w = 0, pixmap_h = 0; 00125 Screen *screen_s; 00126 int screen; 00127 static Colormap colormap; 00128 static GC my_gc = 0, bg_gc, clip_gc = 0, bset_gc = 0, bclear_gc = 0, mask_gc = 00129 0; 00130 static Pixel bgcolor, offlimit_color, grid_color; 00131 static int bgred, bggreen, bgblue; 00132 00133 static GC arc1_gc, arc2_gc; 00134 00135 static hidGC crosshair_gc; 00136 00137 /* These are for the pinout windows. */ 00138 typedef struct PinoutData 00139 { 00140 struct PinoutData *prev, *next; 00141 Widget form; 00142 Window window; 00143 Coord left, right, top, bottom; /* PCB extents of item */ 00144 Coord x, y; /* PCB coordinates of upper right corner of window */ 00145 double zoom; /* PCB units per screen pixel */ 00146 int v_width, v_height; /* pixels */ 00147 void *item; 00148 } PinoutData; 00149 00150 /* Linked list of all pinout windows. */ 00151 static PinoutData *pinouts = 0; 00152 /* If set, we are currently updating this pinout window. */ 00153 static PinoutData *pinout = 0; 00154 00155 static int crosshair_x = 0, crosshair_y = 0; 00156 static int in_move_event = 0, crosshair_in_window = 1; 00157 00158 Widget mainwind; 00159 Widget work_area, messages, command, hscroll, vscroll; 00160 static Widget m_mark, m_crosshair, m_grid, m_zoom, m_mode, m_status; 00161 static Widget m_rats; 00162 Widget lesstif_m_layer; 00163 Widget m_click; 00164 00165 /* This is the size, in pixels, of the viewport. */ 00166 static int view_width, view_height; 00167 /* This is the PCB location represented by the upper left corner of 00168 the viewport. Note that PCB coordinates put 0,0 in the upper left, 00169 much like X does. */ 00170 static int view_left_x = 0, view_top_y = 0; 00171 /* Denotes PCB units per screen pixel. Larger numbers mean zooming 00172 out - the largest value means you are looking at the whole 00173 board. */ 00174 static double view_zoom = MIL_TO_COORD (10), prev_view_zoom = MIL_TO_COORD (10); 00175 static bool flip_x = 0, flip_y = 0; 00176 static bool autofade = 0; 00177 static bool crosshair_on = true; 00178 00179 /* --------------------------------------------------------------------------- 00180 * some local prototypes 00181 */ 00182 static hidGC lesstif_make_gc (void); 00183 00184 static void 00185 ShowCrosshair (bool show) 00186 { 00187 if (crosshair_on == show) 00188 return; 00189 00190 notify_crosshair_change (false); 00191 if (Marked.status) 00192 notify_mark_change (false); 00193 00194 crosshair_on = show; 00195 00196 notify_crosshair_change (true); 00197 if (Marked.status) 00198 notify_mark_change (true); 00199 } 00200 00201 static int 00202 flag_flipx (void *data) 00203 { 00204 return flip_x; 00205 } 00206 static int 00207 flag_flipy (void *data) 00208 { 00209 return flip_y; 00210 } 00211 00212 HID_Flag lesstif_main_flag_list[] = { 00213 {"flip_x", flag_flipx, NULL}, 00214 {"flip_y", flag_flipy, NULL} 00215 }; 00216 00217 REGISTER_FLAGS (lesstif_main_flag_list) 00218 00219 /* This is the size of the current PCB work area. */ 00220 /* Use PCB->MaxWidth, PCB->MaxHeight. */ 00221 /* static int pcb_width, pcb_height; */ 00222 00223 static Arg args[30]; 00224 static int n; 00225 #define stdarg(t,v) XtSetArg(args[n], t, v), n++ 00226 00227 00228 static int use_private_colormap = 0; 00229 static int stdin_listen = 0; 00230 static char *background_image_file = 0; 00231 char *lesstif_pcbmenu_path = "pcb-menu.res"; 00232 00233 HID_Attribute lesstif_attribute_list[] = { 00234 {"install", "Install private colormap", 00235 HID_Boolean, 0, 0, {0, 0, 0}, 0, &use_private_colormap}, 00236 #define HA_colormap 0 00237 00238 /* %start-doc options "22 lesstif GUI Options" 00239 @ftable @code 00240 @item --listen 00241 Listen for actions on stdin. 00242 @end ftable 00243 %end-doc 00244 */ 00245 {"listen", "Listen on standard input for actions", 00246 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen}, 00247 #define HA_listen 1 00248 00249 /* %start-doc options "22 lesstif GUI Options" 00250 @ftable @code 00251 @item --bg-image <string> 00252 File name of an image to put into the background of the GUI canvas. The image must 00253 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be 00254 automatically scaled to fit the canvas. 00255 @end ftable 00256 %end-doc 00257 */ 00258 {"bg-image", "Background Image", 00259 HID_String, 0, 0, {0, 0, 0}, 0, &background_image_file}, 00260 #define HA_bg_image 2 00261 00262 /* %start-doc options "22 lesstif GUI Options" 00263 @ftable @code 00264 @item --pcb-menu <string> 00265 Location of the @file{pcb-menu.res} file which defines the menu for the lesstif GUI. 00266 @end ftable 00267 %end-doc 00268 */ 00269 {"pcb-menu", "Location of pcb-menu.res file", 00270 HID_String, 0, 0, {0, PCBLIBDIR "/pcb-menu.res", 0}, 0, &lesstif_pcbmenu_path} 00271 #define HA_pcbmenu 3 00272 }; 00273 00274 REGISTER_ATTRIBUTES (lesstif_attribute_list) 00275 00276 static void lesstif_use_mask (enum mask_mode mode); 00277 static void zoom_max (); 00278 static void zoom_to (double factor, int x, int y); 00279 static void zoom_by (double factor, int x, int y); 00280 static void zoom_toggle (int x, int y); 00281 static void pinout_callback (Widget, PinoutData *, 00282 XmDrawingAreaCallbackStruct *); 00283 static void pinout_unmap (Widget, PinoutData *, void *); 00284 static void Pan (int mode, int x, int y); 00285 00286 /* Px converts view->pcb, Vx converts pcb->view */ 00287 00288 static inline int 00289 Vx (Coord x) 00290 { 00291 int rv = (x - view_left_x) / view_zoom + 0.5; 00292 if (flip_x) 00293 rv = view_width - rv; 00294 return rv; 00295 } 00296 00297 static inline int 00298 Vy (Coord y) 00299 { 00300 int rv = (y - view_top_y) / view_zoom + 0.5; 00301 if (flip_y) 00302 rv = view_height - rv; 00303 return rv; 00304 } 00305 00306 static inline int 00307 Vz (Coord z) 00308 { 00309 return z / view_zoom + 0.5; 00310 } 00311 00312 static inline Coord 00313 Px (int x) 00314 { 00315 if (flip_x) 00316 x = view_width - x; 00317 return x * view_zoom + view_left_x; 00318 } 00319 00320 static inline Coord 00321 Py (int y) 00322 { 00323 if (flip_y) 00324 y = view_height - y; 00325 return y * view_zoom + view_top_y; 00326 } 00327 00328 static inline Coord 00329 Pz (int z) 00330 { 00331 return z * view_zoom; 00332 } 00333 00334 void 00335 lesstif_coords_to_pcb (int vx, int vy, Coord *px, Coord *py) 00336 { 00337 *px = Px (vx); 00338 *py = Py (vy); 00339 } 00340 00341 Pixel 00342 lesstif_parse_color (char *value) 00343 { 00344 XColor color; 00345 if (XParseColor (display, colormap, value, &color)) 00346 if (XAllocColor (display, colormap, &color)) 00347 return color.pixel; 00348 return 0; 00349 } 00350 00351 static void 00352 do_color (char *value, char *which) 00353 { 00354 XColor color; 00355 if (XParseColor (display, colormap, value, &color)) 00356 if (XAllocColor (display, colormap, &color)) 00357 { 00358 stdarg (which, color.pixel); 00359 } 00360 } 00361 00362 /* ------------------------------------------------------------ */ 00363 00364 static char * 00365 cur_clip () 00366 { 00367 if (TEST_FLAG (ORTHOMOVEFLAG, PCB)) 00368 return "+"; 00369 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB)) 00370 return "*"; 00371 if (PCB->Clipping == 0) 00372 return "X"; 00373 if (PCB->Clipping == 1) 00374 return "_/"; 00375 return "\\_"; 00376 } 00377 00378 /* Called from the core when it's busy doing something and we need to 00379 indicate that to the user. */ 00380 static int 00381 Busy(int argc, char **argv, Coord x, Coord y) 00382 { 00383 static Cursor busy_cursor = 0; 00384 if (busy_cursor == 0) 00385 busy_cursor = XCreateFontCursor (display, XC_watch); 00386 XDefineCursor (display, window, busy_cursor); 00387 XFlush(display); 00388 old_cursor_mode = -1; 00389 return 0; 00390 } 00391 00392 /* ---------------------------------------------------------------------- */ 00393 00394 /* Local actions. */ 00395 00396 static int 00397 PointCursor (int argc, char **argv, Coord x, Coord y) 00398 { 00399 if (argc > 0) 00400 over_point = 1; 00401 else 00402 over_point = 0; 00403 old_cursor_mode = -1; 00404 return 0; 00405 } 00406 00407 static int 00408 PCBChanged (int argc, char **argv, Coord x, Coord y) 00409 { 00410 if (work_area == 0) 00411 return 0; 00412 /*pcb_printf("PCB Changed! %$mD\n", PCB->MaxWidth, PCB->MaxHeight); */ 00413 n = 0; 00414 stdarg (XmNminimum, 0); 00415 stdarg (XmNvalue, 0); 00416 stdarg (XmNsliderSize, PCB->MaxWidth ? PCB->MaxWidth : 1); 00417 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1); 00418 XtSetValues (hscroll, args, n); 00419 n = 0; 00420 stdarg (XmNminimum, 0); 00421 stdarg (XmNvalue, 0); 00422 stdarg (XmNsliderSize, PCB->MaxHeight ? PCB->MaxHeight : 1); 00423 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1); 00424 XtSetValues (vscroll, args, n); 00425 zoom_max (); 00426 00427 hid_action ("NetlistChanged"); 00428 hid_action ("LayersChanged"); 00429 hid_action ("RouteStylesChanged"); 00430 lesstif_sizes_reset (); 00431 lesstif_update_layer_groups (); 00432 while (pinouts) 00433 pinout_unmap (0, pinouts, 0); 00434 if (PCB->Filename) 00435 { 00436 char *cp = strrchr (PCB->Filename, '/'); 00437 n = 0; 00438 stdarg (XmNtitle, cp ? cp + 1 : PCB->Filename); 00439 XtSetValues (appwidget, args, n); 00440 } 00441 crosshair_update_range(); 00442 return 0; 00443 } 00444 00445 00446 static const char setunits_syntax[] = 00447 "SetUnits(mm|mil)"; 00448 00449 static const char setunits_help[] = 00450 "Set the default measurement units."; 00451 00452 /* %start-doc actions SetUnits 00453 00454 @table @code 00455 00456 @item mil 00457 Sets the display units to mils (1/1000 inch). 00458 00459 @item mm 00460 Sets the display units to millimeters. 00461 00462 @end table 00463 00464 %end-doc */ 00465 00466 static int 00467 SetUnits (int argc, char **argv, Coord x, Coord y) 00468 { 00469 const Unit *new_unit; 00470 if (argc == 0) 00471 return 0; 00472 new_unit = get_unit_struct (argv[0]); 00473 if (new_unit != NULL && new_unit->allow != NO_PRINT) 00474 { 00475 Settings.grid_unit = new_unit; 00476 Settings.increments = get_increments_struct (Settings.grid_unit->family); 00477 AttributePut (PCB, "PCB::grid::unit", argv[0]); 00478 } 00479 lesstif_sizes_reset (); 00480 lesstif_styles_update_values (); 00481 return 0; 00482 } 00483 00484 static const char zoom_syntax[] = 00485 "Zoom()\n" 00486 "Zoom(factor)"; 00487 00488 static const char zoom_help[] = 00489 "Various zoom factor changes."; 00490 00491 /* %start-doc actions Zoom 00492 00493 Changes the zoom (magnification) of the view of the board. If no 00494 arguments are passed, the view is scaled such that the board just fits 00495 inside the visible window (i.e. ``view all''). Otherwise, 00496 @var{factor} specifies a change in zoom factor. It may be prefixed by 00497 @code{+}, @code{-}, or @code{=} to change how the zoom factor is 00498 modified. The @var{factor} is a floating point number, such as 00499 @code{1.5} or @code{0.75}. 00500 00501 @table @code 00502 00503 @item +@var{factor} 00504 Values greater than 1.0 cause the board to be drawn smaller; more of 00505 the board will be visible. Values between 0.0 and 1.0 cause the board 00506 to be drawn bigger; less of the board will be visible. 00507 00508 @item -@var{factor} 00509 Values greater than 1.0 cause the board to be drawn bigger; less of 00510 the board will be visible. Values between 0.0 and 1.0 cause the board 00511 to be drawn smaller; more of the board will be visible. 00512 00513 @item =@var{factor} 00514 00515 The @var{factor} is an absolute zoom factor; the unit for this value 00516 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a 00517 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI, 00518 about the actual resolution of most screens - resulting in an "actual 00519 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual 00520 size. 00521 00522 @end table 00523 00524 Note that zoom factors of zero are silently ignored. 00525 00526 %end-doc */ 00527 00528 static int 00529 ZoomAction (int argc, char **argv, Coord x, Coord y) 00530 { 00531 const char *vp; 00532 double v; 00533 if (x == 0 && y == 0) 00534 { 00535 x = view_width / 2; 00536 y = view_height / 2; 00537 } 00538 else 00539 { 00540 x = Vx (x); 00541 y = Vy (y); 00542 } 00543 if (argc < 1) 00544 { 00545 zoom_max (); 00546 return 0; 00547 } 00548 vp = argv[0]; 00549 if (strcasecmp (vp, "toggle") == 0) 00550 { 00551 zoom_toggle (x, y); 00552 return 0; 00553 } 00554 if (*vp == '+' || *vp == '-' || *vp == '=') 00555 vp++; 00556 v = g_ascii_strtod (vp, 0); 00557 if (v <= 0) 00558 return 1; 00559 switch (argv[0][0]) 00560 { 00561 case '-': 00562 zoom_by (1 / v, x, y); 00563 break; 00564 default: 00565 case '+': 00566 zoom_by (v, x, y); 00567 break; 00568 case '=': 00569 zoom_to (v, x, y); 00570 break; 00571 } 00572 return 0; 00573 } 00574 00575 static int pan_thumb_mode; 00576 00577 static int 00578 PanAction (int argc, char **argv, Coord x, Coord y) 00579 { 00580 int mode; 00581 00582 if (argc < 1) 00583 return 1; 00584 00585 if (argc == 2) 00586 { 00587 pan_thumb_mode = (strcasecmp (argv[0], "thumb") == 0) ? 1 : 0; 00588 mode = atoi (argv[1]); 00589 } 00590 else 00591 { 00592 pan_thumb_mode = 0; 00593 mode = atoi (argv[0]); 00594 } 00595 Pan (mode, Vx(x), Vy(y)); 00596 00597 return 0; 00598 } 00599 00600 static const char swapsides_syntax[] = 00601 "SwapSides(|v|h|r)"; 00602 00603 static const char swapsides_help[] = 00604 "Swaps the side of the board you're looking at."; 00605 00606 /* %start-doc actions SwapSides 00607 00608 This action changes the way you view the board. 00609 00610 @table @code 00611 00612 @item v 00613 Flips the board over vertically (up/down). 00614 00615 @item h 00616 Flips the board over horizontally (left/right), like flipping pages in 00617 a book. 00618 00619 @item r 00620 Rotates the board 180 degrees without changing sides. 00621 00622 @end table 00623 00624 If no argument is given, the board isn't moved but the opposite side 00625 is shown. 00626 00627 Normally, this action changes which pads and silk layer are drawn as 00628 true silk, and which are drawn as the "invisible" layer. It also 00629 determines which solder mask you see. 00630 00631 As a special case, if the layer group for the side you're looking at 00632 is visible and currently active, and the layer group for the opposite 00633 is not visible (i.e. disabled), then this action will also swap which 00634 layer group is visible and active, effectively swapping the ``working 00635 side'' of the board. 00636 00637 %end-doc */ 00638 00639 static int 00640 group_showing (int g, int *c) 00641 { 00642 int i, l; 00643 *c = PCB->LayerGroups.Entries[g][0]; 00644 for (i=0; i<PCB->LayerGroups.Number[g]; i++) 00645 { 00646 l = PCB->LayerGroups.Entries[g][i]; 00647 if (l >= 0 && l < max_copper_layer) 00648 { 00649 *c = l; 00650 if (PCB->Data->Layer[l].On) 00651 return 1; 00652 } 00653 } 00654 return 0; 00655 } 00656 00657 static int 00658 SwapSides (int argc, char **argv, Coord x, Coord y) 00659 { 00660 int old_shown_side = Settings.ShowBottomSide; 00661 int top_group = GetLayerGroupNumberBySide (TOP_SIDE); 00662 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); 00663 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]); 00664 int top_layer; 00665 int bottom_layer; 00666 int top_showing = group_showing (top_group, &top_layer); 00667 int bottom_showing = group_showing (bottom_group, &bottom_layer); 00668 00669 if (argc > 0) 00670 { 00671 switch (argv[0][0]) { 00672 case 'h': 00673 case 'H': 00674 flip_x = ! flip_x; 00675 break; 00676 case 'v': 00677 case 'V': 00678 flip_y = ! flip_y; 00679 break; 00680 case 'r': 00681 case 'R': 00682 flip_x = ! flip_x; 00683 flip_y = ! flip_y; 00684 break; 00685 default: 00686 return 1; 00687 } 00688 /* SwapSides will swap this */ 00689 Settings.ShowBottomSide = (flip_x == flip_y); 00690 } 00691 00692 n = 0; 00693 if (flip_x) 00694 stdarg (XmNprocessingDirection, XmMAX_ON_LEFT); 00695 else 00696 stdarg (XmNprocessingDirection, XmMAX_ON_RIGHT); 00697 XtSetValues (hscroll, args, n); 00698 00699 n = 0; 00700 if (flip_y) 00701 stdarg (XmNprocessingDirection, XmMAX_ON_TOP); 00702 else 00703 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM); 00704 XtSetValues (vscroll, args, n); 00705 00706 Settings.ShowBottomSide = !Settings.ShowBottomSide; 00707 00708 /* The idea is that if we're looking at the front side and the front 00709 layer is active (or visa versa), switching sides should switch 00710 layers too. We used to only do this if the other layer wasn't 00711 shown, but we now do it always. Change it back if users get 00712 confused. */ 00713 if (Settings.ShowBottomSide != old_shown_side) 00714 { 00715 if (Settings.ShowBottomSide) 00716 { 00717 if (active_group == top_group) 00718 { 00719 if (top_showing && !bottom_showing) 00720 ChangeGroupVisibility (top_layer, 0, 0); 00721 ChangeGroupVisibility (bottom_layer, 1, 1); 00722 } 00723 } 00724 else 00725 { 00726 if (active_group == bottom_group) 00727 { 00728 if (bottom_showing && !top_showing) 00729 ChangeGroupVisibility (bottom_layer, 0, 0); 00730 ChangeGroupVisibility (top_layer, 1, 1); 00731 } 00732 } 00733 } 00734 lesstif_invalidate_all (); 00735 return 0; 00736 } 00737 00738 static Widget m_cmd = 0, m_cmd_label; 00739 00740 static void 00741 command_callback (Widget w, XtPointer uptr, XmTextVerifyCallbackStruct * cbs) 00742 { 00743 char *s; 00744 switch (cbs->reason) 00745 { 00746 case XmCR_ACTIVATE: 00747 s = XmTextGetString (w); 00748 lesstif_show_crosshair (0); 00749 hid_parse_command (s); 00750 XtFree (s); 00751 XmTextSetString (w, ""); 00752 case XmCR_LOSING_FOCUS: 00753 XtUnmanageChild (m_cmd); 00754 XtUnmanageChild (m_cmd_label); 00755 break; 00756 } 00757 } 00758 00759 static void 00760 command_event_handler (Widget w, XtPointer p, XEvent * e, Boolean * cont) 00761 { 00762 char buf[10]; 00763 KeySym sym; 00764 00765 switch (e->type) 00766 { 00767 case KeyPress: 00768 XLookupString ((XKeyEvent *)e, buf, sizeof (buf), &sym, NULL); 00769 switch (sym) 00770 { 00771 case XK_Escape: 00772 XtUnmanageChild (m_cmd); 00773 XtUnmanageChild (m_cmd_label); 00774 XmTextSetString (w, ""); 00775 *cont = False; 00776 break; 00777 } 00778 break; 00779 } 00780 } 00781 00782 static const char command_syntax[] = 00783 "Command()"; 00784 00785 static const char command_help[] = 00786 "Displays the command line input window."; 00787 00788 /* %start-doc actions Command 00789 00790 The command window allows the user to manually enter actions to be 00791 executed. 00792 Action syntax can be done one of two ways: 00793 00794 @itemize @bullet 00795 00796 @item 00797 Follow the action name by an open parenthesis, arguments separated by 00798 commas, end with a close parenthesis. 00799 Example: 00800 00801 @example 00802 @code{Abc(1,2,3)} 00803 @end example 00804 00805 @item 00806 Separate the action name and arguments by spaces. 00807 Example: 00808 00809 @example 00810 @code{Abc 1 2 3} 00811 @end example 00812 00813 @end itemize 00814 00815 The first option allows you to have arguments with spaces in them, 00816 but the second is more ``natural'' to type for most people. 00817 00818 Note that action names are not case sensitive, but arguments normally 00819 are. 00820 However, most actions will check for ``keywords'' in a case 00821 insensitive way. 00822 00823 There are three ways to finish with the command window. 00824 If you press the @code{Enter} key, the command is invoked, the window 00825 goes away, and the next time you bring up the command window it's empty. 00826 If you press the @code{Esc} key, the window goes away without invoking 00827 anything, and the next time you bring up the command window it's 00828 empty. 00829 If you change focus away from the command window (i.e. click on some 00830 other window), the command window goes away but the next time you bring 00831 it up it resumes entering the command you were entering before. 00832 00833 %end-doc */ 00834 00835 static int 00836 Command (int argc, char **argv, Coord x, Coord y) 00837 { 00838 XtManageChild (m_cmd_label); 00839 XtManageChild (m_cmd); 00840 XmProcessTraversal (m_cmd, XmTRAVERSE_CURRENT); 00841 return 0; 00842 } 00843 00844 static const char benchmark_syntax[] = 00845 "Benchmark()"; 00846 00847 static const char benchmark_help[] = 00848 "Benchmark the GUI speed."; 00849 00850 /* %start-doc actions Benchmark 00851 00852 This action is used to speed-test the Lesstif graphics subsystem. It 00853 redraws the current screen as many times as possible in ten seconds. 00854 It reports the amount of time needed to draw the screen once. 00855 00856 %end-doc */ 00857 00858 static int 00859 Benchmark (int argc, char **argv, Coord x, Coord y) 00860 { 00861 int i = 0; 00862 time_t start, end; 00863 BoxType region; 00864 Drawable save_main; 00865 00866 save_main = main_pixmap; 00867 main_pixmap = window; 00868 00869 region.X1 = 0; 00870 region.Y1 = 0; 00871 region.X2 = PCB->MaxWidth; 00872 region.Y2 = PCB->MaxHeight; 00873 00874 pixmap = window; 00875 XSync (display, 0); 00876 time (&start); 00877 do 00878 { 00879 XFillRectangle (display, pixmap, bg_gc, 0, 0, view_width, view_height); 00880 hid_expose_callback (&lesstif_hid, ®ion, 0); 00881 XSync (display, 0); 00882 time (&end); 00883 i++; 00884 } 00885 while (end - start < 10); 00886 00887 printf ("%g redraws per second\n", i / 10.0); 00888 00889 main_pixmap = save_main; 00890 return 0; 00891 } 00892 00893 static int 00894 Center(int argc, char **argv, Coord x, Coord y) 00895 { 00896 x = GridFit (x, PCB->Grid, PCB->GridOffsetX); 00897 y = GridFit (y, PCB->Grid, PCB->GridOffsetY); 00898 view_left_x = x - (view_width * view_zoom) / 2; 00899 view_top_y = y - (view_height * view_zoom) / 2; 00900 lesstif_pan_fixup (); 00901 /* Move the pointer to the center of the window, but only if it's 00902 currently within the window already. Watch out for edges, 00903 though. */ 00904 XWarpPointer (display, window, window, 0, 0, view_width, view_height, 00905 Vx(x), Vy(y)); 00906 return 0; 00907 } 00908 00909 static const char cursor_syntax[] = 00910 "Cursor(Type,DeltaUp,DeltaRight,Units)"; 00911 00912 static const char cursor_help[] = 00913 "Move the cursor."; 00914 00915 /* %start-doc actions Cursor 00916 00917 This action moves the mouse cursor. Unlike other actions which take 00918 coordinates, this action's coordinates are always relative to the 00919 user's view of the board. Thus, a positive @var{DeltaUp} may move the 00920 cursor towards the board origin if the board is inverted. 00921 00922 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the 00923 viewport to move such that the crosshair is under the mouse cursor. 00924 @samp{Warp} causes the mouse cursor to move to be above the crosshair. 00925 00926 @var{Units} can be one of the following: 00927 00928 @table @samp 00929 00930 @item mil 00931 @itemx mm 00932 The cursor is moved by that amount, in board units. 00933 00934 @item grid 00935 The cursor is moved by that many grid points. 00936 00937 @item view 00938 The values are percentages of the viewport's view. Thus, a pan of 00939 @samp{100} would scroll the viewport by exactly the width of the 00940 current view. 00941 00942 @item board 00943 The values are percentages of the board size. Thus, a move of 00944 @samp{50,50} moves you halfway across the board. 00945 00946 @end table 00947 00948 %end-doc */ 00949 00950 static int 00951 CursorAction(int argc, char **argv, Coord x, Coord y) 00952 { 00953 UnitList extra_units_x = { 00954 { "grid", PCB->Grid, 0 }, 00955 { "view", Pz(view_width), UNIT_PERCENT }, 00956 { "board", PCB->MaxWidth, UNIT_PERCENT }, 00957 { "", 0, 0 } 00958 }; 00959 UnitList extra_units_y = { 00960 { "grid", PCB->Grid, 0 }, 00961 { "view", Pz(view_height), UNIT_PERCENT }, 00962 { "board", PCB->MaxHeight, UNIT_PERCENT }, 00963 { "", 0, 0 } 00964 }; 00965 int pan_warp = HID_SC_DO_NOTHING; 00966 double dx, dy; 00967 00968 if (argc != 4) 00969 AFAIL(cursor); 00970 00971 if (strcasecmp (argv[0], "pan") == 0) 00972 pan_warp = HID_SC_PAN_VIEWPORT; 00973 else if (strcasecmp (argv[0], "warp") == 0) 00974 pan_warp = HID_SC_WARP_POINTER; 00975 else 00976 AFAIL(cursor); 00977 00978 dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "mil"); 00979 if (flip_x) 00980 dx = -dx; 00981 dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "mil"); 00982 if (!flip_y) 00983 dy = -dy; 00984 00985 EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy); 00986 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp); 00987 00988 return 0; 00989 } 00990 00991 HID_Action lesstif_main_action_list[] = { 00992 {"PCBChanged", 0, PCBChanged, 00993 pcbchanged_help, pcbchanged_syntax}, 00994 {"SetUnits", 0, SetUnits, 00995 setunits_help, setunits_syntax}, 00996 {"Zoom", "Click on a place to zoom in", ZoomAction, 00997 zoom_help, zoom_syntax}, 00998 {"Pan", "Click on a place to pan", PanAction, 00999 zoom_help, zoom_syntax}, 01000 {"SwapSides", 0, SwapSides, 01001 swapsides_help, swapsides_syntax}, 01002 {"Command", 0, Command, 01003 command_help, command_syntax}, 01004 {"Benchmark", 0, Benchmark, 01005 benchmark_help, benchmark_syntax}, 01006 {"PointCursor", 0, PointCursor}, 01007 {"Center", "Click on a location to center", Center}, 01008 {"Busy", 0, Busy}, 01009 {"Cursor", 0, CursorAction, 01010 cursor_help, cursor_syntax}, 01011 }; 01012 01013 REGISTER_ACTIONS (lesstif_main_action_list) 01014 01015 01016 /* ---------------------------------------------------------------------- 01017 * redraws the background image 01018 */ 01019 01020 static int bg_w, bg_h, bgi_w, bgi_h; 01021 static Pixel **bg = 0; 01022 static XImage *bgi = 0; 01023 static enum { 01024 PT_unknown, 01025 PT_RGB565, 01026 PT_RGB888 01027 } pixel_type = PT_unknown; 01028 01029 static void 01030 LoadBackgroundFile (FILE *f, char *filename) 01031 { 01032 XVisualInfo vinfot, *vinfo; 01033 Visual *vis; 01034 int c, r, b; 01035 int i, nret; 01036 int p[3], rows, cols, maxval; 01037 01038 if (fgetc(f) != 'P') 01039 { 01040 printf("bgimage: %s signature not P6\n", filename); 01041 return; 01042 } 01043 if (fgetc(f) != '6') 01044 { 01045 printf("bgimage: %s signature not P6\n", filename); 01046 return; 01047 } 01048 for (i=0; i<3; i++) 01049 { 01050 do { 01051 b = fgetc(f); 01052 if (feof(f)) 01053 return; 01054 if (b == '#') 01055 while (!feof(f) && b != '\n') 01056 b = fgetc(f); 01057 } while (!isdigit(b)); 01058 p[i] = b - '0'; 01059 while (isdigit(b = fgetc(f))) 01060 p[i] = p[i]*10 + b - '0'; 01061 } 01062 bg_w = cols = p[0]; 01063 bg_h = rows = p[1]; 01064 maxval = p[2]; 01065 01066 setbuf(stdout, 0); 01067 bg = (Pixel **) malloc (rows * sizeof (Pixel *)); 01068 if (!bg) 01069 { 01070 printf("Out of memory loading %s\n", filename); 01071 return; 01072 } 01073 for (i=0; i<rows; i++) 01074 { 01075 bg[i] = (Pixel *) malloc (cols * sizeof (Pixel)); 01076 if (!bg[i]) 01077 { 01078 printf("Out of memory loading %s\n", filename); 01079 while (--i >= 0) 01080 free (bg[i]); 01081 free (bg); 01082 bg = 0; 01083 return; 01084 } 01085 } 01086 01087 vis = DefaultVisual (display, DefaultScreen(display)); 01088 01089 vinfot.visualid = XVisualIDFromVisual(vis); 01090 vinfo = XGetVisualInfo (display, VisualIDMask, &vinfot, &nret); 01091 01092 #if 0 01093 /* If you want to support more visuals below, you'll probably need 01094 this. */ 01095 printf("vinfo: rm %04x gm %04x bm %04x depth %d class %d\n", 01096 vinfo->red_mask, vinfo->green_mask, vinfo->blue_mask, 01097 vinfo->depth, vinfo->class); 01098 #endif 01099 01100 #if !defined(__cplusplus) 01101 #define c_class class 01102 #endif 01103 01104 if (vinfo->c_class == TrueColor 01105 && vinfo->depth == 16 01106 && vinfo->red_mask == 0xf800 01107 && vinfo->green_mask == 0x07e0 01108 && vinfo->blue_mask == 0x001f) 01109 pixel_type = PT_RGB565; 01110 01111 if (vinfo->c_class == TrueColor 01112 && vinfo->depth == 24 01113 && vinfo->red_mask == 0xff0000 01114 && vinfo->green_mask == 0x00ff00 01115 && vinfo->blue_mask == 0x0000ff) 01116 pixel_type = PT_RGB888; 01117 01118 for (r=0; r<rows; r++) 01119 { 01120 for (c=0; c<cols; c++) 01121 { 01122 XColor pix; 01123 unsigned int pr = (unsigned)fgetc(f); 01124 unsigned int pg = (unsigned)fgetc(f); 01125 unsigned int pb = (unsigned)fgetc(f); 01126 01127 switch (pixel_type) 01128 { 01129 case PT_unknown: 01130 pix.red = pr * 65535 / maxval; 01131 pix.green = pg * 65535 / maxval; 01132 pix.blue = pb * 65535 / maxval; 01133 pix.flags = DoRed | DoGreen | DoBlue; 01134 XAllocColor (display, colormap, &pix); 01135 bg[r][c] = pix.pixel; 01136 break; 01137 case PT_RGB565: 01138 bg[r][c] = (pr>>3)<<11 | (pg>>2)<<5 | (pb>>3); 01139 break; 01140 case PT_RGB888: 01141 bg[r][c] = (pr << 16) | (pg << 8) | (pb); 01142 break; 01143 } 01144 } 01145 } 01146 } 01147 01148 void 01149 LoadBackgroundImage (char *filename) 01150 { 01151 FILE *f = fopen(filename, "rb"); 01152 if (!f) 01153 { 01154 if (NSTRCMP (filename, "pcb-background.ppm")) 01155 perror(filename); 01156 return; 01157 } 01158 LoadBackgroundFile (f, filename); 01159 fclose(f); 01160 } 01161 01162 static void 01163 DrawBackgroundImage () 01164 { 01165 int x, y, w, h; 01166 double xscale, yscale; 01167 int pcbwidth = PCB->MaxWidth / view_zoom; 01168 int pcbheight = PCB->MaxHeight / view_zoom; 01169 01170 if (!window || !bg) 01171 return; 01172 01173 if (!bgi || view_width != bgi_w || view_height != bgi_h) 01174 { 01175 if (bgi) 01176 XDestroyImage (bgi); 01177 /* Cheat - get the image, which sets up the format too. */ 01178 bgi = XGetImage (XtDisplay(work_area), 01179 window, 01180 0, 0, view_width, view_height, 01181 -1, ZPixmap); 01182 bgi_w = view_width; 01183 bgi_h = view_height; 01184 } 01185 01186 w = MIN (view_width, pcbwidth); 01187 h = MIN (view_height, pcbheight); 01188 01189 xscale = (double)bg_w / PCB->MaxWidth; 01190 yscale = (double)bg_h / PCB->MaxHeight; 01191 01192 for (y=0; y<h; y++) 01193 { 01194 int pr = Py(y); 01195 int ir = pr * yscale; 01196 for (x=0; x<w; x++) 01197 { 01198 int pc = Px(x); 01199 int ic = pc * xscale; 01200 XPutPixel (bgi, x, y, bg[ir][ic]); 01201 } 01202 } 01203 XPutImage(display, main_pixmap, bg_gc, 01204 bgi, 01205 0, 0, 0, 0, w, h); 01206 } 01207 /* ---------------------------------------------------------------------- */ 01208 01209 static HID_Attribute * 01210 lesstif_get_export_options (int *n) 01211 { 01212 *n = sizeof (lesstif_attribute_list) / sizeof (HID_Attribute); 01213 return lesstif_attribute_list; 01214 } 01215 01216 static void 01217 set_scroll (Widget s, int pos, int view, int pcb) 01218 { 01219 int sz = view * view_zoom; 01220 if (sz > pcb) 01221 sz = pcb; 01222 if ((pos < 0) || (pos > (pcb - sz))) pos = 0; 01223 n = 0; 01224 stdarg (XmNvalue, pos); 01225 stdarg (XmNsliderSize, sz); 01226 stdarg (XmNincrement, view_zoom); 01227 stdarg (XmNpageIncrement, sz); 01228 stdarg (XmNmaximum, pcb); 01229 XtSetValues (s, args, n); 01230 } 01231 01232 void 01233 lesstif_pan_fixup () 01234 { 01235 #if 0 01236 if (view_left_x > PCB->MaxWidth - (view_width * view_zoom)) 01237 view_left_x = PCB->MaxWidth - (view_width * view_zoom); 01238 if (view_top_y > PCB->MaxHeight - (view_height * view_zoom)) 01239 view_top_y = PCB->MaxHeight - (view_height * view_zoom); 01240 if (view_left_x < 0) 01241 view_left_x = 0; 01242 if (view_top_y < 0) 01243 view_top_y = 0; 01244 if (view_width * view_zoom > PCB->MaxWidth 01245 && view_height * view_zoom > PCB->MaxHeight) 01246 { 01247 zoom_by (1, 0, 0); 01248 return; 01249 } 01250 #endif 01251 01252 set_scroll (hscroll, view_left_x, view_width, PCB->MaxWidth); 01253 set_scroll (vscroll, view_top_y, view_height, PCB->MaxHeight); 01254 01255 lesstif_invalidate_all (); 01256 } 01257 01258 static void 01259 zoom_max () 01260 { 01261 double new_zoom = PCB->MaxWidth / view_width; 01262 if (new_zoom < PCB->MaxHeight / view_height) 01263 new_zoom = PCB->MaxHeight / view_height; 01264 01265 view_left_x = -(view_width * new_zoom - PCB->MaxWidth) / 2; 01266 view_top_y = -(view_height * new_zoom - PCB->MaxHeight) / 2; 01267 view_zoom = new_zoom; 01268 pixel_slop = view_zoom; 01269 lesstif_pan_fixup (); 01270 } 01271 01272 static void 01273 zoom_to (double new_zoom, int x, int y) 01274 { 01275 double max_zoom, xfrac, yfrac; 01276 int cx, cy; 01277 01278 xfrac = (double) x / (double) view_width; 01279 yfrac = (double) y / (double) view_height; 01280 01281 if (flip_x) 01282 xfrac = 1-xfrac; 01283 if (flip_y) 01284 yfrac = 1-yfrac; 01285 01286 max_zoom = PCB->MaxWidth / view_width; 01287 if (max_zoom < PCB->MaxHeight / view_height) 01288 max_zoom = PCB->MaxHeight / view_height; 01289 01290 max_zoom *= MAX_ZOOM_SCALE; 01291 01292 if (new_zoom < 1) 01293 new_zoom = 1; 01294 if (new_zoom > max_zoom) 01295 new_zoom = max_zoom; 01296 01297 cx = view_left_x + view_width * xfrac * view_zoom; 01298 cy = view_top_y + view_height * yfrac * view_zoom; 01299 01300 if (view_zoom != new_zoom) 01301 { 01302 view_zoom = new_zoom; 01303 pixel_slop = view_zoom; 01304 01305 view_left_x = cx - view_width * xfrac * view_zoom; 01306 view_top_y = cy - view_height * yfrac * view_zoom; 01307 } 01308 lesstif_pan_fixup (); 01309 } 01310 01311 static void 01312 zoom_toggle(int x, int y) 01313 { 01314 double tmp; 01315 01316 tmp = prev_view_zoom; 01317 prev_view_zoom = view_zoom; 01318 zoom_to(tmp, x, y); 01319 } 01320 01321 void 01322 zoom_by (double factor, int x, int y) 01323 { 01324 zoom_to (view_zoom * factor, x, y); 01325 } 01326 01327 static int panning = 0; 01328 static int shift_pressed; 01329 static int ctrl_pressed; 01330 static int alt_pressed; 01331 01332 /* X and Y are in screen coordinates. */ 01333 static void 01334 Pan (int mode, int x, int y) 01335 { 01336 static int ox, oy; 01337 static int opx, opy; 01338 01339 panning = mode; 01340 /* This is for ctrl-pan, where the viewport's position is directly 01341 proportional to the cursor position in the window (like the Xaw 01342 thumb panner) */ 01343 if (pan_thumb_mode) 01344 { 01345 opx = x * PCB->MaxWidth / view_width; 01346 opy = y * PCB->MaxHeight / view_height; 01347 if (flip_x) 01348 opx = PCB->MaxWidth - opx; 01349 if (flip_y) 01350 opy = PCB->MaxHeight - opy; 01351 view_left_x = opx - view_width / 2 * view_zoom; 01352 view_top_y = opy - view_height / 2 * view_zoom; 01353 lesstif_pan_fixup (); 01354 } 01355 /* This is the start of a regular pan. On the first click, we 01356 remember the coordinates where we "grabbed" the screen. */ 01357 else if (mode == 1) 01358 { 01359 ox = x; 01360 oy = y; 01361 opx = view_left_x; 01362 opy = view_top_y; 01363 } 01364 /* continued drag, we calculate how far we've moved the cursor and 01365 set the position accordingly. */ 01366 else 01367 { 01368 if (flip_x) 01369 view_left_x = opx + (x - ox) * view_zoom; 01370 else 01371 view_left_x = opx - (x - ox) * view_zoom; 01372 if (flip_y) 01373 view_top_y = opy + (y - oy) * view_zoom; 01374 else 01375 view_top_y = opy - (y - oy) * view_zoom; 01376 lesstif_pan_fixup (); 01377 } 01378 } 01379 01380 static void 01381 mod_changed (XKeyEvent * e, int set) 01382 { 01383 switch (XkbKeycodeToKeysym (display, e->keycode, 0, e->state & ShiftMask ? 1:0)) 01384 { 01385 case XK_Shift_L: 01386 case XK_Shift_R: 01387 shift_pressed = set; 01388 break; 01389 case XK_Control_L: 01390 case XK_Control_R: 01391 ctrl_pressed = set; 01392 break; 01393 #ifdef __APPLE__ 01394 case XK_Mode_switch: 01395 #else 01396 case XK_Alt_L: 01397 case XK_Alt_R: 01398 #endif 01399 alt_pressed = set; 01400 break; 01401 default: 01402 // to include the Apple keyboard left and right command keys use XK_Meta_L and XK_Meta_R respectivly. 01403 return; 01404 } 01405 in_move_event = 1; 01406 notify_crosshair_change (false); 01407 if (panning) 01408 Pan (2, e->x, e->y); 01409 EventMoveCrosshair (Px (e->x), Py (e->y)); 01410 AdjustAttachedObjects (); 01411 notify_crosshair_change (true); 01412 in_move_event = 0; 01413 } 01414 01415 static void 01416 work_area_input (Widget w, XtPointer v, XEvent * e, Boolean * ctd) 01417 { 01418 static int pressed_button = 0; 01419 01420 show_crosshair (0); 01421 switch (e->type) 01422 { 01423 case KeyPress: 01424 mod_changed (&(e->xkey), 1); 01425 if (lesstif_key_event (&(e->xkey))) 01426 return; 01427 break; 01428 01429 case KeyRelease: 01430 mod_changed (&(e->xkey), 0); 01431 break; 01432 01433 case ButtonPress: 01434 { 01435 int mods; 01436 if (pressed_button) 01437 return; 01438 /*printf("click %d\n", e->xbutton.button); */ 01439 if (lesstif_button_event (w, e)) 01440 return; 01441 01442 notify_crosshair_change (false); 01443 pressed_button = e->xbutton.button; 01444 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0) 01445 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0) 01446 #ifdef __APPLE__ 01447 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0); 01448 #else 01449 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0); 01450 #endif 01451 do_mouse_action(e->xbutton.button, mods); 01452 notify_crosshair_change (true); 01453 break; 01454 } 01455 01456 case ButtonRelease: 01457 { 01458 int mods; 01459 if (e->xbutton.button != pressed_button) 01460 return; 01461 lesstif_button_event (w, e); 01462 notify_crosshair_change (false); 01463 pressed_button = 0; 01464 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0) 01465 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0) 01466 #ifdef __APPLE__ 01467 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0) 01468 #else 01469 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0) 01470 #endif 01471 + M_Release; 01472 do_mouse_action (e->xbutton.button, mods); 01473 notify_crosshair_change (true); 01474 break; 01475 } 01476 01477 case MotionNotify: 01478 { 01479 Window root, child; 01480 unsigned int keys_buttons; 01481 int root_x, root_y, pos_x, pos_y; 01482 while (XCheckMaskEvent (display, PointerMotionMask, e)); 01483 XQueryPointer (display, e->xmotion.window, &root, &child, 01484 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons); 01485 shift_pressed = (keys_buttons & ShiftMask); 01486 ctrl_pressed = (keys_buttons & ControlMask); 01487 #ifdef __APPLE__ 01488 alt_pressed = (keys_buttons & (1<<13)); 01489 #else 01490 alt_pressed = (keys_buttons & Mod1Mask); 01491 #endif 01492 /*pcb_printf("m %#mS %#mS\n", Px(e->xmotion.x), Py(e->xmotion.y)); */ 01493 crosshair_in_window = 1; 01494 in_move_event = 1; 01495 if (panning) 01496 Pan (2, pos_x, pos_y); 01497 EventMoveCrosshair (Px (pos_x), Py (pos_y)); 01498 in_move_event = 0; 01499 } 01500 break; 01501 01502 case LeaveNotify: 01503 crosshair_in_window = 0; 01504 ShowCrosshair (false); 01505 need_idle_proc (); 01506 break; 01507 01508 case EnterNotify: 01509 crosshair_in_window = 1; 01510 in_move_event = 1; 01511 EventMoveCrosshair (Px (e->xcrossing.x), Py (e->xcrossing.y)); 01512 ShowCrosshair (true); 01513 in_move_event = 0; 01514 need_idle_proc (); 01515 break; 01516 01517 default: 01518 printf ("work_area: unknown event %d\n", e->type); 01519 break; 01520 } 01521 } 01522 01523 static void 01524 draw_right_cross (GC xor_gc, int x, int y, 01525 int view_width, int view_height) 01526 { 01527 XDrawLine (display, window, xor_gc, 0, y, view_width, y); 01528 XDrawLine (display, window, xor_gc, x, 0, x, view_height); 01529 } 01530 01531 static void 01532 draw_slanted_cross (GC xor_gc, int x, int y, 01533 int view_width, int view_height) 01534 { 01535 int x0, y0, x1, y1; 01536 01537 x0 = x + (view_height - y); 01538 x0 = MAX(0, MIN (x0, view_width)); 01539 x1 = x - y; 01540 x1 = MAX(0, MIN (x1, view_width)); 01541 y0 = y + (view_width - x); 01542 y0 = MAX(0, MIN (y0, view_height)); 01543 y1 = y - x; 01544 y1 = MAX(0, MIN (y1, view_height)); 01545 XDrawLine (display, window, xor_gc, x0, y0, x1, y1); 01546 x0 = x - (view_height - y); 01547 x0 = MAX(0, MIN (x0, view_width)); 01548 x1 = x + y; 01549 x1 = MAX(0, MIN (x1, view_width)); 01550 y0 = y + x; 01551 y0 = MAX(0, MIN (y0, view_height)); 01552 y1 = y - (view_width - x); 01553 y1 = MAX(0, MIN (y1, view_height)); 01554 XDrawLine (display, window, xor_gc, x0, y0, x1, y1); 01555 } 01556 01557 static void 01558 draw_dozen_cross (GC xor_gc, int x, int y, 01559 int view_width, int view_height) 01560 { 01561 int x0, y0, x1, y1; 01562 double tan60 = sqrt (3); 01563 01564 x0 = x + (view_height - y) / tan60; 01565 x0 = MAX(0, MIN (x0, view_width)); 01566 x1 = x - y / tan60; 01567 x1 = MAX(0, MIN (x1, view_width)); 01568 y0 = y + (view_width - x) * tan60; 01569 y0 = MAX(0, MIN (y0, view_height)); 01570 y1 = y - x * tan60; 01571 y1 = MAX(0, MIN (y1, view_height)); 01572 XDrawLine (display, window, xor_gc, x0, y0, x1, y1); 01573 01574 x0 = x + (view_height - y) * tan60; 01575 x0 = MAX(0, MIN (x0, view_width)); 01576 x1 = x - y * tan60; 01577 x1 = MAX(0, MIN (x1, view_width)); 01578 y0 = y + (view_width - x) / tan60; 01579 y0 = MAX(0, MIN (y0, view_height)); 01580 y1 = y - x / tan60; 01581 y1 = MAX(0, MIN (y1, view_height)); 01582 XDrawLine (display, window, xor_gc, x0, y0, x1, y1); 01583 01584 x0 = x - (view_height - y) / tan60; 01585 x0 = MAX(0, MIN (x0, view_width)); 01586 x1 = x + y / tan60; 01587 x1 = MAX(0, MIN (x1, view_width)); 01588 y0 = y + x * tan60; 01589 y0 = MAX(0, MIN (y0, view_height)); 01590 y1 = y - (view_width - x) * tan60; 01591 y1 = MAX(0, MIN (y1, view_height)); 01592 XDrawLine (display, window, xor_gc, x0, y0, x1, y1); 01593 01594 x0 = x - (view_height - y) * tan60; 01595 x0 = MAX(0, MIN (x0, view_width)); 01596 x1 = x + y * tan60; 01597 x1 = MAX(0, MIN (x1, view_width)); 01598 y0 = y + x / tan60; 01599 y0 = MAX(0, MIN (y0, view_height)); 01600 y1 = y - (view_width - x) / tan60; 01601 y1 = MAX(0, MIN (y1, view_height)); 01602 XDrawLine (display, window, xor_gc, x0, y0, x1, y1); 01603 } 01604 01605 static void 01606 draw_crosshair (GC xor_gc, int x, int y, 01607 int view_width, int view_height) 01608 { 01609 draw_right_cross (xor_gc, x, y, view_width, view_height); 01610 if (Crosshair.shape == Union_Jack_Crosshair_Shape) 01611 draw_slanted_cross (xor_gc, x, y, view_width, view_height); 01612 if (Crosshair.shape == Dozen_Crosshair_Shape) 01613 draw_dozen_cross (xor_gc, x, y, view_width, view_height); 01614 } 01615 void 01616 lesstif_show_crosshair (int show) 01617 { 01618 static int showing = 0; 01619 static int sx, sy; 01620 static GC xor_gc = 0; 01621 Pixel crosshair_color; 01622 01623 if (!crosshair_in_window || !window) 01624 return; 01625 if (xor_gc == 0) 01626 { 01627 crosshair_color = lesstif_parse_color (Settings.CrosshairColor) ^ bgcolor; 01628 xor_gc = XCreateGC (display, window, 0, 0); 01629 XSetFunction (display, xor_gc, GXxor); 01630 XSetForeground (display, xor_gc, crosshair_color); 01631 } 01632 if (show == showing) 01633 return; 01634 if (show) 01635 { 01636 sx = Vx (crosshair_x); 01637 sy = Vy (crosshair_y); 01638 } 01639 else 01640 need_idle_proc (); 01641 draw_crosshair (xor_gc, sx, sy, view_width, view_height); 01642 showing = show; 01643 } 01644 01645 static void 01646 work_area_expose (Widget work_area, void *me, 01647 XmDrawingAreaCallbackStruct * cbs) 01648 { 01649 XExposeEvent *e; 01650 01651 show_crosshair (0); 01652 e = &(cbs->event->xexpose); 01653 XSetFunction (display, my_gc, GXcopy); 01654 XCopyArea (display, main_pixmap, window, my_gc, 01655 e->x, e->y, e->width, e->height, e->x, e->y); 01656 show_crosshair (1); 01657 } 01658 01659 static void 01660 scroll_callback (Widget scroll, int *view_dim, 01661 XmScrollBarCallbackStruct * cbs) 01662 { 01663 *view_dim = cbs->value; 01664 lesstif_invalidate_all (); 01665 } 01666 01667 static void 01668 work_area_make_pixmaps (Dimension width, Dimension height) 01669 { 01670 if (main_pixmap) 01671 XFreePixmap (display, main_pixmap); 01672 main_pixmap = 01673 XCreatePixmap (display, window, width, height, 01674 XDefaultDepth (display, screen)); 01675 01676 if (mask_pixmap) 01677 XFreePixmap (display, mask_pixmap); 01678 mask_pixmap = 01679 XCreatePixmap (display, window, width, height, 01680 XDefaultDepth (display, screen)); 01681 #ifdef HAVE_XRENDER 01682 if (main_picture) 01683 { 01684 XRenderFreePicture (display, main_picture); 01685 main_picture = 0; 01686 } 01687 if (mask_picture) 01688 { 01689 XRenderFreePicture (display, mask_picture); 01690 mask_picture = 0; 01691 } 01692 if (use_xrender) 01693 { 01694 main_picture = XRenderCreatePicture (display, main_pixmap, 01695 XRenderFindVisualFormat(display, 01696 DefaultVisual(display, screen)), 0, 0); 01697 mask_picture = XRenderCreatePicture (display, mask_pixmap, 01698 XRenderFindVisualFormat(display, 01699 DefaultVisual(display, screen)), 0, 0); 01700 if (!main_picture || !mask_picture) 01701 use_xrender = 0; 01702 } 01703 #endif /* HAVE_XRENDER */ 01704 01705 if (mask_bitmap) 01706 XFreePixmap (display, mask_bitmap); 01707 mask_bitmap = XCreatePixmap (display, window, width, height, 1); 01708 01709 pixmap = use_mask ? main_pixmap : mask_pixmap; 01710 pixmap_w = width; 01711 pixmap_h = height; 01712 } 01713 01714 static void 01715 work_area_resize (Widget work_area, void *me, 01716 XmDrawingAreaCallbackStruct * cbs) 01717 { 01718 XColor color; 01719 Dimension width, height; 01720 01721 show_crosshair (0); 01722 01723 n = 0; 01724 stdarg (XtNwidth, &width); 01725 stdarg (XtNheight, &height); 01726 stdarg (XmNbackground, &bgcolor); 01727 XtGetValues (work_area, args, n); 01728 view_width = width; 01729 view_height = height; 01730 01731 color.pixel = bgcolor; 01732 XQueryColor (display, colormap, &color); 01733 bgred = color.red; 01734 bggreen = color.green; 01735 bgblue = color.blue; 01736 01737 if (!window) 01738 return; 01739 01740 work_area_make_pixmaps (view_width, view_height); 01741 01742 zoom_by (1, 0, 0); 01743 } 01744 01745 static void 01746 work_area_first_expose (Widget work_area, void *me, 01747 XmDrawingAreaCallbackStruct * cbs) 01748 { 01749 int c; 01750 Dimension width, height; 01751 static char dashes[] = { 4, 4 }; 01752 01753 window = XtWindow (work_area); 01754 my_gc = XCreateGC (display, window, 0, 0); 01755 01756 arc1_gc = XCreateGC (display, window, 0, 0); 01757 c = lesstif_parse_color ("#804000"); 01758 XSetForeground (display, arc1_gc, c); 01759 arc2_gc = XCreateGC (display, window, 0, 0); 01760 c = lesstif_parse_color ("#004080"); 01761 XSetForeground (display, arc2_gc, c); 01762 XSetLineAttributes (display, arc1_gc, 1, LineOnOffDash, 0, 0); 01763 XSetLineAttributes (display, arc2_gc, 1, LineOnOffDash, 0, 0); 01764 XSetDashes (display, arc1_gc, 0, dashes, 2); 01765 XSetDashes (display, arc2_gc, 0, dashes, 2); 01766 01767 n = 0; 01768 stdarg (XtNwidth, &width); 01769 stdarg (XtNheight, &height); 01770 stdarg (XmNbackground, &bgcolor); 01771 XtGetValues (work_area, args, n); 01772 view_width = width; 01773 view_height = height; 01774 01775 offlimit_color = lesstif_parse_color (Settings.OffLimitColor); 01776 grid_color = lesstif_parse_color (Settings.GridColor); 01777 01778 bg_gc = XCreateGC (display, window, 0, 0); 01779 XSetForeground (display, bg_gc, bgcolor); 01780 01781 work_area_make_pixmaps (width, height); 01782 01783 #ifdef HAVE_XRENDER 01784 if (use_xrender) 01785 { 01786 XRenderPictureAttributes pa; 01787 XRenderColor a = {0, 0, 0, 0x8000}; 01788 01789 pale_pixmap = XCreatePixmap (display, window, 1, 1, 8); 01790 pa.repeat = True; 01791 pale_picture = XRenderCreatePicture (display, pale_pixmap, 01792 XRenderFindStandardFormat(display, PictStandardA8), 01793 CPRepeat, &pa); 01794 if (pale_picture) 01795 XRenderFillRectangle(display, PictOpSrc, pale_picture, &a, 0, 0, 1, 1); 01796 else 01797 use_xrender = 0; 01798 } 01799 #endif /* HAVE_XRENDER */ 01800 01801 clip_gc = XCreateGC (display, window, 0, 0); 01802 bset_gc = XCreateGC (display, mask_bitmap, 0, 0); 01803 XSetForeground (display, bset_gc, 1); 01804 bclear_gc = XCreateGC (display, mask_bitmap, 0, 0); 01805 XSetForeground (display, bclear_gc, 0); 01806 01807 XtRemoveCallback (work_area, XmNexposeCallback, 01808 (XtCallbackProc) work_area_first_expose, 0); 01809 XtAddCallback (work_area, XmNexposeCallback, 01810 (XtCallbackProc) work_area_expose, 0); 01811 lesstif_invalidate_all (); 01812 } 01813 01814 static Widget 01815 make_message (char *name, Widget left, int resizeable) 01816 { 01817 Widget w, f; 01818 n = 0; 01819 if (left) 01820 { 01821 stdarg (XmNleftAttachment, XmATTACH_WIDGET); 01822 stdarg (XmNleftWidget, XtParent(left)); 01823 } 01824 else 01825 { 01826 stdarg (XmNleftAttachment, XmATTACH_FORM); 01827 } 01828 stdarg (XmNtopAttachment, XmATTACH_FORM); 01829 stdarg (XmNbottomAttachment, XmATTACH_FORM); 01830 stdarg (XmNshadowType, XmSHADOW_IN); 01831 stdarg (XmNshadowThickness, 1); 01832 stdarg (XmNalignment, XmALIGNMENT_CENTER); 01833 stdarg (XmNmarginWidth, 4); 01834 stdarg (XmNmarginHeight, 1); 01835 if (!resizeable) 01836 stdarg (XmNresizePolicy, XmRESIZE_GROW); 01837 f = XmCreateForm (messages, name, args, n); 01838 XtManageChild (f); 01839 n = 0; 01840 stdarg (XmNtopAttachment, XmATTACH_FORM); 01841 stdarg (XmNbottomAttachment, XmATTACH_FORM); 01842 stdarg (XmNleftAttachment, XmATTACH_FORM); 01843 stdarg (XmNrightAttachment, XmATTACH_FORM); 01844 w = XmCreateLabel (f, name, args, n); 01845 XtManageChild (w); 01846 return w; 01847 } 01848 01849 static void 01850 lesstif_do_export (HID_Attr_Val * options) 01851 { 01852 Dimension width, height; 01853 Widget menu; 01854 Widget work_area_frame; 01855 01856 crosshair_gc = lesstif_make_gc (); 01857 01858 n = 0; 01859 stdarg (XtNwidth, &width); 01860 stdarg (XtNheight, &height); 01861 XtGetValues (appwidget, args, n); 01862 01863 if (width < 1) 01864 width = 640; 01865 if (width > XDisplayWidth (display, screen)) 01866 width = XDisplayWidth (display, screen); 01867 if (height < 1) 01868 height = 480; 01869 if (height > XDisplayHeight (display, screen)) 01870 height = XDisplayHeight (display, screen); 01871 01872 n = 0; 01873 stdarg (XmNwidth, width); 01874 stdarg (XmNheight, height); 01875 XtSetValues (appwidget, args, n); 01876 01877 stdarg (XmNspacing, 0); 01878 mainwind = XmCreateMainWindow (appwidget, "mainWind", args, n); 01879 XtManageChild (mainwind); 01880 01881 n = 0; 01882 stdarg (XmNmarginWidth, 0); 01883 stdarg (XmNmarginHeight, 0); 01884 menu = lesstif_menu (mainwind, "menubar", args, n); 01885 XtManageChild (menu); 01886 01887 n = 0; 01888 stdarg (XmNshadowType, XmSHADOW_IN); 01889 work_area_frame = 01890 XmCreateFrame (mainwind, "work_area_frame", args, n); 01891 XtManageChild (work_area_frame); 01892 01893 n = 0; 01894 do_color (Settings.BackgroundColor, XmNbackground); 01895 work_area = XmCreateDrawingArea (work_area_frame, "work_area", args, n); 01896 XtManageChild (work_area); 01897 XtAddCallback (work_area, XmNexposeCallback, 01898 (XtCallbackProc) work_area_first_expose, 0); 01899 XtAddCallback (work_area, XmNresizeCallback, 01900 (XtCallbackProc) work_area_resize, 0); 01901 /* A regular callback won't work here, because lesstif swallows any 01902 Ctrl<Button>1 event. */ 01903 XtAddEventHandler (work_area, 01904 ButtonPressMask | ButtonReleaseMask 01905 | PointerMotionMask | PointerMotionHintMask 01906 | KeyPressMask | KeyReleaseMask 01907 | EnterWindowMask | LeaveWindowMask, 01908 0, work_area_input, 0); 01909 01910 n = 0; 01911 stdarg (XmNorientation, XmVERTICAL); 01912 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM); 01913 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1); 01914 vscroll = XmCreateScrollBar (mainwind, "vscroll", args, n); 01915 XtAddCallback (vscroll, XmNvalueChangedCallback, 01916 (XtCallbackProc) scroll_callback, (XtPointer) & view_top_y); 01917 XtAddCallback (vscroll, XmNdragCallback, (XtCallbackProc) scroll_callback, 01918 (XtPointer) & view_top_y); 01919 XtManageChild (vscroll); 01920 01921 n = 0; 01922 stdarg (XmNorientation, XmHORIZONTAL); 01923 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1); 01924 hscroll = XmCreateScrollBar (mainwind, "hscroll", args, n); 01925 XtAddCallback (hscroll, XmNvalueChangedCallback, 01926 (XtCallbackProc) scroll_callback, (XtPointer) & view_left_x); 01927 XtAddCallback (hscroll, XmNdragCallback, (XtCallbackProc) scroll_callback, 01928 (XtPointer) & view_left_x); 01929 XtManageChild (hscroll); 01930 01931 n = 0; 01932 stdarg (XmNresize, True); 01933 stdarg (XmNresizePolicy, XmRESIZE_ANY); 01934 messages = XmCreateForm (mainwind, "messages", args, n); 01935 XtManageChild (messages); 01936 01937 n = 0; 01938 stdarg (XmNtopAttachment, XmATTACH_FORM); 01939 stdarg (XmNbottomAttachment, XmATTACH_FORM); 01940 stdarg (XmNleftAttachment, XmATTACH_FORM); 01941 stdarg (XmNrightAttachment, XmATTACH_FORM); 01942 stdarg (XmNalignment, XmALIGNMENT_CENTER); 01943 stdarg (XmNshadowThickness, 2); 01944 m_click = XmCreateLabel (messages, "click", args, n); 01945 01946 n = 0; 01947 stdarg (XmNtopAttachment, XmATTACH_FORM); 01948 stdarg (XmNbottomAttachment, XmATTACH_FORM); 01949 stdarg (XmNleftAttachment, XmATTACH_FORM); 01950 stdarg (XmNlabelString, XmStringCreatePCB ("Command: ")); 01951 m_cmd_label = XmCreateLabel (messages, "command", args, n); 01952 01953 n = 0; 01954 stdarg (XmNtopAttachment, XmATTACH_FORM); 01955 stdarg (XmNbottomAttachment, XmATTACH_FORM); 01956 stdarg (XmNleftAttachment, XmATTACH_WIDGET); 01957 stdarg (XmNleftWidget, m_cmd_label); 01958 stdarg (XmNrightAttachment, XmATTACH_FORM); 01959 stdarg (XmNshadowThickness, 1); 01960 stdarg (XmNhighlightThickness, 0); 01961 stdarg (XmNmarginWidth, 2); 01962 stdarg (XmNmarginHeight, 2); 01963 m_cmd = XmCreateTextField (messages, "command", args, n); 01964 XtAddCallback (m_cmd, XmNactivateCallback, 01965 (XtCallbackProc) command_callback, 0); 01966 XtAddCallback (m_cmd, XmNlosingFocusCallback, 01967 (XtCallbackProc) command_callback, 0); 01968 XtAddEventHandler (m_cmd, KeyPressMask, 0, command_event_handler, 0); 01969 01970 m_mark = make_message ("m_mark", 0, 0); 01971 m_crosshair = make_message ("m_crosshair", m_mark, 0); 01972 m_grid = make_message ("m_grid", m_crosshair, 1); 01973 m_zoom = make_message ("m_zoom", m_grid, 1); 01974 lesstif_m_layer = make_message ("m_layer", m_zoom, 0); 01975 m_mode = make_message ("m_mode", lesstif_m_layer, 1); 01976 m_rats = make_message ("m_rats", m_mode, 1); 01977 m_status = make_message ("m_status", m_mode, 1); 01978 01979 XtUnmanageChild (XtParent (m_mark)); 01980 XtUnmanageChild (XtParent (m_rats)); 01981 01982 n = 0; 01983 stdarg (XmNrightAttachment, XmATTACH_FORM); 01984 XtSetValues (XtParent (m_status), args, n); 01985 01986 /* We'll use this later. */ 01987 n = 0; 01988 stdarg (XmNleftWidget, XtParent (m_mark)); 01989 XtSetValues (XtParent (m_crosshair), args, n); 01990 01991 n = 0; 01992 stdarg (XmNmessageWindow, messages); 01993 XtSetValues (mainwind, args, n); 01994 01995 if (background_image_file) 01996 LoadBackgroundImage (background_image_file); 01997 01998 XtRealizeWidget (appwidget); 01999 02000 while (!window) 02001 { 02002 XEvent e; 02003 XtAppNextEvent (app_context, &e); 02004 XtDispatchEvent (&e); 02005 } 02006 02007 PCBChanged (0, 0, 0, 0); 02008 02009 XtAppMainLoop (app_context); 02010 } 02011 02012 static void 02013 lesstif_do_exit (HID *hid) 02014 { 02015 XtAppSetExitFlag (app_context); 02016 } 02017 02018 void 02019 lesstif_uninit_menu (void); 02020 02021 static void 02022 lesstif_uninit (HID *hid) 02023 { 02024 lesstif_uninit_menu (); 02025 } 02026 02027 02028 #if 0 02029 XrmOptionDescRec lesstif_options[] = { 02030 }; 02031 02032 XtResource lesstif_resources[] = { 02033 }; 02034 #endif 02035 02036 typedef union 02037 { 02038 int i; 02039 double f; 02040 char *s; 02041 Coord c; 02042 } val_union; 02043 02044 static Boolean 02045 pcb_cvt_string_to_double (Display * d, XrmValue * args, Cardinal * num_args, 02046 XrmValue * from, XrmValue * to, XtPointer * data) 02047 { 02048 static double rv; 02049 rv = strtod ((char *) from->addr, 0); 02050 if (to->addr) 02051 *(double *) to->addr = rv; 02052 else 02053 to->addr = (XPointer) & rv; 02054 to->size = sizeof (rv); 02055 return True; 02056 } 02057 02058 static Boolean 02059 pcb_cvt_string_to_coord (Display * d, XrmValue * args, Cardinal * num_args, 02060 XrmValue * from, XrmValue * to, XtPointer *data) 02061 { 02062 static Coord rv; 02063 rv = GetValue ((char *) from->addr, NULL, NULL); 02064 if (to->addr) 02065 *(Coord *) to->addr = rv; 02066 else 02067 to->addr = (XPointer) &rv; 02068 to->size = sizeof (rv); 02069 return TRUE; 02070 } 02071 02072 static void 02073 mainwind_delete_cb () 02074 { 02075 hid_action ("Quit"); 02076 } 02077 02078 static void 02079 lesstif_listener_cb (XtPointer client_data, int *fid, XtInputId *id) 02080 { 02081 char buf[BUFSIZ]; 02082 int nbytes; 02083 02084 if ((nbytes = read (*fid, buf, BUFSIZ)) == -1) 02085 perror ("lesstif_listener_cb"); 02086 02087 if (nbytes) 02088 { 02089 buf[nbytes] = '\0'; 02090 hid_parse_actions (buf); 02091 } 02092 } 02093 02094 static void 02095 lesstif_parse_arguments (int *argc, char ***argv) 02096 { 02097 Atom close_atom; 02098 HID_AttrNode *ha; 02099 int acount = 0, amax; 02100 int rcount = 0, rmax; 02101 int i; 02102 XrmOptionDescRec *new_options; 02103 XtResource *new_resources; 02104 val_union *new_values; 02105 int render_event, render_error; 02106 02107 XtSetTypeConverter (XtRString, 02108 XtRDouble, 02109 pcb_cvt_string_to_double, NULL, 0, XtCacheAll, NULL); 02110 XtSetTypeConverter (XtRString, 02111 XtRPCBCoord, 02112 pcb_cvt_string_to_coord, NULL, 0, XtCacheAll, NULL); 02113 02114 02115 for (ha = hid_attr_nodes; ha; ha = ha->next) 02116 for (i = 0; i < ha->n; i++) 02117 { 02118 HID_Attribute *a = ha->attributes + i; 02119 switch (a->type) 02120 { 02121 case HID_Integer: 02122 case HID_Coord: 02123 case HID_Real: 02124 case HID_String: 02125 case HID_Path: 02126 case HID_Boolean: 02127 acount++; 02128 rcount++; 02129 break; 02130 default: 02131 break; 02132 } 02133 } 02134 02135 #if 0 02136 amax = acount + XtNumber (lesstif_options); 02137 #else 02138 amax = acount; 02139 #endif 02140 02141 new_options = (XrmOptionDescRec *) malloc ((amax + 1) * sizeof (XrmOptionDescRec)); 02142 02143 #if 0 02144 memcpy (new_options + acount, lesstif_options, sizeof (lesstif_options)); 02145 #endif 02146 acount = 0; 02147 02148 #if 0 02149 rmax = rcount + XtNumber (lesstif_resources); 02150 #else 02151 rmax = rcount; 02152 #endif 02153 02154 new_resources = (XtResource *) malloc ((rmax + 1) * sizeof (XtResource)); 02155 new_values = (val_union *) malloc ((rmax + 1) * sizeof (val_union)); 02156 #if 0 02157 memcpy (new_resources + acount, lesstif_resources, 02158 sizeof (lesstif_resources)); 02159 #endif 02160 rcount = 0; 02161 02162 for (ha = hid_attr_nodes; ha; ha = ha->next) 02163 for (i = 0; i < ha->n; i++) 02164 { 02165 HID_Attribute *a = ha->attributes + i; 02166 XrmOptionDescRec *o = new_options + acount; 02167 char *tmpopt, *tmpres; 02168 XtResource *r = new_resources + rcount; 02169 02170 tmpopt = (char *) malloc (strlen (a->name) + 3); 02171 tmpopt[0] = tmpopt[1] = '-'; 02172 strcpy (tmpopt + 2, a->name); 02173 o->option = tmpopt; 02174 02175 tmpres = (char *) malloc (strlen (a->name) + 2); 02176 tmpres[0] = '*'; 02177 strcpy (tmpres + 1, a->name); 02178 o->specifier = tmpres; 02179 02180 switch (a->type) 02181 { 02182 case HID_Integer: 02183 case HID_Coord: 02184 case HID_Real: 02185 case HID_String: 02186 case HID_Path: 02187 o->argKind = XrmoptionSepArg; 02188 o->value = 0; 02189 acount++; 02190 break; 02191 case HID_Boolean: 02192 o->argKind = XrmoptionNoArg; 02193 o->value = "True"; 02194 acount++; 02195 break; 02196 default: 02197 break; 02198 } 02199 02200 r->resource_name = a->name; 02201 r->resource_class = a->name; 02202 r->resource_offset = sizeof (val_union) * rcount; 02203 02204 switch (a->type) 02205 { 02206 case HID_Integer: 02207 r->resource_type = XtRInt; 02208 r->default_type = XtRInt; 02209 r->resource_size = sizeof (int); 02210 r->default_addr = &(a->default_val.int_value); 02211 rcount++; 02212 break; 02213 case HID_Coord: 02214 r->resource_type = XtRPCBCoord; 02215 r->default_type = XtRPCBCoord; 02216 r->resource_size = sizeof (Coord); 02217 r->default_addr = &(a->default_val.coord_value); 02218 rcount++; 02219 break; 02220 case HID_Real: 02221 r->resource_type = XtRDouble; 02222 r->default_type = XtRDouble; 02223 r->resource_size = sizeof (double); 02224 r->default_addr = &(a->default_val.real_value); 02225 rcount++; 02226 break; 02227 case HID_String: 02228 case HID_Path: 02229 r->resource_type = XtRString; 02230 r->default_type = XtRString; 02231 r->resource_size = sizeof (char *); 02232 r->default_addr = (char *) a->default_val.str_value; 02233 rcount++; 02234 break; 02235 case HID_Boolean: 02236 r->resource_type = XtRBoolean; 02237 r->default_type = XtRInt; 02238 r->resource_size = sizeof (int); 02239 r->default_addr = &(a->default_val.int_value); 02240 rcount++; 02241 break; 02242 default: 02243 break; 02244 } 02245 } 02246 #if 0 02247 for (i = 0; i < XtNumber (lesstif_resources); i++) 02248 { 02249 XtResource *r = new_resources + rcount; 02250 r->resource_offset = sizeof (val_union) * rcount; 02251 rcount++; 02252 } 02253 #endif 02254 02255 n = 0; 02256 stdarg (XmNdeleteResponse, XmDO_NOTHING); 02257 02258 appwidget = XtAppInitialize (&app_context, 02259 "Pcb", 02260 new_options, amax, argc, *argv, 0, args, n); 02261 02262 display = XtDisplay (appwidget); 02263 screen_s = XtScreen (appwidget); 02264 screen = XScreenNumberOfScreen (screen_s); 02265 colormap = XDefaultColormap (display, screen); 02266 02267 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0); 02268 XmAddWMProtocolCallback (appwidget, close_atom, 02269 (XtCallbackProc) mainwind_delete_cb, 0); 02270 02271 /* XSynchronize(display, True); */ 02272 02273 XtGetApplicationResources (appwidget, new_values, new_resources, 02274 rmax, 0, 0); 02275 02276 #ifdef HAVE_XRENDER 02277 use_xrender = XRenderQueryExtension (display, &render_event, &render_error) && 02278 XRenderFindVisualFormat (display, DefaultVisual(display, screen)); 02279 #ifdef HAVE_XINERAMA 02280 /* Xinerama and XRender don't get along well */ 02281 if (XineramaQueryExtension (display, &render_event, &render_error) 02282 && XineramaIsActive (display)) 02283 use_xrender = 0; 02284 #endif /* HAVE_XINERAMA */ 02285 #endif /* HAVE_XRENDER */ 02286 02287 rcount = 0; 02288 for (ha = hid_attr_nodes; ha; ha = ha->next) 02289 for (i = 0; i < ha->n; i++) 02290 { 02291 HID_Attribute *a = ha->attributes + i; 02292 val_union *v = new_values + rcount; 02293 switch (a->type) 02294 { 02295 case HID_Integer: 02296 if (a->value) 02297 *(int *) a->value = v->i; 02298 else 02299 a->default_val.int_value = v->i; 02300 rcount++; 02301 break; 02302 case HID_Coord: 02303 if (a->value) 02304 *(Coord *) a->value = v->c; 02305 else 02306 a->default_val.coord_value = v->c; 02307 rcount++; 02308 break; 02309 case HID_Boolean: 02310 if (a->value) 02311 *(char *) a->value = v->i; 02312 else 02313 a->default_val.int_value = v->i; 02314 rcount++; 02315 break; 02316 case HID_Real: 02317 if (a->value) 02318 *(double *) a->value = v->f; 02319 else 02320 a->default_val.real_value = v->f; 02321 rcount++; 02322 break; 02323 case HID_String: 02324 case HID_Path: 02325 if (a->value) 02326 *(char **) a->value = v->s; 02327 else 02328 a->default_val.str_value = v->s; 02329 rcount++; 02330 break; 02331 default: 02332 break; 02333 } 02334 } 02335 02336 /* redefine colormap, if requested via "-install" */ 02337 if (use_private_colormap) 02338 { 02339 colormap = XCopyColormapAndFree (display, colormap); 02340 XtVaSetValues (appwidget, XtNcolormap, colormap, NULL); 02341 } 02342 02343 /* listen on standard input for actions */ 02344 if (stdin_listen) 02345 { 02346 XtAppAddInput (app_context, fileno (stdin), (XtPointer) XtInputReadMask, 02347 lesstif_listener_cb, NULL); 02348 } 02349 } 02350 02354 void 02355 lesstif_draw_grid (BoxType * region) 02356 { 02357 static XPoint *points = 0; 02358 static int npoints = 0; 02359 Coord x1, y1, x2, y2, prevx; 02360 Coord x, y; 02361 int n; 02362 static GC grid_gc = 0; 02363 02364 if (!Settings.DrawGrid) 02365 return; /* grid hidden */ 02366 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE) 02367 return; /* zoomed out too far, points too close together */ 02368 if (!grid_gc) 02369 { 02370 grid_gc = XCreateGC (display, window, 0, 0); 02371 XSetFunction (display, grid_gc, GXxor); 02372 XSetForeground (display, grid_gc, grid_color); 02373 } 02374 /* Find the bounding grid points, all others lay between them, the points 02375 could be outside the drawing area, so skip those. */ 02376 if (flip_x) 02377 { 02378 x2 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX); 02379 x1 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX); 02380 if (Vx (x2) < 0) x2 -= PCB->Grid; 02381 if (Vx (x1) >= view_width) x1 += PCB->Grid; 02382 } 02383 else 02384 { 02385 x1 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX); 02386 x2 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX); 02387 if (Vx (x1) < 0) x1 += PCB->Grid; 02388 if (Vx (x2) >= view_width) x2 -= PCB->Grid; 02389 } 02390 if (flip_y) 02391 { 02392 y2 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY); 02393 y1 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY); 02394 if (Vy (y2) < 0) y2 -= PCB->Grid; 02395 if (Vy (y1) >= view_height) y1 += PCB->Grid; 02396 } 02397 else 02398 { 02399 y1 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY); 02400 y2 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY); 02401 if (Vy (y1) < 0) y1 += PCB->Grid; 02402 if (Vy (y2) >= view_height) y2 -= PCB->Grid; 02403 } 02404 n = (x2 - x1) / PCB->Grid + 1; /* Number of points in one row */ 02405 if (n > npoints) 02406 { /* [n]points are static, reallocate if we need more memory */ 02407 npoints = n + 10; 02408 points = (XPoint *) realloc (points, npoints * sizeof (XPoint)); 02409 } 02410 n = 0; 02411 prevx = 0; 02412 for (x = x1; x <= x2; x += PCB->Grid) 02413 { 02414 int temp = Vx (x); 02415 points[n].x = temp; 02416 if (n) 02417 { 02418 points[n].x -= prevx; 02419 points[n].y = 0; 02420 } 02421 prevx = temp; 02422 n++; 02423 } 02424 for (y = y1; y <= y2; y += PCB->Grid) 02425 { 02426 int vy = Vy (y); 02427 points[0].y = vy; 02428 /* Draw a row of points. CoordModePrevious makes next point relative to 02429 previous point */ 02430 XDrawPoints (display, pixmap, grid_gc, points, n, CoordModePrevious); 02431 } 02432 } /* end draw_grid */ 02433 02434 static void 02435 mark_delta_to_widget (Coord dx, Coord dy, Widget w) 02436 { 02437 char *buf; 02438 double g = coord_to_unit (Settings.grid_unit, PCB->Grid); 02439 int prec; 02440 XmString ms; 02441 02442 /* Integer-sized grid? */ 02443 if (((int) (g * 10000 + 0.5) % 10000) == 0) 02444 prec = 0; 02445 else 02446 prec = Settings.grid_unit->default_prec; 02447 02448 if (dx == 0 && dy == 0) 02449 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS", UUNIT, prec, dx, prec, dy); 02450 else 02451 { 02452 Angle angle = atan2 (dy, -dx) * 180 / M_PI; 02453 Coord dist = Distance (0, 0, dx, dy); 02454 02455 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS (%.*mS, %.2f\260)", UUNIT, 02456 prec, dx, prec, dy, prec, dist, angle); 02457 } 02458 02459 ms = XmStringCreatePCB (buf); 02460 n = 0; 02461 stdarg (XmNlabelString, ms); 02462 XtSetValues (w, args, n); 02463 g_free (buf); 02464 } 02465 02466 static int 02467 cursor_pos_to_widget (Coord x, Coord y, Widget w, int prev_state) 02468 { 02469 int this_state = prev_state; 02470 static char *buf; 02471 double g = coord_to_unit (Settings.grid_unit, PCB->Grid); 02472 XmString ms; 02473 int prec; 02474 02475 /* Determine necessary precision (and state) based 02476 * on the user's grid setting */ 02477 if (((int) (g * 10000 + 0.5) % 10000) == 0) 02478 { 02479 prec = 0; 02480 this_state = Settings.grid_unit->allow; 02481 } 02482 else 02483 { 02484 prec = Settings.grid_unit->default_prec; 02485 this_state = -Settings.grid_unit->allow; 02486 } 02487 02488 if (x < 0) 02489 buf = g_strdup (""); 02490 else 02491 buf = pcb_g_strdup_printf ("%m+%.*mS, %.*mS", UUNIT, prec, x, prec, y); 02492 02493 ms = XmStringCreatePCB (buf); 02494 n = 0; 02495 stdarg (XmNlabelString, ms); 02496 XtSetValues (w, args, n); 02497 g_free (buf); 02498 return this_state; 02499 } 02500 02501 #define S Settings 02502 02503 void 02504 lesstif_update_status_line () 02505 { 02506 char *buf = NULL; 02507 char *s45 = cur_clip (); 02508 XmString xs; 02509 02510 switch (Settings.Mode) 02511 { 02512 case VIA_MODE: 02513 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS \370=%.2mS", UUNIT, 02514 S.ViaThickness, S.Keepaway, S.ViaDrillingHole); 02515 break; 02516 case LINE_MODE: 02517 case ARC_MODE: 02518 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS %s", UUNIT, 02519 S.LineThickness, S.Keepaway, s45); 02520 break; 02521 case RECTANGLE_MODE: 02522 case POLYGON_MODE: 02523 buf = pcb_g_strdup_printf ("%m+%.2mS %s", UUNIT, S.Keepaway, s45); 02524 break; 02525 case TEXT_MODE: 02526 buf = g_strdup_printf ("%d %%", S.TextScale); 02527 break; 02528 case MOVE_MODE: 02529 case COPY_MODE: 02530 case INSERTPOINT_MODE: 02531 case RUBBERBANDMOVE_MODE: 02532 buf = g_strdup_printf ("%s", s45); 02533 break; 02534 case NO_MODE: 02535 case PASTEBUFFER_MODE: 02536 case ROTATE_MODE: 02537 case REMOVE_MODE: 02538 case THERMAL_MODE: 02539 case ARROW_MODE: 02540 case LOCK_MODE: 02541 default: 02542 buf = g_strdup(""); 02543 break; 02544 } 02545 02546 xs = XmStringCreatePCB (buf); 02547 n = 0; 02548 stdarg (XmNlabelString, xs); 02549 XtSetValues (m_status, args, n); 02550 g_free (buf); 02551 } 02552 02553 #undef S 02554 02555 static int idle_proc_set = 0; 02556 static int need_redraw = 0; 02557 02558 static Boolean 02559 idle_proc (XtPointer dummy) 02560 { 02561 if (need_redraw) 02562 { 02563 int mx, my; 02564 BoxType region; 02565 lesstif_use_mask (HID_MASK_OFF); 02566 pixmap = main_pixmap; 02567 mx = view_width; 02568 my = view_height; 02569 region.X1 = Px (0); 02570 region.Y1 = Py (0); 02571 region.X2 = Px (view_width); 02572 region.Y2 = Py (view_height); 02573 if (flip_x) 02574 { 02575 Coord tmp = region.X1; 02576 region.X1 = region.X2; 02577 region.X2 = tmp; 02578 } 02579 if (flip_y) 02580 { 02581 Coord tmp = region.Y1; 02582 region.Y1 = region.Y2; 02583 region.Y2 = tmp; 02584 } 02585 XSetForeground (display, bg_gc, bgcolor); 02586 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx, my); 02587 02588 if (region.X1 < 0 || region.Y1 < 0 02589 || region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight) 02590 { 02591 int leftmost, rightmost, topmost, bottommost; 02592 02593 leftmost = Vx (0); 02594 rightmost = Vx (PCB->MaxWidth); 02595 topmost = Vy (0); 02596 bottommost = Vy (PCB->MaxHeight); 02597 if (leftmost > rightmost) { 02598 int t = leftmost; 02599 leftmost = rightmost; 02600 rightmost = t; 02601 } 02602 if (topmost > bottommost) { 02603 int t = topmost; 02604 topmost = bottommost; 02605 bottommost = t; 02606 } 02607 if (leftmost < 0) 02608 leftmost = 0; 02609 if (topmost < 0) 02610 topmost = 0; 02611 if (rightmost > view_width) 02612 rightmost = view_width; 02613 if (bottommost > view_height) 02614 bottommost = view_height; 02615 02616 XSetForeground (display, bg_gc, offlimit_color); 02617 02618 /* L T R 02619 L x R 02620 L B R */ 02621 02622 if (leftmost > 0) 02623 { 02624 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, 02625 leftmost, view_height); 02626 } 02627 if (rightmost < view_width) 02628 { 02629 XFillRectangle (display, main_pixmap, bg_gc, rightmost+1, 0, 02630 view_width-rightmost+1, view_height); 02631 } 02632 if (topmost > 0) 02633 { 02634 XFillRectangle (display, main_pixmap, bg_gc, leftmost, 0, 02635 rightmost-leftmost+1, topmost); 02636 } 02637 if (bottommost < view_height) 02638 { 02639 XFillRectangle (display, main_pixmap, bg_gc, leftmost, bottommost+1, 02640 rightmost-leftmost+1, view_height-bottommost+1); 02641 } 02642 } 02643 DrawBackgroundImage(); 02644 hid_expose_callback (&lesstif_hid, ®ion, 0); 02645 lesstif_graphics.draw_grid (®ion); 02646 lesstif_use_mask (HID_MASK_OFF); 02647 show_crosshair (0); /* To keep the drawn / not drawn info correct */ 02648 XSetFunction (display, my_gc, GXcopy); 02649 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width, 02650 view_height, 0, 0); 02651 pixmap = window; 02652 if (crosshair_on) 02653 { 02654 DrawAttached (crosshair_gc); 02655 DrawMark (crosshair_gc); 02656 } 02657 need_redraw = 0; 02658 } 02659 02660 { 02661 static int c_x = -2, c_y = -2; 02662 static MarkType saved_mark; 02663 static const Unit *old_grid_unit = NULL; 02664 if (crosshair_x != c_x || crosshair_y != c_y 02665 || Settings.grid_unit != old_grid_unit 02666 || memcmp (&saved_mark, &Marked, sizeof (MarkType))) 02667 { 02668 static int last_state = 0; 02669 static int this_state = 0; 02670 02671 c_x = crosshair_x; 02672 c_y = crosshair_y; 02673 02674 this_state = 02675 cursor_pos_to_widget (crosshair_x, crosshair_y, m_crosshair, 02676 this_state); 02677 if (Marked.status) 02678 mark_delta_to_widget (crosshair_x - Marked.X, crosshair_y - Marked.Y, 02679 m_mark); 02680 02681 if (Marked.status != saved_mark.status) 02682 { 02683 if (Marked.status) 02684 { 02685 XtManageChild (XtParent (m_mark)); 02686 XtManageChild (m_mark); 02687 n = 0; 02688 stdarg (XmNleftAttachment, XmATTACH_WIDGET); 02689 stdarg (XmNleftWidget, XtParent (m_mark)); 02690 XtSetValues (XtParent (m_crosshair), args, n); 02691 } 02692 else 02693 { 02694 n = 0; 02695 stdarg (XmNleftAttachment, XmATTACH_FORM); 02696 XtSetValues (XtParent (m_crosshair), args, n); 02697 XtUnmanageChild (XtParent (m_mark)); 02698 } 02699 last_state = this_state + 100; 02700 } 02701 memcpy (&saved_mark, &Marked, sizeof (MarkType)); 02702 02703 if (old_grid_unit != Settings.grid_unit) 02704 { 02705 old_grid_unit = Settings.grid_unit; 02706 /* Force a resize on units change. */ 02707 last_state ++; 02708 } 02709 02710 /* This is obtuse. We want to enable XmRESIZE_ANY long enough 02711 to shrink to fit the new format (if any), then switch it 02712 back to XmRESIZE_GROW to prevent it from shrinking due to 02713 changes in the number of actual digits printed. Thus, when 02714 you switch from a small grid and %.2f formats to a large 02715 grid and %d formats, you aren't punished with a wide and 02716 mostly white-space label widget. "this_state" indicates 02717 which of the above formats we're using. "last_state" is 02718 either zero (when resizing) or the same as "this_state" 02719 (when grow-only), or a non-zero but not "this_state" which 02720 means we need to start a resize cycle. */ 02721 if (this_state != last_state && last_state) 02722 { 02723 n = 0; 02724 stdarg (XmNresizePolicy, XmRESIZE_ANY); 02725 XtSetValues (XtParent (m_mark), args, n); 02726 XtSetValues (XtParent (m_crosshair), args, n); 02727 last_state = 0; 02728 } 02729 else if (this_state != last_state) 02730 { 02731 n = 0; 02732 stdarg (XmNresizePolicy, XmRESIZE_GROW); 02733 XtSetValues (XtParent (m_mark), args, n); 02734 XtSetValues (XtParent (m_crosshair), args, n); 02735 last_state = this_state; 02736 } 02737 } 02738 } 02739 02740 { 02741 static Coord old_grid = -1; 02742 static Coord old_gx, old_gy; 02743 static const Unit *old_unit; 02744 XmString ms; 02745 if (PCB->Grid != old_grid 02746 || PCB->GridOffsetX != old_gx 02747 || PCB->GridOffsetY != old_gy || Settings.grid_unit != old_unit) 02748 { 02749 static char buf[100]; 02750 old_grid = PCB->Grid; 02751 old_unit = Settings.grid_unit; 02752 old_gx = PCB->GridOffsetX; 02753 old_gy = PCB->GridOffsetY; 02754 if (old_grid == 1) 02755 { 02756 strcpy (buf, "No Grid"); 02757 } 02758 else 02759 { 02760 if (old_gx || old_gy) 02761 pcb_snprintf (buf, sizeof (buf), "%m+%$mS @%mS,%mS", 02762 UUNIT, old_grid, old_gx, old_gy); 02763 else 02764 pcb_snprintf (buf, sizeof (buf), "%m+%$mS", UUNIT, old_grid); 02765 } 02766 ms = XmStringCreatePCB (buf); 02767 n = 0; 02768 stdarg (XmNlabelString, ms); 02769 XtSetValues (m_grid, args, n); 02770 } 02771 } 02772 02773 { 02774 static double old_zoom = -1; 02775 static const Unit *old_grid_unit = NULL; 02776 if (view_zoom != old_zoom || Settings.grid_unit != old_grid_unit) 02777 { 02778 gchar *buf = pcb_g_strdup_printf ("%m+%$mS/pix", 02779 Settings.grid_unit->allow, (Coord) view_zoom); 02780 XmString ms; 02781 02782 old_zoom = view_zoom; 02783 old_grid_unit = Settings.grid_unit; 02784 02785 ms = XmStringCreatePCB (buf); 02786 n = 0; 02787 stdarg (XmNlabelString, ms); 02788 XtSetValues (m_zoom, args, n); 02789 g_free (buf); 02790 } 02791 } 02792 02793 { 02794 if (old_cursor_mode != Settings.Mode) 02795 { 02796 char *s = "None"; 02797 XmString ms; 02798 int cursor = -1; 02799 static int free_cursor = 0; 02800 02801 old_cursor_mode = Settings.Mode; 02802 switch (Settings.Mode) 02803 { 02804 case NO_MODE: 02805 s = "None"; 02806 cursor = XC_X_cursor; 02807 break; 02808 case VIA_MODE: 02809 s = "Via"; 02810 cursor = -1; 02811 break; 02812 case LINE_MODE: 02813 s = "Line"; 02814 cursor = XC_pencil; 02815 break; 02816 case RECTANGLE_MODE: 02817 s = "Rectangle"; 02818 cursor = XC_ul_angle; 02819 break; 02820 case POLYGON_MODE: 02821 s = "Polygon"; 02822 cursor = XC_sb_up_arrow; 02823 break; 02824 case POLYGONHOLE_MODE: 02825 s = "Polygon Hole"; 02826 cursor = XC_sb_up_arrow; 02827 break; 02828 case PASTEBUFFER_MODE: 02829 s = "Paste"; 02830 cursor = XC_hand1; 02831 break; 02832 case TEXT_MODE: 02833 s = "Text"; 02834 cursor = XC_xterm; 02835 break; 02836 case ROTATE_MODE: 02837 s = "Rotate"; 02838 cursor = XC_exchange; 02839 break; 02840 case REMOVE_MODE: 02841 s = "Remove"; 02842 cursor = XC_pirate; 02843 break; 02844 case MOVE_MODE: 02845 s = "Move"; 02846 cursor = XC_crosshair; 02847 break; 02848 case COPY_MODE: 02849 s = "Copy"; 02850 cursor = XC_crosshair; 02851 break; 02852 case INSERTPOINT_MODE: 02853 s = "Insert"; 02854 cursor = XC_dotbox; 02855 break; 02856 case RUBBERBANDMOVE_MODE: 02857 s = "RBMove"; 02858 cursor = XC_top_left_corner; 02859 break; 02860 case THERMAL_MODE: 02861 s = "Thermal"; 02862 cursor = XC_iron_cross; 02863 break; 02864 case ARC_MODE: 02865 s = "Arc"; 02866 cursor = XC_question_arrow; 02867 break; 02868 case ARROW_MODE: 02869 s = "Arrow"; 02870 if (over_point) 02871 cursor = XC_draped_box; 02872 else 02873 cursor = XC_left_ptr; 02874 break; 02875 case LOCK_MODE: 02876 s = "Lock"; 02877 cursor = XC_hand2; 02878 break; 02879 } 02880 ms = XmStringCreatePCB (s); 02881 n = 0; 02882 stdarg (XmNlabelString, ms); 02883 XtSetValues (m_mode, args, n); 02884 02885 if (free_cursor) 02886 { 02887 XFreeCursor (display, my_cursor); 02888 free_cursor = 0; 02889 } 02890 if (cursor == -1) 02891 { 02892 static Pixmap nocur_source = 0; 02893 static Pixmap nocur_mask = 0; 02894 static Cursor nocursor = 0; 02895 if (nocur_source == 0) 02896 { 02897 XColor fg, bg; 02898 nocur_source = 02899 XCreateBitmapFromData (display, window, "\0", 1, 1); 02900 nocur_mask = 02901 XCreateBitmapFromData (display, window, "\0", 1, 1); 02902 02903 fg.red = fg.green = fg.blue = 65535; 02904 bg.red = bg.green = bg.blue = 0; 02905 fg.flags = bg.flags = DoRed | DoGreen | DoBlue; 02906 nocursor = XCreatePixmapCursor (display, nocur_source, 02907 nocur_mask, &fg, &bg, 0, 0); 02908 } 02909 my_cursor = nocursor; 02910 } 02911 else 02912 { 02913 my_cursor = XCreateFontCursor (display, cursor); 02914 free_cursor = 1; 02915 } 02916 XDefineCursor (display, window, my_cursor); 02917 lesstif_update_status_line (); 02918 } 02919 } 02920 { 02921 static char *old_clip = 0; 02922 static int old_tscale = -1; 02923 char *new_clip = cur_clip (); 02924 02925 if (new_clip != old_clip || Settings.TextScale != old_tscale) 02926 { 02927 lesstif_update_status_line (); 02928 old_clip = new_clip; 02929 old_tscale = Settings.TextScale; 02930 } 02931 } 02932 02933 { 02934 static int old_nrats = -1; 02935 static char buf[20]; 02936 02937 if (old_nrats != PCB->Data->RatN) 02938 { 02939 old_nrats = PCB->Data->RatN; 02940 sprintf(buf, "%d rat%s", PCB->Data->RatN, PCB->Data->RatN == 1 ? "" : "s"); 02941 if (PCB->Data->RatN) 02942 { 02943 XtManageChild(XtParent(m_rats)); 02944 XtManageChild(m_rats); 02945 n = 0; 02946 stdarg (XmNleftWidget, m_rats); 02947 XtSetValues (XtParent (m_status), args, n); 02948 } 02949 02950 n = 0; 02951 stdarg (XmNlabelString, XmStringCreatePCB (buf)); 02952 XtSetValues (m_rats, args, n); 02953 02954 if (!PCB->Data->RatN) 02955 { 02956 n = 0; 02957 stdarg (XmNleftWidget, m_mode); 02958 XtSetValues (XtParent (m_status), args, n); 02959 XtUnmanageChild(XtParent(m_rats)); 02960 } 02961 } 02962 } 02963 02964 lesstif_update_widget_flags (); 02965 02966 show_crosshair (1); 02967 idle_proc_set = 0; 02968 return True; 02969 } 02970 02971 void 02972 lesstif_need_idle_proc () 02973 { 02974 if (idle_proc_set || window == 0) 02975 return; 02976 XtAppAddWorkProc (app_context, idle_proc, 0); 02977 idle_proc_set = 1; 02978 } 02979 02980 static void 02981 lesstif_invalidate_lr (Coord l, Coord r, Coord t, Coord b) 02982 { 02983 if (!window) 02984 return; 02985 02986 need_redraw = 1; 02987 need_idle_proc (); 02988 } 02989 02990 void 02991 lesstif_invalidate_all (void) 02992 { 02993 lesstif_invalidate_lr (0, PCB->MaxWidth, 0, PCB->MaxHeight); 02994 } 02995 02996 static void 02997 lesstif_notify_crosshair_change (bool changes_complete) 02998 { 02999 static int invalidate_depth = 0; 03000 Pixmap save_pixmap; 03001 03002 if (! my_gc) 03003 return; 03004 03005 if (changes_complete) 03006 invalidate_depth --; 03007 03008 if (invalidate_depth < 0) 03009 { 03010 invalidate_depth = 0; 03011 /* A mismatch of changes_complete == false and == true notifications 03012 * is not expected to occur, but we will try to handle it gracefully. 03013 * As we know the crosshair will have been shown already, we must 03014 * repaint the entire view to be sure not to leave an artaefact. 03015 */ 03016 need_idle_proc (); 03017 return; 03018 } 03019 03020 if (invalidate_depth == 0 && crosshair_on) 03021 { 03022 save_pixmap = pixmap; 03023 pixmap = window; 03024 DrawAttached (crosshair_gc); 03025 pixmap = save_pixmap; 03026 } 03027 03028 if (!changes_complete) 03029 invalidate_depth ++; 03030 } 03031 03032 static void 03033 lesstif_notify_mark_change (bool changes_complete) 03034 { 03035 static int invalidate_depth = 0; 03036 Pixmap save_pixmap; 03037 03038 if (changes_complete) 03039 invalidate_depth --; 03040 03041 if (invalidate_depth < 0) 03042 { 03043 invalidate_depth = 0; 03044 /* A mismatch of changes_complete == false and == true notifications 03045 * is not expected to occur, but we will try to handle it gracefully. 03046 * As we know the mark will have been shown already, we must 03047 * repaint the entire view to be sure not to leave an artaefact. 03048 */ 03049 need_idle_proc (); 03050 return; 03051 } 03052 03053 if (invalidate_depth == 0 && crosshair_on) 03054 { 03055 save_pixmap = pixmap; 03056 pixmap = window; 03057 DrawMark (crosshair_gc); 03058 pixmap = save_pixmap; 03059 } 03060 03061 if (!changes_complete) 03062 invalidate_depth ++; 03063 } 03064 03065 static int 03066 lesstif_set_layer (const char *name, int group, int empty) 03067 { 03068 int idx = group; 03069 if (idx >= 0 && idx < max_group) 03070 { 03071 int n = PCB->LayerGroups.Number[group]; 03072 for (idx = 0; idx < n-1; idx ++) 03073 { 03074 int ni = PCB->LayerGroups.Entries[group][idx]; 03075 if (ni >= 0 && ni < max_copper_layer + SILK_LAYER 03076 && PCB->Data->Layer[ni].On) 03077 break; 03078 } 03079 idx = PCB->LayerGroups.Entries[group][idx]; 03080 #if 0 03081 if (idx == LayerStack[0] 03082 || GetLayerGroupNumberByNumber (idx) == 03083 GetLayerGroupNumberByNumber (LayerStack[0])) 03084 autofade = 0; 03085 else 03086 autofade = 1; 03087 #endif 03088 } 03089 #if 0 03090 else 03091 autofade = 0; 03092 #endif 03093 if (idx >= 0 && idx < max_copper_layer + SILK_LAYER) 03094 return pinout ? 1 : PCB->Data->Layer[idx].On; 03095 if (idx < 0) 03096 { 03097 switch (SL_TYPE (idx)) 03098 { 03099 case SL_INVISIBLE: 03100 return pinout ? 0 : PCB->InvisibleObjectsOn; 03101 case SL_MASK: 03102 if (SL_MYSIDE (idx) && !pinout) 03103 return TEST_FLAG (SHOWMASKFLAG, PCB); 03104 return 0; 03105 case SL_SILK: 03106 if (SL_MYSIDE (idx) || pinout) 03107 return PCB->ElementOn; 03108 return 0; 03109 case SL_ASSY: 03110 return 0; 03111 case SL_UDRILL: 03112 case SL_PDRILL: 03113 return 1; 03114 case SL_RATS: 03115 return PCB->RatOn; 03116 } 03117 } 03118 return 0; 03119 } 03120 03121 static hidGC 03122 lesstif_make_gc (void) 03123 { 03124 hidGC rv = (hid_gc_struct *) malloc (sizeof (hid_gc_struct)); 03125 memset (rv, 0, sizeof (hid_gc_struct)); 03126 rv->me_pointer = &lesstif_hid; 03127 return rv; 03128 } 03129 03130 static void 03131 lesstif_destroy_gc (hidGC gc) 03132 { 03133 free (gc); 03134 } 03135 03136 static void 03137 lesstif_use_mask (enum mask_mode mode) 03138 { 03139 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && 03140 !use_xrender) 03141 mode = HID_MASK_OFF; 03142 if ((mode == HID_MASK_OFF) == (use_mask == HID_MASK_OFF)) 03143 return; 03144 use_mask = mode; 03145 if (pinout) 03146 return; 03147 if (!window) 03148 return; 03149 /* printf("use_mask(%d)\n", use_it); */ 03150 if (!mask_pixmap) 03151 { 03152 mask_pixmap = 03153 XCreatePixmap (display, window, pixmap_w, pixmap_h, 03154 XDefaultDepth (display, screen)); 03155 mask_bitmap = XCreatePixmap (display, window, pixmap_w, pixmap_h, 1); 03156 } 03157 if (mode != HID_MASK_OFF) 03158 { 03159 pixmap = mask_pixmap; 03160 XSetForeground (display, my_gc, 0); 03161 XSetFunction (display, my_gc, GXcopy); 03162 XFillRectangle (display, mask_pixmap, my_gc, 03163 0, 0, view_width, view_height); 03164 XFillRectangle (display, mask_bitmap, bclear_gc, 03165 0, 0, view_width, view_height); 03166 } 03167 else 03168 { 03169 pixmap = main_pixmap; 03170 #ifdef HAVE_XRENDER 03171 if (use_xrender) 03172 { 03173 XRenderPictureAttributes pa; 03174 03175 pa.clip_mask = mask_bitmap; 03176 XRenderChangePicture(display, main_picture, CPClipMask, &pa); 03177 XRenderComposite(display, PictOpOver, mask_picture, pale_picture, 03178 main_picture, 0, 0, 0, 0, 0, 0, view_width, view_height); 03179 } 03180 else 03181 #endif /* HAVE_XRENDER */ 03182 { 03183 XSetClipMask (display, clip_gc, mask_bitmap); 03184 XCopyArea (display, mask_pixmap, main_pixmap, clip_gc, 03185 0, 0, view_width, view_height, 0, 0); 03186 } 03187 } 03188 } 03189 03190 static void 03191 lesstif_set_color (hidGC gc, const char *name) 03192 { 03193 static void *cache = 0; 03194 hidval cval; 03195 static XColor color, exact_color; 03196 03197 if (!display) 03198 return; 03199 if (!name) 03200 name = "red"; 03201 gc->colorname = name; 03202 if (strcmp (name, "erase") == 0) 03203 { 03204 gc->color = bgcolor; 03205 gc->erase = 1; 03206 } 03207 else if (strcmp (name, "drill") == 0) 03208 { 03209 gc->color = offlimit_color; 03210 gc->erase = 0; 03211 } 03212 else if (hid_cache_color (0, name, &cval, &cache)) 03213 { 03214 gc->color = cval.lval; 03215 gc->erase = 0; 03216 } 03217 else 03218 { 03219 if (!XAllocNamedColor (display, colormap, name, &color, &exact_color)) 03220 color.pixel = WhitePixel (display, screen); 03221 #if 0 03222 printf ("lesstif_set_color `%s' %08x rgb/%d/%d/%d\n", 03223 name, color.pixel, color.red, color.green, color.blue); 03224 #endif 03225 cval.lval = gc->color = color.pixel; 03226 hid_cache_color (1, name, &cval, &cache); 03227 gc->erase = 0; 03228 } 03229 if (autofade) 03230 { 03231 static int lastcolor = -1, lastfade = -1; 03232 if (gc->color == lastcolor) 03233 gc->color = lastfade; 03234 else 03235 { 03236 lastcolor = gc->color; 03237 color.pixel = gc->color; 03238 03239 XQueryColor (display, colormap, &color); 03240 color.red = (bgred + color.red) / 2; 03241 color.green = (bggreen + color.green) / 2; 03242 color.blue = (bgblue + color.blue) / 2; 03243 XAllocColor (display, colormap, &color); 03244 lastfade = gc->color = color.pixel; 03245 } 03246 } 03247 } 03248 03249 static void 03250 set_gc (hidGC gc) 03251 { 03252 int cap, join, width; 03253 if (gc->me_pointer != &lesstif_hid) 03254 { 03255 fprintf (stderr, "Fatal: GC from another HID passed to lesstif HID\n"); 03256 abort (); 03257 } 03258 #if 0 03259 pcb_printf ("set_gc c%s %08lx w%#mS c%d x%d e%d\n", 03260 gc->colorname, gc->color, gc->width, gc->cap, gc->xor_set, gc->erase); 03261 #endif 03262 switch (gc->cap) 03263 { 03264 case Square_Cap: 03265 cap = CapProjecting; 03266 join = JoinMiter; 03267 break; 03268 case Trace_Cap: 03269 case Round_Cap: 03270 cap = CapRound; 03271 join = JoinRound; 03272 break; 03273 case Beveled_Cap: 03274 cap = CapProjecting; 03275 join = JoinBevel; 03276 break; 03277 default: 03278 cap = CapProjecting; 03279 join = JoinBevel; 03280 break; 03281 } 03282 if (gc->xor_set) 03283 { 03284 XSetFunction (display, my_gc, GXxor); 03285 XSetForeground (display, my_gc, gc->color ^ bgcolor); 03286 } 03287 else if (gc->erase) 03288 { 03289 XSetFunction (display, my_gc, GXcopy); 03290 XSetForeground (display, my_gc, offlimit_color); 03291 } 03292 else 03293 { 03294 XSetFunction (display, my_gc, GXcopy); 03295 XSetForeground (display, my_gc, gc->color); 03296 } 03297 width = Vz (gc->width); 03298 if (width < 0) 03299 width = 0; 03300 XSetLineAttributes (display, my_gc, width, LineSolid, cap, 03301 join); 03302 if (use_mask) 03303 { 03304 if (gc->erase) 03305 mask_gc = bclear_gc; 03306 else 03307 mask_gc = bset_gc; 03308 XSetLineAttributes (display, mask_gc, Vz (gc->width), LineSolid, cap, 03309 join); 03310 } 03311 } 03312 03313 static void 03314 lesstif_set_line_cap (hidGC gc, EndCapStyle style) 03315 { 03316 gc->cap = style; 03317 } 03318 03319 static void 03320 lesstif_set_line_width (hidGC gc, Coord width) 03321 { 03322 gc->width = width; 03323 } 03324 03325 static void 03326 lesstif_set_draw_xor (hidGC gc, int xor_set) 03327 { 03328 gc->xor_set = xor_set; 03329 } 03330 03331 #define ISORT(a,b) if (a>b) { a^=b; b^=a; a^=b; } 03332 03333 static void 03334 lesstif_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 03335 { 03336 double dx1, dy1, dx2, dy2; 03337 int vw = Vz (gc->width); 03338 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase) 03339 return; 03340 #if 0 03341 pcb_printf ("draw_line %#mD-%#mD @%#mS", x1, y1, x2, y2, gc->width); 03342 #endif 03343 dx1 = Vx (x1); 03344 dy1 = Vy (y1); 03345 dx2 = Vx (x2); 03346 dy2 = Vy (y2); 03347 #if 0 03348 pcb_printf (" = %#mD-%#mD %s\n", x1, y1, x2, y2, gc->colorname); 03349 #endif 03350 03351 #if 1 03352 if (! ClipLine (0, 0, view_width, view_height, 03353 &dx1, &dy1, &dx2, &dy2, vw)) 03354 return; 03355 #endif 03356 03357 x1 = dx1; 03358 y1 = dy1; 03359 x2 = dx2; 03360 y2 = dy2; 03361 03362 set_gc (gc); 03363 if (gc->cap == Square_Cap && x1 == x2 && y1 == y2) 03364 { 03365 XFillRectangle (display, pixmap, my_gc, x1 - vw / 2, y1 - vw / 2, vw, 03366 vw); 03367 if (use_mask) 03368 XFillRectangle (display, mask_bitmap, mask_gc, x1 - vw / 2, 03369 y1 - vw / 2, vw, vw); 03370 } 03371 else 03372 { 03373 XDrawLine (display, pixmap, my_gc, x1, y1, x2, y2); 03374 if (use_mask) 03375 XDrawLine (display, mask_bitmap, mask_gc, x1, y1, x2, y2); 03376 } 03377 } 03378 03379 static void 03380 lesstif_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, 03381 Angle start_angle, Angle delta_angle) 03382 { 03383 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase) 03384 return; 03385 #if 0 03386 pcb_printf ("draw_arc %#mD %#mSx%#mS s %d d %d", cx, cy, width, height, start_angle, delta_angle); 03387 #endif 03388 width = Vz (width); 03389 height = Vz (height); 03390 cx = Vx (cx) - width; 03391 cy = Vy (cy) - height; 03392 if (flip_x) 03393 { 03394 start_angle = 180 - start_angle; 03395 delta_angle = - delta_angle; 03396 } 03397 if (flip_y) 03398 { 03399 start_angle = - start_angle; 03400 delta_angle = - delta_angle; 03401 } 03402 start_angle = NormalizeAngle (start_angle); 03403 if (start_angle >= 180) 03404 start_angle -= 360; 03405 #if 0 03406 pcb_printf (" = %#mD %#mSx%#mS %d %s\n", cx, cy, width, height, gc->width, 03407 gc->colorname); 03408 #endif 03409 set_gc (gc); 03410 XDrawArc (display, pixmap, my_gc, cx, cy, 03411 width * 2, height * 2, (start_angle + 180) * 64, 03412 delta_angle * 64); 03413 if (use_mask && !TEST_FLAG (THINDRAWFLAG, PCB)) 03414 XDrawArc (display, mask_bitmap, mask_gc, cx, cy, 03415 width * 2, height * 2, (start_angle + 180) * 64, 03416 delta_angle * 64); 03417 #if 0 03418 /* Enable this if you want to see the center and radii of drawn 03419 arcs, for debugging. */ 03420 if (TEST_FLAG (THINDRAWFLAG, PCB) 03421 && delta_angle != 360) 03422 { 03423 cx += width; 03424 cy += height; 03425 XDrawLine (display, pixmap, arc1_gc, cx, cy, 03426 cx - width*cos(start_angle*M_PI/180), 03427 cy + width*sin(start_angle*M_PI/180)); 03428 XDrawLine (display, pixmap, arc2_gc, cx, cy, 03429 cx - width*cos((start_angle+delta_angle)*M_PI/180), 03430 cy + width*sin((start_angle+delta_angle)*M_PI/180)); 03431 } 03432 #endif 03433 } 03434 03435 static void 03436 lesstif_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 03437 { 03438 int vw = Vz (gc->width); 03439 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase) 03440 return; 03441 x1 = Vx (x1); 03442 y1 = Vy (y1); 03443 x2 = Vx (x2); 03444 y2 = Vy (y2); 03445 if (x1 < -vw && x2 < -vw) 03446 return; 03447 if (y1 < -vw && y2 < -vw) 03448 return; 03449 if (x1 > view_width + vw && x2 > view_width + vw) 03450 return; 03451 if (y1 > view_height + vw && y2 > view_height + vw) 03452 return; 03453 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; } 03454 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; } 03455 set_gc (gc); 03456 XDrawRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1); 03457 if (use_mask) 03458 XDrawRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1, 03459 y2 - y1 + 1); 03460 } 03461 03462 static void 03463 lesstif_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) 03464 { 03465 if (pinout && use_mask && gc->erase) 03466 return; 03467 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase) 03468 return; 03469 #if 0 03470 pcb_printf ("fill_circle %#mD %#mS", cx, cy, radius); 03471 #endif 03472 radius = Vz (radius); 03473 cx = Vx (cx) - radius; 03474 cy = Vy (cy) - radius; 03475 if (cx < -2 * radius || cx > view_width) 03476 return; 03477 if (cy < -2 * radius || cy > view_height) 03478 return; 03479 #if 0 03480 pcb_printf (" = %#mD %#mS %lx %s\n", cx, cy, radius, gc->color, gc->colorname); 03481 #endif 03482 set_gc (gc); 03483 XFillArc (display, pixmap, my_gc, cx, cy, 03484 radius * 2, radius * 2, 0, 360 * 64); 03485 if (use_mask) 03486 XFillArc (display, mask_bitmap, mask_gc, cx, cy, 03487 radius * 2, radius * 2, 0, 360 * 64); 03488 } 03489 03490 static void 03491 lesstif_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) 03492 { 03493 static XPoint *p = 0; 03494 static int maxp = 0; 03495 int i; 03496 03497 if (maxp < n_coords) 03498 { 03499 maxp = n_coords + 10; 03500 if (p) 03501 p = (XPoint *) realloc (p, maxp * sizeof (XPoint)); 03502 else 03503 p = (XPoint *) malloc (maxp * sizeof (XPoint)); 03504 } 03505 03506 for (i = 0; i < n_coords; i++) 03507 { 03508 p[i].x = Vx (x[i]); 03509 p[i].y = Vy (y[i]); 03510 } 03511 #if 0 03512 printf ("fill_polygon %d pts\n", n_coords); 03513 #endif 03514 set_gc (gc); 03515 XFillPolygon (display, pixmap, my_gc, p, n_coords, Complex, 03516 CoordModeOrigin); 03517 if (use_mask) 03518 XFillPolygon (display, mask_bitmap, mask_gc, p, n_coords, Complex, 03519 CoordModeOrigin); 03520 } 03521 03522 static void 03523 lesstif_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 03524 { 03525 int vw = Vz (gc->width); 03526 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase) 03527 return; 03528 x1 = Vx (x1); 03529 y1 = Vy (y1); 03530 x2 = Vx (x2); 03531 y2 = Vy (y2); 03532 if (x1 < -vw && x2 < -vw) 03533 return; 03534 if (y1 < -vw && y2 < -vw) 03535 return; 03536 if (x1 > view_width + vw && x2 > view_width + vw) 03537 return; 03538 if (y1 > view_height + vw && y2 > view_height + vw) 03539 return; 03540 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; } 03541 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; } 03542 set_gc (gc); 03543 XFillRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, 03544 y2 - y1 + 1); 03545 if (use_mask) 03546 XFillRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1, 03547 y2 - y1 + 1); 03548 } 03549 03550 static void 03551 lesstif_calibrate (double xval, double yval) 03552 { 03553 CRASH; 03554 } 03555 03556 static int 03557 lesstif_shift_is_pressed (void) 03558 { 03559 return shift_pressed; 03560 } 03561 03562 static int 03563 lesstif_control_is_pressed (void) 03564 { 03565 return ctrl_pressed; 03566 } 03567 03568 static int 03569 lesstif_mod1_is_pressed (void) 03570 { 03571 return alt_pressed; 03572 } 03573 03574 extern void lesstif_get_coords (const char *msg, Coord *x, Coord *y); 03575 03576 static void 03577 lesstif_set_crosshair (int x, int y, int action) 03578 { 03579 if (crosshair_x != x || crosshair_y != y) 03580 { 03581 lesstif_show_crosshair(0); 03582 crosshair_x = x; 03583 crosshair_y = y; 03584 need_idle_proc (); 03585 03586 if (mainwind 03587 && !in_move_event 03588 && (x < view_left_x 03589 || x > view_left_x + view_width * view_zoom 03590 || y < view_top_y || y > view_top_y + view_height * view_zoom)) 03591 { 03592 view_left_x = x - (view_width * view_zoom) / 2; 03593 view_top_y = y - (view_height * view_zoom) / 2; 03594 lesstif_pan_fixup (); 03595 } 03596 03597 } 03598 03599 if (action == HID_SC_CENTER_IN_VIEWPORT_AND_WARP_POINTER) 03600 { 03601 fprintf ( 03602 stderr, 03603 "warning:%s:%i: HID_SC_CENTER_IN_VIEWPORT_AND_WARP_POINTER not " 03604 "implemented in this HID, using HID_SC_WARP_POINTER instead\n", 03605 __FILE__, 03606 __LINE__ ); 03607 action = HID_SC_WARP_POINTER; 03608 } 03609 if (action == HID_SC_PAN_VIEWPORT) 03610 { 03611 Window root, child; 03612 unsigned int keys_buttons; 03613 int pos_x, pos_y, root_x, root_y; 03614 XQueryPointer (display, window, &root, &child, 03615 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons); 03616 if (flip_x) 03617 view_left_x = x - (view_width-pos_x) * view_zoom; 03618 else 03619 view_left_x = x - pos_x * view_zoom; 03620 if (flip_y) 03621 view_top_y = y - (view_height-pos_y) * view_zoom; 03622 else 03623 view_top_y = y - pos_y * view_zoom; 03624 lesstif_pan_fixup(); 03625 action = HID_SC_WARP_POINTER; 03626 } 03627 if (action == HID_SC_WARP_POINTER) 03628 { 03629 in_move_event ++; 03630 XWarpPointer (display, None, window, 0, 0, 0, 0, Vx(x), Vy(y)); 03631 in_move_event --; 03632 } 03633 } 03634 03635 typedef struct 03636 { 03637 void (*func) (hidval); 03638 hidval user_data; 03639 XtIntervalId id; 03640 } TimerStruct; 03641 03642 static void 03643 lesstif_timer_cb (XtPointer * p, XtIntervalId * id) 03644 { 03645 TimerStruct *ts = (TimerStruct *) p; 03646 ts->func (ts->user_data); 03647 free (ts); 03648 } 03649 03650 static hidval 03651 lesstif_add_timer (void (*func) (hidval user_data), 03652 unsigned long milliseconds, hidval user_data) 03653 { 03654 TimerStruct *t; 03655 hidval rv; 03656 t = (TimerStruct *) malloc (sizeof (TimerStruct)); 03657 rv.ptr = t; 03658 t->func = func; 03659 t->user_data = user_data; 03660 t->id = XtAppAddTimeOut (app_context, milliseconds, (XtTimerCallbackProc)lesstif_timer_cb, t); 03661 return rv; 03662 } 03663 03664 static void 03665 lesstif_stop_timer (hidval hv) 03666 { 03667 TimerStruct *ts = (TimerStruct *) hv.ptr; 03668 XtRemoveTimeOut (ts->id); 03669 free (ts); 03670 } 03671 03672 03673 typedef struct 03674 { 03675 void (*func) ( hidval, int, unsigned int, hidval ); 03676 hidval user_data; 03677 int fd; 03678 XtInputId id; 03679 } 03680 WatchStruct; 03681 03682 /* We need a wrapper around the hid file watch because to pass the correct flags 03683 */ 03684 static void 03685 lesstif_watch_cb (XtPointer client_data, int *fid, XtInputId * id) 03686 { 03687 unsigned int pcb_condition = 0; 03688 struct pollfd fds; 03689 short condition; 03690 hidval x; 03691 WatchStruct *watch = (WatchStruct*)client_data; 03692 03693 fds.fd = watch->fd; 03694 fds.events = POLLIN | POLLOUT; 03695 poll( &fds, 1, 0 ); 03696 condition = fds.revents; 03697 03698 // Should we only include those we were asked to watch? 03699 if (condition & POLLIN) 03700 pcb_condition |= PCB_WATCH_READABLE; 03701 if (condition & POLLOUT) 03702 pcb_condition |= PCB_WATCH_WRITABLE; 03703 if (condition & POLLERR) 03704 pcb_condition |= PCB_WATCH_ERROR; 03705 if (condition & POLLHUP) 03706 pcb_condition |= PCB_WATCH_HANGUP; 03707 03708 x.ptr = (void *) watch; 03709 watch->func (x, watch->fd, pcb_condition, watch->user_data); 03710 03711 return; 03712 } 03713 03714 hidval 03715 lesstif_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data), 03716 hidval user_data) 03717 { 03718 WatchStruct *watch = (WatchStruct *) malloc (sizeof(WatchStruct)); 03719 hidval ret; 03720 unsigned int xt_condition = 0; 03721 03722 if (condition & PCB_WATCH_READABLE) 03723 xt_condition |= XtInputReadMask; 03724 if (condition & PCB_WATCH_WRITABLE) 03725 xt_condition |= XtInputWriteMask; 03726 if (condition & PCB_WATCH_ERROR) 03727 xt_condition |= XtInputExceptMask; 03728 if (condition & PCB_WATCH_HANGUP) 03729 xt_condition |= XtInputExceptMask; 03730 03731 watch->func = func; 03732 watch->user_data = user_data; 03733 watch->fd = fd; 03734 watch->id = XtAppAddInput( app_context, fd, (XtPointer) (size_t) xt_condition, lesstif_watch_cb, watch ); 03735 03736 ret.ptr = (void *) watch; 03737 return ret; 03738 } 03739 03740 void 03741 lesstif_unwatch_file (hidval data) 03742 { 03743 WatchStruct *watch = (WatchStruct*)data.ptr; 03744 XtRemoveInput( watch->id ); 03745 free( watch ); 03746 } 03747 03748 typedef struct 03749 { 03750 XtBlockHookId id; 03751 void (*func) (hidval user_data); 03752 hidval user_data; 03753 } BlockHookStruct; 03754 03755 static void lesstif_block_hook_cb(XtPointer user_data); 03756 03757 static void 03758 lesstif_block_hook_cb (XtPointer user_data) 03759 { 03760 BlockHookStruct *block_hook = (BlockHookStruct *)user_data; 03761 block_hook->func( block_hook->user_data ); 03762 } 03763 03764 static hidval 03765 lesstif_add_block_hook (void (*func) (hidval data), hidval user_data ) 03766 { 03767 hidval ret; 03768 BlockHookStruct *block_hook = (BlockHookStruct *) malloc( sizeof( BlockHookStruct )); 03769 03770 block_hook->func = func; 03771 block_hook->user_data = user_data; 03772 03773 block_hook->id = XtAppAddBlockHook( app_context, lesstif_block_hook_cb, (XtPointer)block_hook ); 03774 03775 ret.ptr = (void *) block_hook; 03776 return ret; 03777 } 03778 03779 static void 03780 lesstif_stop_block_hook (hidval mlpoll) 03781 { 03782 BlockHookStruct *block_hook = (BlockHookStruct *)mlpoll.ptr; 03783 XtRemoveBlockHook( block_hook->id ); 03784 free( block_hook ); 03785 } 03786 03787 03788 extern void lesstif_logv (const char *fmt, va_list ap); 03789 03790 extern int lesstif_confirm_dialog (char *msg, ...); 03791 03792 extern int lesstif_close_confirm_dialog (); 03793 03794 extern void lesstif_report_dialog (char *title, char *msg); 03795 03796 extern int 03797 lesstif_attribute_dialog (HID_Attribute * attrs, 03798 int n_attrs, HID_Attr_Val * results, 03799 const char * title, const char * descr); 03800 03801 static void 03802 pinout_callback (Widget da, PinoutData * pd, 03803 XmDrawingAreaCallbackStruct * cbs) 03804 { 03805 BoxType region; 03806 int save_vx, save_vy, save_vw, save_vh; 03807 int save_fx, save_fy; 03808 double save_vz; 03809 Pixmap save_px; 03810 int reason = cbs ? cbs->reason : 0; 03811 03812 if (pd->window == 0 && reason == XmCR_RESIZE) 03813 return; 03814 if (pd->window == 0 || reason == XmCR_RESIZE) 03815 { 03816 Dimension w, h; 03817 double z; 03818 03819 n = 0; 03820 stdarg (XmNwidth, &w); 03821 stdarg (XmNheight, &h); 03822 XtGetValues (da, args, n); 03823 03824 pd->window = XtWindow (da); 03825 pd->v_width = w; 03826 pd->v_height = h; 03827 pd->zoom = (pd->right - pd->left + 1) / (double) w; 03828 z = (pd->bottom - pd->top + 1) / (double) h; 03829 if (pd->zoom < z) 03830 pd->zoom = z; 03831 03832 pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2; 03833 pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2; 03834 } 03835 03836 save_vx = view_left_x; 03837 save_vy = view_top_y; 03838 save_vz = view_zoom; 03839 save_vw = view_width; 03840 save_vh = view_height; 03841 save_fx = flip_x; 03842 save_fy = flip_y; 03843 save_px = pixmap; 03844 pinout = pd; 03845 pixmap = pd->window; 03846 view_left_x = pd->x; 03847 view_top_y = pd->y; 03848 view_zoom = pd->zoom; 03849 view_width = pd->v_width; 03850 view_height = pd->v_height; 03851 use_mask = 0; 03852 flip_x = flip_y = 0; 03853 03854 region.X1 = 0; 03855 region.Y1 = 0; 03856 region.X2 = PCB->MaxWidth; 03857 region.Y2 = PCB->MaxHeight; 03858 03859 XFillRectangle (display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height); 03860 hid_expose_callback (&lesstif_hid, ®ion, pd->item); 03861 03862 pinout = 0; 03863 view_left_x = save_vx; 03864 view_top_y = save_vy; 03865 view_zoom = save_vz; 03866 view_width = save_vw; 03867 view_height = save_vh; 03868 pixmap = save_px; 03869 flip_x = save_fx; 03870 flip_y = save_fy; 03871 } 03872 03873 static void 03874 pinout_unmap (Widget w, PinoutData * pd, void *v) 03875 { 03876 if (pd->prev) 03877 pd->prev->next = pd->next; 03878 else 03879 pinouts = pd->next; 03880 if (pd->next) 03881 pd->next->prev = pd->prev; 03882 XtDestroyWidget (XtParent (pd->form)); 03883 free (pd); 03884 } 03885 03886 BoxType *hid_get_extents (void *item); 03887 03888 static void 03889 lesstif_show_item (void *item) 03890 { 03891 double scale; 03892 Widget da; 03893 BoxType *extents; 03894 PinoutData *pd; 03895 03896 for (pd = pinouts; pd; pd = pd->next) 03897 if (pd->item == item) 03898 return; 03899 if (!mainwind) 03900 return; 03901 03902 pd = (PinoutData *) calloc (1, sizeof (PinoutData)); 03903 03904 pd->item = item; 03905 03906 extents = hid_get_extents (item); 03907 pd->left = extents->X1; 03908 pd->right = extents->X2; 03909 pd->top = extents->Y1; 03910 pd->bottom = extents->Y2; 03911 03912 if (pd->left > pd->right) 03913 { 03914 free (pd); 03915 return; 03916 } 03917 pd->prev = 0; 03918 pd->next = pinouts; 03919 if (pd->next) 03920 pd->next->prev = pd; 03921 pinouts = pd; 03922 pd->zoom = 0; 03923 03924 n = 0; 03925 pd->form = XmCreateFormDialog (mainwind, "pinout", args, n); 03926 pd->window = 0; 03927 XtAddCallback (pd->form, XmNunmapCallback, (XtCallbackProc) pinout_unmap, 03928 (XtPointer) pd); 03929 03930 scale = 03931 sqrt (200.0 * 200.0 / 03932 ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0))); 03933 03934 n = 0; 03935 stdarg (XmNwidth, (int) (scale * (pd->right - pd->left + 1))); 03936 stdarg (XmNheight, (int) (scale * (pd->bottom - pd->top + 1))); 03937 stdarg (XmNleftAttachment, XmATTACH_FORM); 03938 stdarg (XmNrightAttachment, XmATTACH_FORM); 03939 stdarg (XmNtopAttachment, XmATTACH_FORM); 03940 stdarg (XmNbottomAttachment, XmATTACH_FORM); 03941 da = XmCreateDrawingArea (pd->form, "pinout", args, n); 03942 XtManageChild (da); 03943 03944 XtAddCallback (da, XmNexposeCallback, (XtCallbackProc) pinout_callback, 03945 (XtPointer) pd); 03946 XtAddCallback (da, XmNresizeCallback, (XtCallbackProc) pinout_callback, 03947 (XtPointer) pd); 03948 03949 XtManageChild (pd->form); 03950 pinout = 0; 03951 } 03952 03953 static void 03954 lesstif_beep (void) 03955 { 03956 putchar (7); 03957 fflush (stdout); 03958 } 03959 03960 03961 static bool progress_cancelled = false; 03962 03963 static void 03964 progress_cancel_callback (Widget w, void *v, void *cbs) 03965 { 03966 progress_cancelled = true; 03967 } 03968 03969 static Widget progress_dialog = 0; 03970 static Widget progress_cancel, progress_label; 03971 static Widget progress_scale; 03972 03973 static void 03974 lesstif_progress_dialog (int so_far, int total, const char *msg) 03975 { 03976 XmString xs; 03977 03978 if (mainwind == 0) 03979 return; 03980 03981 if (progress_dialog == 0) 03982 { 03983 Atom close_atom; 03984 03985 n = 0; 03986 stdarg (XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); 03987 stdarg (XmNtitle, "Progress"); 03988 stdarg (XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); 03989 stdarg (XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); 03990 progress_dialog = XmCreateInformationDialog (mainwind, "progress", args, n); 03991 XtAddCallback (progress_dialog, XmNcancelCallback, 03992 (XtCallbackProc) progress_cancel_callback, NULL); 03993 03994 progress_cancel = XmMessageBoxGetChild (progress_dialog, XmDIALOG_CANCEL_BUTTON); 03995 progress_label = XmMessageBoxGetChild (progress_dialog, XmDIALOG_MESSAGE_LABEL); 03996 03997 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_OK_BUTTON)); 03998 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_HELP_BUTTON)); 03999 04000 stdarg (XmNdefaultPosition, False); 04001 XtSetValues (progress_dialog, args, n); 04002 04003 n = 0; 04004 stdarg(XmNminimum, 0); 04005 stdarg(XmNvalue, 0); 04006 stdarg(XmNmaximum, total > 0 ? total : 1); 04007 stdarg(XmNorientation, XmHORIZONTAL); 04008 stdarg(XmNshowArrows, false); 04009 progress_scale = XmCreateScrollBar (progress_dialog, "scale", args, n); 04010 XtManageChild (progress_scale); 04011 04012 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0); 04013 XmAddWMProtocolCallback (XtParent (progress_dialog), close_atom, 04014 (XtCallbackProc) progress_cancel_callback, 0); 04015 } 04016 04017 n = 0; 04018 stdarg(XmNvalue, 0); 04019 stdarg(XmNsliderSize, (so_far <= total) ? (so_far < 0) ? 0 : so_far : total); 04020 stdarg(XmNmaximum, total > 0 ? total : 1); 04021 XtSetValues (progress_scale, args, n); 04022 04023 n = 0; 04024 xs = XmStringCreatePCB ((char *)msg); 04025 stdarg (XmNmessageString, xs); 04026 XtSetValues (progress_dialog, args, n); 04027 04028 return; 04029 } 04030 04031 #define MIN_TIME_SEPARATION 0.1 /* seconds */ 04032 04033 static int 04034 lesstif_progress (int so_far, int total, const char *message) 04035 { 04036 static bool started = false; 04037 XEvent e; 04038 struct timeval time; 04039 double time_delta, time_now; 04040 static double time_then = 0.0; 04041 int retval = 0; 04042 04043 if (so_far == 0 && total == 0 && message == NULL) 04044 { 04045 XtUnmanageChild (progress_dialog); 04046 started = false; 04047 progress_cancelled = false; 04048 return retval; 04049 } 04050 04051 gettimeofday (&time, NULL); 04052 time_now = time.tv_sec + time.tv_usec / 1000000.0; 04053 04054 time_delta = time_now - time_then; 04055 04056 if (started && time_delta < MIN_TIME_SEPARATION) 04057 return retval; 04058 04059 /* Create or update the progress dialog */ 04060 lesstif_progress_dialog (so_far, total, message); 04061 04062 if (!started) 04063 { 04064 XtManageChild (progress_dialog); 04065 started = true; 04066 } 04067 04068 /* Dispatch pending events */ 04069 while (XtAppPending (app_context)) 04070 { 04071 XtAppNextEvent (app_context, &e); 04072 XtDispatchEvent (&e); 04073 } 04074 idle_proc (NULL); 04075 04076 /* If rendering takes a while, make sure the core has enough time to 04077 do work. */ 04078 gettimeofday (&time, NULL); 04079 time_then = time.tv_sec + time.tv_usec / 1000000.0; 04080 04081 return progress_cancelled; 04082 } 04083 04084 static HID_DRAW * 04085 lesstif_request_debug_draw (void) 04086 { 04087 /* Send drawing to the backing pixmap */ 04088 pixmap = main_pixmap; 04089 return lesstif_hid.graphics; 04090 } 04091 04092 static void 04093 lesstif_flush_debug_draw (void) 04094 { 04095 /* Copy the backing pixmap to the display and redraw any attached objects */ 04096 XSetFunction (display, my_gc, GXcopy); 04097 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width, 04098 view_height, 0, 0); 04099 pixmap = window; 04100 if (crosshair_on) 04101 { 04102 DrawAttached (crosshair_gc); 04103 DrawMark (crosshair_gc); 04104 } 04105 pixmap = main_pixmap; 04106 } 04107 04108 static void 04109 lesstif_finish_debug_draw (void) 04110 { 04111 lesstif_flush_debug_draw (); 04112 /* No special tear down requirements 04113 */ 04114 } 04115 04116 #include "dolists.h" 04117 04118 void 04119 hid_lesstif_init () 04120 { 04121 memset (&lesstif_hid, 0, sizeof (HID)); 04122 memset (&lesstif_graphics, 0, sizeof (HID_DRAW)); 04123 04124 common_nogui_init (&lesstif_hid); 04125 common_draw_helpers_init (&lesstif_graphics); 04126 04127 lesstif_hid.struct_size = sizeof (HID); 04128 lesstif_hid.name = "lesstif"; 04129 lesstif_hid.description = "LessTif - a Motif clone for X/Unix"; 04130 lesstif_hid.gui = 1; 04131 lesstif_hid.poly_before = 1; 04132 04133 lesstif_hid.get_export_options = lesstif_get_export_options; 04134 lesstif_hid.do_export = lesstif_do_export; 04135 lesstif_hid.do_exit = lesstif_do_exit; 04136 lesstif_hid.uninit = lesstif_uninit; 04137 lesstif_hid.parse_arguments = lesstif_parse_arguments; 04138 lesstif_hid.invalidate_lr = lesstif_invalidate_lr; 04139 lesstif_hid.invalidate_all = lesstif_invalidate_all; 04140 lesstif_hid.notify_crosshair_change = lesstif_notify_crosshair_change; 04141 lesstif_hid.notify_mark_change = lesstif_notify_mark_change; 04142 lesstif_hid.set_layer = lesstif_set_layer; 04143 04144 lesstif_hid.calibrate = lesstif_calibrate; 04145 lesstif_hid.shift_is_pressed = lesstif_shift_is_pressed; 04146 lesstif_hid.control_is_pressed = lesstif_control_is_pressed; 04147 lesstif_hid.mod1_is_pressed = lesstif_mod1_is_pressed; 04148 lesstif_hid.get_coords = lesstif_get_coords; 04149 lesstif_hid.set_crosshair = lesstif_set_crosshair; 04150 lesstif_hid.add_timer = lesstif_add_timer; 04151 lesstif_hid.stop_timer = lesstif_stop_timer; 04152 lesstif_hid.watch_file = lesstif_watch_file; 04153 lesstif_hid.unwatch_file = lesstif_unwatch_file; 04154 lesstif_hid.add_block_hook = lesstif_add_block_hook; 04155 lesstif_hid.stop_block_hook = lesstif_stop_block_hook; 04156 04157 lesstif_hid.log = lesstif_log; 04158 lesstif_hid.logv = lesstif_logv; 04159 lesstif_hid.confirm_dialog = lesstif_confirm_dialog; 04160 lesstif_hid.close_confirm_dialog = lesstif_close_confirm_dialog; 04161 lesstif_hid.report_dialog = lesstif_report_dialog; 04162 lesstif_hid.prompt_for = lesstif_prompt_for; 04163 lesstif_hid.fileselect = lesstif_fileselect; 04164 lesstif_hid.attribute_dialog = lesstif_attribute_dialog; 04165 lesstif_hid.show_item = lesstif_show_item; 04166 lesstif_hid.beep = lesstif_beep; 04167 lesstif_hid.progress = lesstif_progress; 04168 lesstif_hid.edit_attributes = lesstif_attributes_dialog; 04169 04170 lesstif_hid.request_debug_draw = lesstif_request_debug_draw; 04171 lesstif_hid.flush_debug_draw = lesstif_flush_debug_draw; 04172 lesstif_hid.finish_debug_draw = lesstif_finish_debug_draw; 04173 04174 lesstif_hid.graphics = &lesstif_graphics; 04175 04176 lesstif_graphics.make_gc = lesstif_make_gc; 04177 lesstif_graphics.destroy_gc = lesstif_destroy_gc; 04178 lesstif_graphics.use_mask = lesstif_use_mask; 04179 lesstif_graphics.set_color = lesstif_set_color; 04180 lesstif_graphics.set_line_cap = lesstif_set_line_cap; 04181 lesstif_graphics.set_line_width = lesstif_set_line_width; 04182 lesstif_graphics.set_draw_xor = lesstif_set_draw_xor; 04183 lesstif_graphics.draw_line = lesstif_draw_line; 04184 lesstif_graphics.draw_arc = lesstif_draw_arc; 04185 lesstif_graphics.draw_rect = lesstif_draw_rect; 04186 lesstif_graphics.fill_circle = lesstif_fill_circle; 04187 lesstif_graphics.fill_polygon = lesstif_fill_polygon; 04188 lesstif_graphics.fill_rect = lesstif_fill_rect; 04189 04190 lesstif_graphics.draw_grid = lesstif_draw_grid; 04191 04192 lesstif_graphics.draw_pcb_polygon = common_gui_draw_pcb_polygon; 04193 04194 hid_register_hid (&lesstif_hid); 04195 #include "lesstif_lists.h" 04196 }