pcb 4.1.1
An interactive printed circuit board layout editor.

hid/lesstif/main.c

Go to the documentation of this file.
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, &region, 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, &region, 0);
02645       lesstif_graphics.draw_grid (&region);
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, &region, 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 }