1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/drawing.c,v 1.69 2011/06/09 16:11:41 cvsps Exp $
19  */
20 
21 #define _INCLUDE_FROM_DRAWING_C_
22 
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25 
26 #include "align.e"
27 #include "animate.e"
28 #include "arc.e"
29 #include "attr.e"
30 #include "auxtext.e"
31 #include "box.e"
32 #include "choice.e"
33 #include "cmd.e"
34 #include "color.e"
35 #include "cutpaste.e"
36 #include "cursor.e"
37 #include "dialog.e"
38 #include "drawing.e"
39 #include "dup.e"
40 #include "edit.e"
41 #include "eps.e"
42 #include "exec.e"
43 #include "file.e"
44 #include "font.e"
45 #include "grid.e"
46 #include "group.e"
47 #include "help.e"
48 #include "imgproc.e"
49 #include "import.e"
50 #include "inmethod.e"
51 #include "mark.e"
52 #include "mainloop.e"
53 #include "mainmenu.e"
54 #include "menu.e"
55 #include "menuinfo.e"
56 #include "miniline.e"
57 #include "msg.e"
58 #include "navigate.e"
59 #include "names.e"
60 #include "obj.e"
61 #include "oval.e"
62 #include "page.e"
63 #include "pattern.e"
64 #include "pin.e"
65 #include "poly.e"
66 #include "polygon.e"
67 #include "raster.e"
68 #include "rcbox.e"
69 #include "rect.e"
70 #include "remote.e"
71 #include "ruler.e"
72 #include "scroll.e"
73 #include "select.e"
74 #include "setup.e"
75 #include "shape.e"
76 #include "shortcut.e"
77 #include "special.e"
78 #include "stk.e"
79 #include "stream.e"
80 #include "stretch.e"
81 #include "strtbl.e"
82 #include "tangram2.e"
83 #include "tcp.e"
84 #include "text.e"
85 #include "tidget.e"
86 #include "util.e"
87 #include "wb.e"
88 #include "xbitmap.e"
89 #include "xpixmap.e"
90 
91 #define O_VIS 4
92 #define O_INVIS 4
93 #define O_GRID (O_VIS+O_INVIS)
94 
95 #define DEF_CHECK_INTERVAL 1
96 
97 int		disableRedraw=FALSE;
98 int		intrCheckInterval=DEF_CHECK_INTERVAL;
99 int		pasteInDrawTextMode=FALSE;
100 int		pasteFromFileInDrawTextMode=FALSE;
101 int		pasteCompoundTextInDrawTextMode=FALSE;
102 char		pasteFromFileName[MAXPATHLENGTH+1];
103 int		copyInDrawTextMode=FALSE;
104 int		copyDoubleByteStringInDrawTextMode=FALSE;
105 int		numRedrawBBox=INVALID;
106 int		numClipRecs=0;
107 int		clipOrdering=Unsorted;
108 XRectangle	clipRecs[4];
109 int		checkBBox=TRUE;
110 
111 int		btn1Warp=FALSE;
112 
113 int		userDisableRedraw=FALSE;
114 int		executingCommands=FALSE;
115 int		escPressedWhileExecutingCommands=FALSE;
116 int		gnDisableShortcuts=FALSE;
117 int		enableMouseWheel=TRUE;
118 int		btn2PopupMainMenu=FALSE;
119 
120 static Pixmap	execAnimatePixmap=None;
121 static int	execAnimatePixmapW=0, execAnimatePixmapH=0;
122 static int	execAnimatePixmapDataW=0, execAnimatePixmapDataH=0;
123 
124 static Pixmap	execAnimateRulerPixmap=None;
125 static int	execAnimateRulerPixmapW=0, execAnimateRulerPixmapH=0;
126 
127 static struct BBRec	smallArea[2];
128 
129 static int skipCrossHair=FALSE;
130 
SetXorDrawGC(xor_pixel)131 void SetXorDrawGC(xor_pixel)
132    int xor_pixel;
133 {
134    XGCValues values;
135 
136    values.foreground = xor_pixel;
137    values.function = GXxor;
138    values.fill_style = FillSolid;
139 #ifdef NO_THIN_LINE
140    values.line_width = 1;
141 #else
142    values.line_width = 0;
143 #endif
144    values.line_style = LineSolid;
145 
146    XChangeGC(mainDisplay, drawGC,
147          GCForeground | GCFunction | GCFillStyle | GCLineWidth | GCLineStyle,
148          &values);
149 }
150 
SetDefaultDrawWinClipRecs()151 void SetDefaultDrawWinClipRecs()
152 {
153    SetRecVals(clipRecs[0], 0, 0, ZOOMED_SIZE(drawWinW), ZOOMED_SIZE(drawWinH));
154    numClipRecs = 1;
155    clipOrdering = YXBanded;
156    XSetClipRectangles(mainDisplay, drawGC, 0, 0, clipRecs, numClipRecs,
157          clipOrdering);
158 }
159 
SetDefaultIconWinClipRecs()160 void SetDefaultIconWinClipRecs()
161 {
162    SetRecVals(clipRecs[0], 0, 0, iconWindowW, iconWindowH);
163    numClipRecs = 1;
164    clipOrdering = YXBanded;
165    XSetClipRectangles(mainDisplay, drawGC, 0, 0, clipRecs, numClipRecs,
166          clipOrdering);
167 }
168 
169 static
DrawHorizOutline(Win,Y,X1,X2,XStart,XEnd)170 void DrawHorizOutline(Win, Y, X1, X2, XStart, XEnd)
171    Window Win;
172    int Y, X1, X2, XStart, XEnd;
173    /* XStart and XEnd are the real place, X1 and X2 are on outline grid */
174 {
175    register int i;
176 
177    if (XStart-X1 < O_VIS) {
178       XDrawLine(mainDisplay, Win, defaultGC, XStart, Y, X1+O_VIS-1, Y);
179    }
180    for (i=X1+O_GRID; i < X2-O_GRID; i+= O_GRID) {
181       XDrawLine(mainDisplay, Win, defaultGC, i, Y, i+O_VIS-1, Y);
182    }
183    if (X2-XEnd < O_VIS) {
184       XDrawLine(mainDisplay, Win, defaultGC, X2-O_GRID, Y, XEnd, Y);
185    } else {
186       XDrawLine(mainDisplay, Win, defaultGC, X2-O_GRID, Y, X2-O_INVIS-1, Y);
187    }
188 }
189 
190 static
DrawVertOutline(Win,X,Y1,Y2,YStart,YEnd)191 void DrawVertOutline(Win, X, Y1, Y2, YStart, YEnd)
192    Window Win;
193    int X, Y1, Y2, YStart, YEnd;
194    /* YStart and YEnd are the real place, Y1 and Y2 are on outline grid */
195 {
196    register int i;
197 
198    if (YStart-Y1 < O_VIS) {
199       XDrawLine(mainDisplay, Win, defaultGC, X, YStart, X, Y1+O_VIS-1);
200    }
201    for (i=Y1+O_GRID; i < Y2-O_GRID; i+= O_GRID) {
202       XDrawLine(mainDisplay, Win, defaultGC, X, i, X, i+O_VIS-1);
203    }
204    if (Y2-YEnd < O_VIS) {
205       XDrawLine(mainDisplay, Win, defaultGC, X, Y2-O_GRID, X, YEnd);
206    } else {
207       XDrawLine(mainDisplay, Win, defaultGC, X, Y2-O_GRID, X, Y2-O_INVIS-1);
208    }
209 }
210 
211 static
DrawSymOutline(Win,XOff,YOff,ObjPtr)212 void DrawSymOutline(Win, XOff, YOff, ObjPtr)
213    Window Win;
214    int XOff, YOff;
215    struct ObjRec *ObjPtr;
216 {
217    int ltx, lty, rbx, rby, x_start, x_end, y_start, y_end;
218 
219    ltx = ZOOMED_SIZE(ObjPtr->obbox.ltx - XOff - QUARTER_INCH) + 1;
220    lty = ZOOMED_SIZE(ObjPtr->obbox.lty - YOff - QUARTER_INCH) + 1;
221    rbx = ZOOMED_SIZE(ObjPtr->obbox.rbx - XOff + QUARTER_INCH) - 1;
222    rby = ZOOMED_SIZE(ObjPtr->obbox.rby - YOff + QUARTER_INCH) - 1;
223 
224    x_start = (ltx % O_GRID == 0) ? ltx : (int)(ltx / O_GRID) * O_GRID;
225    x_end = (rbx % O_GRID == 0) ? rbx : ((int)(rbx / O_GRID) + 1) * O_GRID;
226    DrawHorizOutline(Win, lty, x_start, x_end, ltx, rbx);
227    DrawHorizOutline(Win, rby, x_start, x_end, ltx, rbx);
228    y_start = (lty % O_GRID == 0) ? lty : (int)(lty / O_GRID) * O_GRID;
229    y_end = (rby % O_GRID == 0) ? rby : ((int)(rby / O_GRID) + 1) * O_GRID;
230    DrawVertOutline(Win, ltx, y_start, y_end, lty, rby);
231    DrawVertOutline(Win, rbx, y_start, y_end, lty, rby);
232 }
233 
234 static
NeedToDraw(ObjBBox)235 int NeedToDraw(ObjBBox)
236    struct BBRec ObjBBox;
237 {
238    switch (numRedrawBBox) {
239    case 0: return (BBoxIntersect(ObjBBox, drawWinBBox));
240    case 1: return (BBoxIntersect(ObjBBox, drawWinBBox) &&
241          BBoxIntersect(ObjBBox, smallArea[0]));
242    case 2: return (BBoxIntersect(ObjBBox, drawWinBBox) &&
243          (BBoxIntersect(ObjBBox, smallArea[0]) ||
244          BBoxIntersect(ObjBBox, smallArea[1])));
245    default:
246       fprintf(stderr, "%s\n", TgLoadString(STID_WARN_INVALID_NUMREDRAWBBOX));
247       break;
248    }
249    return TRUE;
250 }
251 
252 #include "xbm/intr.xbm"
253 #include "xbm/trek.xbm"
254 
255 static int intrShown=FALSE;
256 static int checkCount=0;
257 static int savedCheckInterval=(-1);
258 static int intrIndex=(-1);
259 
260 static long intrTick=0L;
261 
262 static
RedrawInterrupt()263 void RedrawInterrupt()
264 {
265    GC gc;
266    XGCValues values;
267    int x=0, y=0, bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
268 #ifdef _NO_GETTIMEOFDAY
269    struct timeb now;
270 #else /* ~_NO_GETTIMEOFDAY */
271    struct timeval now;
272    struct timezone zone;
273 #endif /* _NO_GETTIMEOFDAY */
274    long cur_tick;
275 
276    if (!intrShown) return;
277 
278 #ifdef _NO_GETTIMEOFDAY
279    ftime(&now);
280    cur_tick = ((long)(((long)now.millitm) / 200)) +
281          ((long)(((long)now.time) * 5));
282 #else /* ~_NO_GETTIMEOFDAY */
283    gettimeofday(&now, &zone);
284    cur_tick = ((long)(now.tv_usec / 200000)) + ((long)(now.tv_sec * 5));
285 #endif /* _NO_GETTIMEOFDAY */
286    if (intrIndex != (-1) && intrTick == cur_tick) return;
287 
288    intrTick = cur_tick;
289    if (++intrIndex == MAXINTRS) intrIndex = 0;
290 
291    x = ((rulerW-intr_width)>>1);
292    y = ((rulerW-intr_height)>>1);
293    values.foreground = myFgPixel;
294    values.background = bg_pixel;
295    values.function = GXcopy;
296    values.fill_style = FillSolid;
297    gc = XCreateGC(mainDisplay, dummyWindow1,
298          GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
299    if (gc != NULL) {
300       if (threeDLook) {
301          XSetForeground(mainDisplay, gc, bg_pixel);
302          XFillRectangle(mainDisplay, dummyWindow1, gc, 0, 0, rulerW, rulerW);
303       }
304       values.foreground = myFgPixel;
305       values.fill_style = FillOpaqueStippled;
306       values.stipple = intrPixmap[intrIndex];
307       values.ts_x_origin = x;
308       values.ts_y_origin = y;
309       XChangeGC(mainDisplay, gc, GCForeground | GCFillStyle | GCStipple |
310             GCTileStipXOrigin | GCTileStipYOrigin, &values);
311       XFillRectangle(mainDisplay, dummyWindow1, gc, x, y, intr_width,
312             intr_height);
313       XFreeGC(mainDisplay, gc);
314    }
315    XSync(mainDisplay, False);
316 }
317 
318 static
ShowHyperSpace()319 void ShowHyperSpace()
320 {
321    GC gc;
322    XGCValues values;
323    int x=0, y=0, bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
324 
325    x = ((rulerW-1-trek_width)>>1);
326    y = ((rulerW-1-trek_height)>>1);
327    values.foreground = myFgPixel;
328    values.background = bg_pixel;
329    values.function = GXcopy;
330    values.fill_style = FillSolid;
331    gc = XCreateGC(mainDisplay, dummyWindow1,
332          GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
333    if (gc != NULL) {
334       if (threeDLook) {
335          XSetForeground(mainDisplay, gc, bg_pixel);
336          XFillRectangle(mainDisplay, dummyWindow1, gc, 0, 0, rulerW, rulerW);
337       }
338       values.foreground = myFgPixel;
339       values.fill_style = FillOpaqueStippled;
340       values.stipple = trekPixmap;
341       values.ts_x_origin = x;
342       values.ts_y_origin = y;
343       XChangeGC(mainDisplay, gc, GCForeground | GCFillStyle | GCStipple |
344             GCTileStipXOrigin | GCTileStipYOrigin, &values);
345       XFillRectangle(mainDisplay, dummyWindow1, gc, x, y, trek_width,
346             trek_height);
347       XFreeGC(mainDisplay, gc);
348    }
349 }
350 
351 static int interruptLevel=0;
352 
ShowInterrupt(CheckInterval)353 void ShowInterrupt(CheckInterval)
354    int CheckInterval;
355 {
356    if (PRTGIF || interruptLevel++ > 0) return;
357 
358    if (CheckInterval > 0) {
359       savedCheckInterval = intrCheckInterval;
360       intrCheckInterval = CheckInterval;
361    }
362    if (intrCheckInterval <= 0) return;
363 
364    intrShown = TRUE;
365    intrIndex = (-1);
366    RedrawInterrupt();
367 }
368 
HideInterrupt()369 int HideInterrupt()
370 {
371    if (PRTGIF || --interruptLevel > 0) return interruptLevel;
372    interruptLevel = 0;
373    if (execAnimatePixmap == None) {
374       XEvent ev;
375 
376       while (XCheckWindowEvent(mainDisplay,dummyWindow1,ButtonPressMask,&ev)) ;
377    }
378    XClearWindow(mainDisplay, dummyWindow1);
379    intrShown = FALSE;
380    checkCount = 0;
381    if (savedCheckInterval > 0) {
382       intrCheckInterval = savedCheckInterval;
383       savedCheckInterval = (-1);
384    }
385    if (inHyperSpace) ShowHyperSpace();
386    XSync(mainDisplay, False);
387    return 0;
388 }
389 
390 static
HighLightDummyWindow1(highlight)391 void HighLightDummyWindow1(highlight)
392    int highlight;
393 {
394    if (threeDLook) {
395       struct BBRec bbox;
396 
397       SetBBRec(&bbox, 0, 0, rulerW-1, rulerW-1);
398       if (highlight) {
399          TgDrawThreeDButton(mainDisplay, dummyWindow1, textMenuGC, &bbox,
400                TGBS_RAISED, 1, FALSE);
401       } else {
402          TgClearThreeDButton(mainDisplay, dummyWindow1, textMenuGC, &bbox, 1);
403       }
404    }
405 }
406 
RedrawDummyWindow1()407 void RedrawDummyWindow1()
408 {
409    XEvent ev;
410 
411    if (mainDisplay == NULL) return;
412 
413    while (XCheckWindowEvent(mainDisplay, dummyWindow1, ExposureMask, &ev)) ;
414    while (XCheckWindowEvent(mainDisplay, dummyWindow1, ButtonPressMask, &ev)) ;
415    if (intrShown) {
416       RedrawInterrupt();
417    } else if (inHyperSpace) {
418       ShowHyperSpace();
419    } else {
420       HideInterrupt();
421    }
422    if (intr_bits != NULL && trek_bits != NULL) { } /* do nothing but reference the variable */
423 }
424 
425 #include "xbm/run.xbm"
426 
427 static
ShowRunning(dpy,win,win_w,win_h)428 void ShowRunning(dpy, win, win_w, win_h)
429    Display *dpy;
430    Window win;
431    int win_w, win_h;
432 {
433    GC gc;
434    XGCValues values;
435    int x=0, y=0, bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
436 
437    x = ((rulerW-run_width)>>1);
438    y = ((rulerW-run_height)>>1);
439    values.foreground = myFgPixel;
440    values.background = bg_pixel;
441    values.function = GXcopy;
442    values.fill_style = FillSolid;
443    gc = XCreateGC(dpy, win,
444          GCForeground | GCBackground | GCFunction | GCFillStyle, &values);
445    if (gc != NULL) {
446       if (threeDLook) {
447          XSetForeground(dpy, gc, bg_pixel);
448          XFillRectangle(dpy, win, gc, 0, 0, win_w, win_h);
449       }
450       values.foreground = myFgPixel;
451       values.fill_style = FillOpaqueStippled;
452       values.stipple = runBitmap;
453       values.ts_x_origin = x;
454       values.ts_y_origin = y;
455       XChangeGC(dpy, gc, GCForeground | GCFillStyle | GCStipple |
456             GCTileStipXOrigin | GCTileStipYOrigin, &values);
457       XFillRectangle(dpy, win, gc, 0, 0, run_width, run_height);
458       XFreeGC(dpy, gc);
459    }
460    if (run_bits != NULL) { } /* do nothing but reference the variable */
461 }
462 
RedrawDummyWindow2()463 void RedrawDummyWindow2()
464 {
465    XEvent ev;
466 
467    if (mainDisplay == NULL) return;
468 
469    XClearWindow(mainDisplay, dummyWindow2);
470    while (XCheckWindowEvent(mainDisplay, dummyWindow2, ExposureMask, &ev)) ;
471    if (gnDisableShortcuts) {
472       ShowRunning(mainDisplay, dummyWindow2, scrollBarW, scrollBarW);
473    }
474    if (threeDLook) {
475       struct BBRec bbox;
476 
477       SetBBRec(&bbox, 0, 0, scrollBarW, scrollBarW);
478       TgDrawThreeDButton(mainDisplay, dummyWindow2, textMenuGC, &bbox,
479             gnDisableShortcuts ? TGBS_RAISED : TGBS_LOWRED, 2, TRUE);
480    }
481 }
482 
DummiesEventHandler(input)483 void DummiesEventHandler(input)
484    XEvent *input;
485 {
486    if (input->xany.window == dummyWindow1) {
487       if (input->type == Expose) {
488          RedrawDummyWindow1();
489       } else if (input->type == EnterNotify) {
490          if (intrShown) {
491             SetMouseStatus(TgLoadCachedString(CSTID_INTERRUPT),
492                   TgLoadCachedString(CSTID_INTERRUPT),
493                   TgLoadCachedString(CSTID_INTERRUPT));
494          } else if (inHyperSpace) {
495             SetMouseStatus(TgLoadCachedString(CSTID_LEAVE_HYPERSPACE),
496                   TgLoadCachedString(CSTID_PARANED_NONE),
497                   TgLoadCachedString(CSTID_PARANED_NONE));
498          } else {
499             SetMouseStatus(TgLoadCachedString(CSTID_ENTER_HYPERSPACE),
500                   TgLoadCachedString(CSTID_PARANED_NONE),
501                   TgLoadCachedString(CSTID_PARANED_NONE));
502          }
503          if (inHyperSpace) {
504             HighLightDummyWindow1(TRUE);
505          }
506       } else if (input->type == LeaveNotify) {
507          SetMouseStatus("", "", "");
508          if (inHyperSpace) {
509             HighLightDummyWindow1(FALSE);
510          }
511       } else if (input->type == ButtonPress) {
512          if (!intrShown && execAnimatePixmap == None) {
513             ToggleHyperSpace(FALSE);
514             if (inHyperSpace) {
515                HighLightDummyWindow1(TRUE);
516             }
517          } else if (intrShown) {
518             HideInterrupt();
519          }
520       }
521    } else if (input->xany.window == dummyWindow2) {
522       if (input->type == Expose) {
523          RedrawDummyWindow2();
524       } else if (input->type == EnterNotify) {
525          SetMouseStatusToAllNone();
526       }
527    }
528 }
529 
530 static XComposeStatus c_stat;
531 
KeyPressEventIsEscape(key_ev)532 int KeyPressEventIsEscape(key_ev)
533    XKeyEvent *key_ev;
534 {
535    KeySym key_sym=(KeySym)0;
536    char buf[80];
537    int has_ch=XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
538 
539    TranslateKeys(buf, &key_sym);
540    if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
541       return TRUE;
542    }
543    return FALSE;
544 }
545 
546 static
CheckESC(p_display,p_ev,psz_arg)547 Bool CheckESC(p_display, p_ev, psz_arg)
548    Display *p_display;
549    XEvent *p_ev;
550    char *psz_arg;
551 {
552    if (p_ev->type == KeyPress) {
553       if (KeyPressEventIsEscape(&p_ev->xkey)) {
554          return True;
555       }
556    }
557    return False;
558 }
559 
ESCPressed()560 int ESCPressed()
561 {
562    XEvent ev;
563 
564    if (PRTGIF) return FALSE;
565    if (XCheckIfEvent(mainDisplay, &ev, CheckESC, NULL)) {
566       if (executingCommands) {
567          escPressedWhileExecutingCommands = TRUE;
568       }
569       return TRUE;
570    }
571    if (executingCommands) {
572       return escPressedWhileExecutingCommands;
573    }
574    return FALSE;
575 }
576 
CheckInterrupt(check_esc)577 int CheckInterrupt(check_esc)
578    int check_esc;
579 {
580    if (PRTGIF) return FALSE;
581    if (execAnimatePixmap == None && intrCheckInterval <= 0) return FALSE;
582    if (check_esc && ESCPressed()) return TRUE;
583    if (++checkCount >= intrCheckInterval) {
584       XEvent ev;
585 
586       RedrawInterrupt();
587       checkCount = 0;
588       if (check_esc && XCheckWindowEvent(mainDisplay, dummyWindow1,
589             ButtonPressMask, &ev)) {
590          while (XCheckWindowEvent(mainDisplay, dummyWindow1, ButtonPressMask,
591                &ev)) ;
592          return TRUE;
593       }
594    }
595    return FALSE;
596 }
597 
DrawClippedPixmap(pixmap,win,gc,pixmap_w,pixmap_h,ltx,lty)598 void DrawClippedPixmap(pixmap, win, gc, pixmap_w, pixmap_h, ltx, lty)
599    Pixmap pixmap;
600    Window win;
601    GC gc;
602    int pixmap_w, pixmap_h, ltx, lty;
603 {
604    if (numClipRecs <= 0) {
605       XCopyArea(mainDisplay, pixmap, win, gc, 0, 0, pixmap_w, pixmap_h,
606             ltx, lty);
607    } else {
608       int i;
609       struct BBRec pixmap_bbox;
610 
611       pixmap_bbox.ltx = ltx;
612       pixmap_bbox.lty = lty;
613       pixmap_bbox.rbx = ltx+pixmap_w;
614       pixmap_bbox.rby = lty+pixmap_h;
615       for (i=0; i < numClipRecs; i++) {
616          struct BBRec bbox;
617 
618          bbox.ltx = (int)clipRecs[i].x;
619          bbox.lty = (int)clipRecs[i].y;
620          bbox.rbx = bbox.ltx + ((int)clipRecs[i].width);
621          bbox.rby = bbox.lty + ((int)clipRecs[i].height);
622          if (BBoxIntersect(pixmap_bbox, bbox)) {
623             int x, y, w, h;
624 
625             bbox.ltx = max(bbox.ltx, pixmap_bbox.ltx);
626             bbox.lty = max(bbox.lty, pixmap_bbox.lty);
627             bbox.rbx = min(bbox.rbx, pixmap_bbox.rbx);
628             bbox.rby = min(bbox.rby, pixmap_bbox.rby);
629             x = bbox.ltx - pixmap_bbox.ltx;
630             y = bbox.lty - pixmap_bbox.lty;
631             w = bbox.rbx - bbox.ltx;
632             h = bbox.rby - bbox.lty;
633             XCopyArea(mainDisplay, pixmap, win, gc, x, y, w, h,
634                   ltx+x, lty+y);
635          }
636       }
637    }
638 }
639 
FillClippedRectangle(win,gc,ltx,lty,orig_w,orig_h)640 void FillClippedRectangle(win, gc, ltx, lty, orig_w, orig_h)
641    Window win;
642    GC gc;
643    int ltx, lty, orig_w, orig_h;
644 {
645    if (numClipRecs <= 0) {
646       XFillRectangle(mainDisplay, win, gc, ltx, lty, orig_w, orig_h);
647    } else {
648       int i;
649       struct BBRec obj_bbox;
650 
651       obj_bbox.ltx = ltx;
652       obj_bbox.lty = lty;
653       obj_bbox.rbx = ltx+orig_w;
654       obj_bbox.rby = lty+orig_h;
655       for (i=0; i < numClipRecs; i++) {
656          struct BBRec bbox;
657 
658          bbox.ltx = (int)clipRecs[i].x;
659          bbox.lty = (int)clipRecs[i].y;
660          bbox.rbx = bbox.ltx + ((int)clipRecs[i].width);
661          bbox.rby = bbox.lty + ((int)clipRecs[i].height);
662          if (BBoxIntersect(obj_bbox, bbox)) {
663             int x, y, w, h;
664 
665             bbox.ltx = max(bbox.ltx, obj_bbox.ltx);
666             bbox.lty = max(bbox.lty, obj_bbox.lty);
667             bbox.rbx = min(bbox.rbx, obj_bbox.rbx);
668             bbox.rby = min(bbox.rby, obj_bbox.rby);
669             x = bbox.ltx - obj_bbox.ltx;
670             y = bbox.lty - obj_bbox.lty;
671             w = bbox.rbx - bbox.ltx;
672             h = bbox.rby - bbox.lty;
673             XFillRectangle(mainDisplay, win, gc, ltx+x, lty+y, w, h);
674          }
675       }
676    }
677 }
678 
ObjInVisibleLayer(ObjPtr)679 int ObjInVisibleLayer(ObjPtr)
680    struct ObjRec *ObjPtr;
681 {
682    struct ObjRec *obj_ptr;
683    struct AttrRec *attr_ptr;
684 
685    if (!colorLayers) return TRUE;
686 
687    switch (ObjPtr->type) {
688    case OBJ_POLY:
689    case OBJ_BOX:
690    case OBJ_OVAL:
691    case OBJ_POLYGON:
692    case OBJ_ARC:
693    case OBJ_RCBOX:
694    case OBJ_XBM:
695       if (colorLayerOn[ObjPtr->color]) {
696          return TRUE;
697       }
698       break;
699 
700    case OBJ_TEXT:
701       if (ObjPtr->detail.t->fill != NONEPAT && colorLayerOn[ObjPtr->color]) {
702          return TRUE;
703       } else {
704          return MiniLinesInVisibleLayer(&ObjPtr->detail.t->minilines);
705       }
706       break;
707 
708    case OBJ_XPM: return TRUE;
709 
710    case OBJ_GROUP:
711    case OBJ_ICON:
712    case OBJ_SYM:
713       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
714             obj_ptr=obj_ptr->prev) {
715          obj_ptr->tmp_parent = ObjPtr;
716          if (ObjInVisibleLayer(obj_ptr)) {
717             return TRUE;
718          }
719       }
720       break;
721 
722    case OBJ_PIN:
723       obj_ptr = GetPinObj(ObjPtr);
724       obj_ptr->tmp_parent = ObjPtr;
725       if (ObjInVisibleLayer(obj_ptr)) {
726          return TRUE;
727       }
728       break;
729    }
730    for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
731       if (attr_ptr->shown && ObjInVisibleLayer(attr_ptr->obj)) {
732          return TRUE;
733       }
734    }
735    return FALSE;
736 }
737 
DrawObj(Win,ObjPtr)738 int DrawObj(Win, ObjPtr)
739    Window Win;
740    register struct ObjRec *ObjPtr;
741    /* returns TRUE if all objects are drawn */
742    /* returns FALSE if interrupted by the user */
743 {
744    if (disableRedraw || (placingTopObj && ObjPtr==topObj)) {
745       return TRUE;
746    }
747    switch (ObjPtr->type) {
748    case OBJ_POLY:
749       if (!colorLayers ||
750             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
751          DrawPolyObj(Win, drawOrigX, drawOrigY, ObjPtr);
752          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
753       }
754       break;
755    case OBJ_BOX:
756       if (!colorLayers ||
757             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
758          DrawBoxObj(Win, drawOrigX, drawOrigY, ObjPtr);
759          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
760       }
761       break;
762    case OBJ_OVAL:
763       if (!colorLayers ||
764             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
765          DrawOvalObj(Win, drawOrigX, drawOrigY, ObjPtr);
766          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
767       }
768       break;
769    case OBJ_TEXT:
770       if (!colorLayers ||
771             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
772          DrawTextObj(Win, drawOrigX, drawOrigY, ObjPtr);
773       }
774       break;
775    case OBJ_POLYGON:
776       if (!colorLayers ||
777             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
778          DrawPolygonObj(Win, drawOrigX, drawOrigY, ObjPtr);
779          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
780       }
781       break;
782    case OBJ_ARC:
783       if (!colorLayers ||
784             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
785          DrawArcObj(Win, drawOrigX, drawOrigY, ObjPtr);
786          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
787       }
788       break;
789    case OBJ_RCBOX:
790       if (!colorLayers ||
791             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
792          DrawRCBoxObj(Win, drawOrigX, drawOrigY, ObjPtr);
793          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
794       }
795       break;
796    case OBJ_XBM:
797       if (!colorLayers ||
798             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
799          DrawXBmObj(Win, drawOrigX, drawOrigY, ObjPtr);
800          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
801       }
802       break;
803    case OBJ_XPM:
804       if (!colorLayers ||
805             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
806          DrawXPmObj(Win, drawOrigX, drawOrigY, ObjPtr);
807          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
808       }
809       break;
810 
811    case OBJ_SYM:
812    case OBJ_ICON:
813    case OBJ_GROUP:
814       if (!colorLayers ||
815             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
816          struct ObjRec *obj_ptr=ObjPtr->detail.r->last;
817 
818          for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
819             if (!checkBBox || NeedToDraw(obj_ptr->bbox)) {
820                obj_ptr->tmp_parent = ObjPtr;
821                if (!DrawObj(Win, obj_ptr)) return FALSE;
822                if (execAnimatePixmap == None && CheckInterrupt(TRUE)) {
823                   SetStringStatus(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
824                   Msg(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
825                   return FALSE;
826                }
827             }
828          }
829          if (ObjPtr->type == OBJ_ICON && ObjPtr->dirty) {
830             struct AttrRec *attr_ptr=ObjPtr->fattr;
831 
832             for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->next) {
833                UpdTextBBox(attr_ptr->obj);
834             }
835             AdjObjBBox(ObjPtr);
836             UpdSelBBox();
837             ObjPtr->dirty = FALSE;
838          }
839          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
840          if (ObjPtr->type == OBJ_SYM) {
841             DrawSymOutline(Win, drawOrigX, drawOrigY, ObjPtr);
842          }
843       }
844       break;
845 
846    case OBJ_PIN:
847       if (!colorLayers ||
848             ObjPtr->tmp_parent!=NULL || ObjInVisibleLayer(ObjPtr)) {
849          struct ObjRec *obj_ptr=GetPinObj(ObjPtr);
850 
851          if (!checkBBox || NeedToDraw(obj_ptr->bbox)) {
852             obj_ptr->tmp_parent = ObjPtr;
853             if (!DrawObj(Win, obj_ptr)) return FALSE;
854             if (execAnimatePixmap == None && CheckInterrupt(TRUE)) {
855                SetStringStatus(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
856                Msg(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
857                return FALSE;
858             }
859          }
860          DrawAttrs(Win, drawOrigX, drawOrigY, ObjPtr->fattr);
861       }
862       break;
863    }
864    return TRUE;
865 }
866 
DrawPaperBoundary(Win)867 void DrawPaperBoundary(Win)
868    Window Win;
869 {
870    register int x_end, y_end;
871 
872    if (mainDisplay == NULL || inSlideShow) return;
873 
874    if (drawOrigX+drawWinW > paperWidth) {
875       x_end = OFFSET_X(paperWidth);
876       if (drawOrigY+drawWinH > paperHeight) {
877          y_end = OFFSET_Y(paperHeight);
878          XDrawLine(mainDisplay, Win, defaultGC, x_end, 0, x_end, y_end);
879          XDrawLine(mainDisplay, Win, defaultGC, 0, y_end, x_end, y_end);
880       } else {
881          XDrawLine(mainDisplay, Win, defaultGC, x_end, 0, x_end,
882                ZOOMED_SIZE(drawWinH));
883       }
884    } else if (drawOrigY+drawWinH > paperHeight) {
885       y_end = OFFSET_Y(paperHeight);
886       XDrawLine(mainDisplay, Win, defaultGC, 0, y_end,
887             ZOOMED_SIZE(drawWinW), y_end);
888    }
889 }
890 
RedrawAnArea(BotObj,LtX,LtY,RbX,RbY)891 void RedrawAnArea(BotObj, LtX, LtY, RbX, RbY)
892    struct ObjRec *BotObj;
893    int LtX, LtY, RbX, RbY;
894    /* LtX, LtY, RbX, RbY are absolute coordinates */
895 {
896    register struct ObjRec *obj_ptr;
897    int x=OFFSET_X(LtX), y=OFFSET_Y(LtY), redraw_cross_hair=FALSE;
898    int w=ZOOMED_SIZE(RbX-LtX)+1, h=ZOOMED_SIZE(RbY-LtY)+1;
899 
900    if (mainDisplay == NULL || disableRedraw) return;
901 
902    if (!userDisableRedraw) {
903       smallArea[0].ltx = LtX; smallArea[0].lty = LtY;
904       smallArea[0].rbx = RbX; smallArea[0].rby = RbY;
905       if (!BBoxIntersect(smallArea[0], drawWinBBox)) {
906          return;
907       }
908       SetRecVals(clipRecs[0], OFFSET_X(LtX), OFFSET_Y(LtY),
909             ZOOMED_SIZE(RbX-LtX)+1, ZOOMED_SIZE(RbY-LtY)+1);
910       numClipRecs = 1;
911       clipOrdering = YXBanded;
912       XSetClipRectangles(mainDisplay, drawGC, 0, 0, clipRecs, numClipRecs,
913             clipOrdering);
914 
915       if (execAnimatePixmap != None) {
916          XGCValues values;
917          int real_w=(x+w >= execAnimatePixmapW ? execAnimatePixmapW-x : w);
918          int real_h=(y+h >= execAnimatePixmapH ? execAnimatePixmapH-y : h);
919 
920          if (!skipCrossHair && showCrossHair) {
921             int cx, cy;
922 
923             GetCrossHairPosition(&cx, &cy, NULL);
924             if (cx >= x && cx < x+real_w && cy >= y && cy < y+real_h) {
925                RedrawCrossHair();
926                redraw_cross_hair = TRUE;
927             }
928          }
929          values.foreground = GetDrawingBgPixel(INVALID, INVALID);
930          values.function = GXcopy;
931          values.fill_style = FillSolid;
932          XChangeGC(mainDisplay, drawGC,
933                GCForeground | GCFunction | GCFillStyle, &values);
934          XFillRectangle(mainDisplay, execAnimatePixmap, drawGC,
935                x, y, real_w, real_h);
936       } else {
937          if (!skipCrossHair && showCrossHair) {
938             int cx, cy;
939 
940             GetCrossHairPosition(&cx, &cy, NULL);
941             if (cx >= x && cx < x+w && cy >= y && cy < y+h) {
942                RedrawCrossHair();
943                redraw_cross_hair = TRUE;
944             }
945          }
946          XClearArea(mainDisplay, drawWindow, x, y, w, h, FALSE);
947       }
948 
949       if ((paperWidth >= LtX && paperWidth <= RbX) ||
950             (paperHeight >= LtY && paperHeight <= RbY)) {
951          DrawPaperBoundary(execAnimatePixmap==None ? drawWindow :
952                execAnimatePixmap);
953       }
954       if (execAnimatePixmap != None) {
955          DrawGridLines(execAnimatePixmap, x, y, w, h);
956          DrawPageLines(execAnimatePixmap, x, y, w, h);
957       } else {
958          DrawGridLines(drawWindow, x, y, w, h);
959          DrawPageLines(drawWindow, x, y, w, h);
960       }
961       ShowInterrupt(DEF_CHECK_INTERVAL);
962    }
963    numRedrawBBox = 1;
964    smallArea[0].ltx = LtX; smallArea[0].lty = LtY;
965    smallArea[0].rbx = RbX; smallArea[0].rby = RbY;
966    for (obj_ptr = BotObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
967       obj_ptr->tmp_parent = NULL;
968       if (BBoxIntersect(obj_ptr->bbox, drawWinBBox) &&
969             BBoxIntersect(obj_ptr->bbox, smallArea[0])) {
970          if (!DrawObj(execAnimatePixmap==None ? drawWindow : execAnimatePixmap,
971                obj_ptr)) {
972             break;
973          }
974          if (execAnimatePixmap == None && CheckInterrupt(TRUE)) {
975             SetStringStatus(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
976             Msg(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
977             break;
978          }
979       }
980    }
981    if (!userDisableRedraw) {
982       HideInterrupt();
983       SetDefaultDrawWinClipRecs();
984       if (execAnimatePixmap != None && execAnimateRedraw &&
985             x < execAnimatePixmapW && y < execAnimatePixmapH) {
986          int real_w=(x+w >= execAnimatePixmapW ? execAnimatePixmapW-x : w);
987          int real_h=(y+h >= execAnimatePixmapH ? execAnimatePixmapH-y : h);
988 
989          XSetFunction(mainDisplay, drawGC, GXcopy);
990          XCopyArea(mainDisplay, execAnimatePixmap, drawWindow, drawGC,
991                x, y, real_w, real_h, x, y);
992       }
993       if (redraw_cross_hair) RedrawCrossHair();
994    }
995 }
996 
RedrawAreas(BotObj,LtX1,LtY1,RbX1,RbY1,LtX2,LtY2,RbX2,RbY2)997 void RedrawAreas(BotObj, LtX1, LtY1, RbX1, RbY1, LtX2, LtY2, RbX2, RbY2)
998    struct ObjRec *BotObj;
999    int LtX1, LtY1, RbX1, RbY1, LtX2, LtY2, RbX2, RbY2;
1000    /* note:  these coordinates are absolute */
1001 {
1002    register struct ObjRec *obj_ptr;
1003    struct BBRec bbox1, bbox2;
1004    int rec1_slot, redraw_cross_hair=FALSE;
1005    int x1=OFFSET_X(LtX1), y1=OFFSET_Y(LtY1);
1006    int w1=ZOOMED_SIZE(RbX1-LtX1)+1, h1=ZOOMED_SIZE(RbY1-LtY1)+1;
1007    int x2=OFFSET_X(LtX2), y2=OFFSET_Y(LtY2);
1008    int w2=ZOOMED_SIZE(RbX2-LtX2)+1, h2=ZOOMED_SIZE(RbY2-LtY2)+1;
1009 
1010    if (mainDisplay == NULL || disableRedraw) return;
1011 
1012    bbox1.ltx = LtX1; bbox1.lty = LtY1;
1013    bbox1.rbx = RbX1; bbox1.rby = RbY1;
1014    bbox2.ltx = LtX2; bbox2.lty = LtY2;
1015    bbox2.rbx = RbX2; bbox2.rby = RbY2;
1016 
1017    if (Inside(bbox1, bbox2)) {
1018       RedrawAnArea(BotObj, LtX2, LtY2, RbX2, RbY2);
1019       return;
1020    } else if (Inside(bbox2, bbox1)) {
1021       RedrawAnArea(BotObj, LtX1, LtY1, RbX1, RbY1);
1022       return;
1023    }
1024    if (!BBoxIntersect(bbox1, drawWinBBox) &&
1025          !BBoxIntersect(bbox2, drawWinBBox)) {
1026       return;
1027    }
1028 
1029    if (!userDisableRedraw) {
1030       if (execAnimatePixmap != None) {
1031          XGCValues values;
1032          int real_w=(x1+w1 >= execAnimatePixmapW ? execAnimatePixmapW-x1 : w1);
1033          int real_h=(y1+h1 >= execAnimatePixmapH ? execAnimatePixmapH-y1 : h1);
1034 
1035          if (!skipCrossHair && showCrossHair) {
1036             int cx, cy;
1037 
1038             GetCrossHairPosition(&cx, &cy, NULL);
1039             if (cx >= x1 && cx < x1+real_w && cy >= y1 && cy < y1+real_h) {
1040                RedrawCrossHair();
1041                redraw_cross_hair = TRUE;
1042             }
1043          }
1044          values.foreground = GetDrawingBgPixel(INVALID, INVALID);
1045          values.function = GXcopy;
1046          values.fill_style = FillSolid;
1047          XChangeGC(mainDisplay, drawGC,
1048                GCForeground | GCFunction | GCFillStyle, &values);
1049          XFillRectangle(mainDisplay, execAnimatePixmap, drawGC,
1050                x1, y1, real_w, real_h);
1051       } else {
1052          if (!skipCrossHair && showCrossHair) {
1053             int cx, cy;
1054 
1055             GetCrossHairPosition(&cx, &cy, NULL);
1056             if (cx >= x1 && cx < x1+w1 && cy >= y1 && cy < y1+h1) {
1057                RedrawCrossHair();
1058                redraw_cross_hair = TRUE;
1059             }
1060          }
1061          XClearArea(mainDisplay, drawWindow, x1, y1, w1, h1, FALSE);
1062       }
1063 
1064       if (BBoxIntersect(bbox1, bbox2)) {
1065          int union_ltx, union_lty, union_rbx, union_rby;
1066 
1067          union_ltx = min(LtX1,LtX2); union_lty = min(LtY1,LtY2);
1068          union_rbx = max(RbX1,RbX2); union_rby = max(RbY1,RbY2);
1069          skipCrossHair = TRUE;
1070          RedrawAnArea(BotObj, union_ltx, union_lty, union_rbx, union_rby);
1071          skipCrossHair = FALSE;
1072          if (redraw_cross_hair) RedrawCrossHair();
1073          return;
1074       }
1075       if (LtY1 == LtY2) {
1076          rec1_slot = (LtX1 <= LtX2) ? 0 : 1;
1077          SetRecVals(clipRecs[rec1_slot], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1078                ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-LtY1)+1);
1079          SetRecVals(clipRecs[!rec1_slot], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1080                ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-LtY2)+1);
1081          numClipRecs = 2;
1082       } else {
1083          if (LtY1 < LtY2) {
1084             if (RbY1 <= LtY2) {  /* y-extents do not intersect */
1085                SetRecVals(clipRecs[0], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1086                      ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-LtY1)+1);
1087                SetRecVals(clipRecs[1], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1088                      ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-LtY2)+1);
1089                numClipRecs = 2;
1090             } else if (RbY1 >= RbY2) {
1091                /* box 2's y-extents is inside box 1's y-extents */
1092                /*
1093                 * Updated on 6/7/2009.  The old code below using rec1_slot
1094                 *       did not make sense.
1095                 *
1096                 * rec1_slot = (LtX1 < LtX2) ? 0 : 1;
1097                 */
1098                SetRecVals(clipRecs[0], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1099                      ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-LtY1)+1);
1100                SetRecVals(clipRecs[1], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1101                      ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-LtY2)+1);
1102                numClipRecs = 2;
1103             } else {
1104                SetRecVals(clipRecs[0], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1105                      ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(LtY2-LtY1)+1);
1106                if (LtX1 < LtX2) {
1107                   SetRecVals(clipRecs[1], OFFSET_X(LtX1), OFFSET_Y(LtY2),
1108                         ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-LtY2)+1);
1109                   SetRecVals(clipRecs[2], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1110                         ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY1-LtY2)+1);
1111                } else {
1112                   SetRecVals(clipRecs[1], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1113                         ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY1-LtY2)+1);
1114                   SetRecVals(clipRecs[2], OFFSET_X(LtX1), OFFSET_Y(LtY2),
1115                         ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-LtY2)+1);
1116                }
1117                SetRecVals(clipRecs[3], OFFSET_X(LtX2), OFFSET_Y(RbY1),
1118                      ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-RbY1)+1);
1119                numClipRecs = 4;
1120             }
1121          } else {
1122             if (RbY2 <= LtY1) {  /* y-extents do not intersect */
1123                SetRecVals(clipRecs[0], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1124                      ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-LtY2)+1);
1125                SetRecVals(clipRecs[1], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1126                      ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-LtY1)+1);
1127                numClipRecs = 2;
1128             } else if (RbY2 >= RbY1) {
1129                /* box 1's y-extents is inside box 2's y-extents */
1130                rec1_slot = (LtX1 < LtX2) ? 0 : 1;
1131                SetRecVals(clipRecs[rec1_slot], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1132                      ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-LtY1)+1);
1133                SetRecVals(clipRecs[!rec1_slot], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1134                      ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-LtY2)+1);
1135                numClipRecs = 2;
1136             } else {
1137                SetRecVals(clipRecs[0], OFFSET_X(LtX2), OFFSET_Y(LtY2),
1138                      ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(LtY1-LtY2)+1);
1139                if (LtX1 < LtX2) {
1140                   SetRecVals(clipRecs[1], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1141                         ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY2-LtY1)+1);
1142                   SetRecVals(clipRecs[2], OFFSET_X(LtX2), OFFSET_Y(LtY1),
1143                         ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-LtY1)+1);
1144                } else {
1145                   SetRecVals(clipRecs[1], OFFSET_X(LtX2), OFFSET_Y(LtY1),
1146                         ZOOMED_SIZE(RbX2-LtX2)+1, ZOOMED_SIZE(RbY2-LtY1)+1);
1147                   SetRecVals(clipRecs[2], OFFSET_X(LtX1), OFFSET_Y(LtY1),
1148                         ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY2-LtY1)+1);
1149                }
1150                SetRecVals(clipRecs[3], OFFSET_X(LtX1), OFFSET_Y(RbY2),
1151                      ZOOMED_SIZE(RbX1-LtX1)+1, ZOOMED_SIZE(RbY1-RbY2)+1);
1152                numClipRecs = 4;
1153             }
1154          }
1155       }
1156       clipOrdering = YXSorted;
1157       XSetClipRectangles(mainDisplay, drawGC, 0, 0, clipRecs, numClipRecs,
1158             clipOrdering);
1159 
1160       if ((paperWidth >= LtX1 && paperWidth <= RbX1) ||
1161             (paperHeight >= LtY1 && paperHeight <= RbY1) ||
1162             (paperWidth >= LtX2 && paperWidth <= RbX2) ||
1163             (paperHeight >= LtY2 && paperHeight <= RbY2)) {
1164          DrawPaperBoundary(execAnimatePixmap==None ? drawWindow :
1165                execAnimatePixmap);
1166       }
1167       if (execAnimatePixmap != None) {
1168          DrawGridLines(execAnimatePixmap, x1, y1, w1, h1);
1169          DrawPageLines(execAnimatePixmap, x1, y1, w1, h1);
1170       } else {
1171          DrawGridLines(drawWindow, x1, y1, w1, h1);
1172          DrawPageLines(drawWindow, x1, y1, w1, h1);
1173       }
1174       ShowInterrupt(DEF_CHECK_INTERVAL);
1175    }
1176    numRedrawBBox = 2;
1177    smallArea[0].ltx = LtX1; smallArea[0].lty = LtY1;
1178    smallArea[0].rbx = RbX1; smallArea[0].rby = RbY1;
1179    smallArea[1].ltx = LtX2; smallArea[1].lty = LtY2;
1180    smallArea[1].rbx = RbX2; smallArea[1].rby = RbY2;
1181    for (obj_ptr = BotObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
1182       obj_ptr->tmp_parent = NULL;
1183       if (BBoxIntersect(obj_ptr->bbox, drawWinBBox) &&
1184             (BBoxIntersect(obj_ptr->bbox, bbox1) ||
1185             BBoxIntersect(obj_ptr->bbox, bbox2))) {
1186          if (!DrawObj(execAnimatePixmap==None ? drawWindow : execAnimatePixmap,
1187                obj_ptr)) {
1188             break;
1189          }
1190          if (execAnimatePixmap == None && CheckInterrupt(TRUE)) {
1191             SetStringStatus(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
1192             Msg(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
1193             break;
1194          }
1195       }
1196    }
1197    if (!userDisableRedraw) {
1198       HideInterrupt();
1199       SetDefaultDrawWinClipRecs();
1200       if (execAnimatePixmap != None && execAnimateRedraw) {
1201          XSetFunction(mainDisplay, drawGC, GXcopy);
1202          if (x1 < execAnimatePixmapW && y1 < execAnimatePixmapH) {
1203             int real_w=(x1+w1>=execAnimatePixmapW ? execAnimatePixmapW-x1 : w1);
1204             int real_h=(y1+h1>=execAnimatePixmapH ? execAnimatePixmapH-y1 : h1);
1205 
1206             XCopyArea(mainDisplay, execAnimatePixmap, drawWindow, drawGC,
1207                   x1, y1, real_w, real_h, x1, y1);
1208          }
1209          if (x2 < execAnimatePixmapW && y2 < execAnimatePixmapH) {
1210             int real_w=(x2+w2>=execAnimatePixmapW ? execAnimatePixmapW-x2 : w2);
1211             int real_h=(y2+h2>=execAnimatePixmapH ? execAnimatePixmapH-y2 : h2);
1212 
1213             XCopyArea(mainDisplay, execAnimatePixmap, drawWindow, drawGC,
1214                   x2, y2, real_w, real_h, x2, y2);
1215          }
1216       }
1217       if (redraw_cross_hair) RedrawCrossHair();
1218    }
1219 }
1220 
1221 static
GetBetterBBox(ObjPtr,LtX,LtY,RbX,RbY,AlreadyFound)1222 void GetBetterBBox(ObjPtr, LtX, LtY, RbX, RbY, AlreadyFound)
1223    struct ObjRec *ObjPtr;
1224    int *LtX, *LtY, *RbX, *RbY, *AlreadyFound;
1225 {
1226    int found, style=INVALID, w=0, ltx, lty, rbx, rby;
1227    struct ObjRec *obj_ptr;
1228    struct AttrRec *attr_ptr;
1229 
1230    if (colorLayers &&
1231             ObjPtr->tmp_parent==NULL && !ObjInVisibleLayer(ObjPtr)) {
1232       return;
1233    }
1234    if (*AlreadyFound && ObjPtr->bbox.ltx >= *LtX && ObjPtr->bbox.lty >= *LtY &&
1235          ObjPtr->bbox.rbx <= *RbX && ObjPtr->bbox.rby <= *RbY) {
1236       return;
1237    }
1238    switch (ObjPtr->type) {
1239    case OBJ_POLY:
1240    case OBJ_ARC:
1241       switch (ObjPtr->type) {
1242       case OBJ_POLY:
1243          w = ObjPtr->detail.p->width;
1244          style = ObjPtr->detail.p->style;
1245          break;
1246       case OBJ_ARC:
1247          w = ObjPtr->detail.a->width;
1248          style = ObjPtr->detail.a->style;
1249          break;
1250       }
1251       if (style==LS_PLAIN && (w & 0x1)) {
1252          w = (w-1)>>1;
1253          ltx = ObjPtr->obbox.ltx-w; lty = ObjPtr->obbox.lty-w;
1254          rbx = ObjPtr->obbox.rbx+w; rby = ObjPtr->obbox.rby+w;
1255       } else {
1256          ltx = ObjPtr->bbox.ltx; lty = ObjPtr->bbox.lty;
1257          rbx = ObjPtr->bbox.rbx; rby = ObjPtr->bbox.rby;
1258       }
1259       break;
1260    case OBJ_BOX:
1261    case OBJ_OVAL:
1262    case OBJ_POLYGON:
1263    case OBJ_RCBOX:
1264       switch (ObjPtr->type) {
1265       case OBJ_BOX: w = ObjPtr->detail.b->width; break;
1266       case OBJ_OVAL: w = ObjPtr->detail.o->width; break;
1267       case OBJ_POLYGON: w = ObjPtr->detail.g->width; break;
1268       case OBJ_RCBOX: w = ObjPtr->detail.rcb->width; break;
1269       }
1270       if (w & 0x1) {
1271          w = (w-1)>>1;
1272          ltx = ObjPtr->obbox.ltx-w; lty = ObjPtr->obbox.lty-w;
1273          rbx = ObjPtr->obbox.rbx+w; rby = ObjPtr->obbox.rby+w;
1274       } else {
1275          ltx = ObjPtr->bbox.ltx; lty = ObjPtr->bbox.lty;
1276          rbx = ObjPtr->bbox.rbx; rby = ObjPtr->bbox.rby;
1277       }
1278       break;
1279 
1280    case OBJ_TEXT:
1281       ltx = ObjPtr->bbox.ltx; lty = ObjPtr->bbox.lty;
1282       rbx = ObjPtr->bbox.rbx; rby = ObjPtr->bbox.rby;
1283       break;
1284 
1285    case OBJ_XBM:
1286    case OBJ_XPM:
1287       ltx = ObjPtr->bbox.ltx;   lty = ObjPtr->bbox.lty;
1288       rbx = ObjPtr->bbox.rbx-1; rby = ObjPtr->bbox.rby-1;
1289       break;
1290 
1291    case OBJ_GROUP:
1292    case OBJ_ICON:
1293    case OBJ_SYM:
1294       found = FALSE;
1295       obj_ptr = ObjPtr->detail.r->last;
1296       for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
1297          obj_ptr->tmp_parent = ObjPtr;
1298          GetBetterBBox(obj_ptr, &ltx, &lty, &rbx, &rby, &found);
1299       }
1300       if (!found) {
1301          return;
1302       }
1303       break;
1304 
1305    case OBJ_PIN:
1306       found = FALSE;
1307       obj_ptr = GetPinObj(ObjPtr);
1308       obj_ptr->tmp_parent = ObjPtr;
1309       GetBetterBBox(obj_ptr, &ltx, &lty, &rbx, &rby, &found);
1310       if (!found) {
1311          return;
1312       }
1313       break;
1314    }
1315    for (attr_ptr=ObjPtr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) {
1316       if (attr_ptr->shown) {
1317          if (attr_ptr->obj->bbox.ltx < ltx) ltx = attr_ptr->obj->bbox.ltx;
1318          if (attr_ptr->obj->bbox.lty < lty) lty = attr_ptr->obj->bbox.lty;
1319          if (attr_ptr->obj->bbox.rbx > rbx) rbx = attr_ptr->obj->bbox.rbx;
1320          if (attr_ptr->obj->bbox.rby > rby) rby = attr_ptr->obj->bbox.rby;
1321       }
1322    }
1323    if (ObjPtr->type == OBJ_SYM) {
1324       if (ObjPtr->obbox.ltx-QUARTER_INCH < ltx) {
1325          ltx = ObjPtr->obbox.ltx - QUARTER_INCH;
1326       }
1327       if (ObjPtr->obbox.lty-QUARTER_INCH < lty) {
1328          lty = ObjPtr->obbox.lty - QUARTER_INCH;
1329       }
1330       if (ObjPtr->obbox.rbx+QUARTER_INCH > rbx) {
1331          rbx = ObjPtr->obbox.rbx + QUARTER_INCH;
1332       }
1333       if (ObjPtr->obbox.rby+QUARTER_INCH > rby) {
1334          rby = ObjPtr->obbox.rby + QUARTER_INCH;
1335       }
1336    }
1337    if (*AlreadyFound) {
1338       if (ltx < *LtX) *LtX = ltx; if (lty < *LtY) *LtY = lty;
1339       if (rbx > *RbX) *RbX = rbx; if (rby > *RbY) *RbY = rby;
1340    } else {
1341       *LtX = ltx; *LtY = lty; *RbX = rbx; *RbY = rby;
1342    }
1343    *AlreadyFound = TRUE;
1344 }
1345 
RedrawDuringScrolling()1346 int RedrawDuringScrolling()
1347 {
1348    return (scrollingCanvas != INVALID && (execAnimatePixmap != None ||
1349          smoothScrollingCanvas == JUMP_SCROLLING));
1350 }
1351 
1352 static
RedrawVertSliceFromCache(start_frac,scroll_all_the_way)1353 void RedrawVertSliceFromCache(start_frac, scroll_all_the_way)
1354    double start_frac;
1355    int scroll_all_the_way;
1356 {
1357    int y=0;
1358 
1359    if (start_frac < 0.0) start_frac = 0.0;
1360    if (start_frac > 1.0) start_frac = 1.0;
1361    if (scroll_all_the_way) {
1362       GetMaxScrollOrigin(NULL, &y);
1363    } else {
1364       double dv=(double)0;
1365 
1366       switch (gridSystem) {
1367       case ENGLISH_GRID:
1368          dv = ((double)paperHeight) * start_frac;
1369          break;
1370       case METRIC_GRID:
1371          if (zoomedIn && zoomScale > 1) {
1372             dv = ((double)paperHeight) * start_frac;
1373          } else {
1374             dv = ((double)paperHeight) * start_frac;
1375          }
1376          break;
1377       }
1378       y = round(dv);
1379    }
1380    XCopyArea(mainDisplay, execAnimatePixmap, drawWindow, drawGC,
1381          0, ZOOMED_SIZE(y), initDrawWinW, initDrawWinH, 0, 0);
1382    XCopyArea(mainDisplay, execAnimateRulerPixmap, vRuleWindow, defaultGC,
1383          0, ZOOMED_SIZE(y), rulerW-windowPadding, initDrawWinH, 0, 0);
1384 }
1385 
1386 static
RedrawHoriSliceFromCache(start_frac,scroll_all_the_way)1387 void RedrawHoriSliceFromCache(start_frac, scroll_all_the_way)
1388    double start_frac;
1389    int scroll_all_the_way;
1390 {
1391    int x=0;
1392 
1393    if (start_frac < 0.0) start_frac = 0.0;
1394    if (start_frac > 1.0) start_frac = 1.0;
1395    if (scroll_all_the_way) {
1396       GetMaxScrollOrigin(&x, NULL);
1397    } else {
1398       double dv=(double)0;
1399 
1400       switch (gridSystem) {
1401       case ENGLISH_GRID:
1402          dv = ((double)paperWidth) * start_frac;
1403          break;
1404       case METRIC_GRID:
1405          if (zoomedIn && zoomScale > 1) {
1406             dv = ((double)paperWidth) * start_frac;
1407          } else {
1408             dv = ((double)paperWidth) * start_frac;
1409          }
1410          break;
1411       }
1412       x = round(dv);
1413    }
1414    XCopyArea(mainDisplay, execAnimatePixmap, drawWindow, drawGC,
1415          ZOOMED_SIZE(x), 0, initDrawWinW, initDrawWinH, 0, 0);
1416    XCopyArea(mainDisplay, execAnimateRulerPixmap, hRuleWindow, defaultGC,
1417          ZOOMED_SIZE(x), 0, initDrawWinW, rulerW-windowPadding, 0, 0);
1418 }
1419 
RedrawAreaFromCache(start_frac,scroll_all_the_way)1420 void RedrawAreaFromCache(start_frac, scroll_all_the_way)
1421    double start_frac;
1422    int scroll_all_the_way;
1423 {
1424    if (mainDisplay == NULL || disableRedraw) return;
1425 
1426    if (RedrawDuringScrolling()) {
1427       switch (scrollingCanvas) {
1428       case SCRL_UP:
1429       case SCRL_DN:
1430          RedrawVertSliceFromCache(start_frac, scroll_all_the_way);
1431          break;
1432       case SCRL_LF:
1433       case SCRL_RT:
1434          RedrawHoriSliceFromCache(start_frac, scroll_all_the_way);
1435          break;
1436       }
1437    }
1438 }
1439 
RedrawDrawWindow(BotObj)1440 void RedrawDrawWindow(BotObj)
1441    struct ObjRec *BotObj;
1442 {
1443    register struct ObjRec *obj_ptr;
1444 
1445    if (mainDisplay == NULL || disableRedraw) return;
1446 
1447    if (!skipCrossHair) {
1448       RedrawCrossHair();
1449    }
1450    if (execAnimating) {
1451       int already_animating=(execAnimatePixmap!=None), x=0, y=0, w=0, h=0;
1452 
1453       if (execAnimatePixmap != None) {
1454          XFreePixmap(mainDisplay, execAnimatePixmap);
1455       }
1456       if (execAnimateRulerPixmap != None) {
1457          XFreePixmap(mainDisplay, execAnimateRulerPixmap);
1458       }
1459       execAnimatePixmap = execAnimateRulerPixmap = None;
1460       switch (scrollingCanvas) {
1461       case SCRL_UP:
1462       case SCRL_DN:
1463          execAnimatePixmapW = ZOOMED_SIZE(drawWinW);
1464          GetMaxScrollOrigin(NULL, &y);
1465          execAnimatePixmapDataH = ZOOMED_SIZE(y+drawWinH);
1466          h = ZOOMED_SIZE(paperHeight);
1467          if ((h % initDrawWinH) == 0) {
1468             execAnimatePixmapH = (((int)(h / initDrawWinH))+1)*initDrawWinH;
1469          } else {
1470             execAnimatePixmapH = (((int)(h / initDrawWinH))+2)*initDrawWinH;
1471          }
1472          execAnimateRulerPixmapW = rulerW-windowPadding;
1473          execAnimateRulerPixmapH = execAnimatePixmapH;
1474          break;
1475       case SCRL_LF:
1476       case SCRL_RT:
1477          w = ZOOMED_SIZE(paperWidth);
1478          if ((w % initDrawWinW) == 0) {
1479             execAnimatePixmapW = (((int)(w / initDrawWinW))+1)*initDrawWinW;
1480          } else {
1481             execAnimatePixmapW = (((int)(w / initDrawWinW))+2)*initDrawWinW;
1482          }
1483          GetMaxScrollOrigin(&x, NULL);
1484          execAnimatePixmapDataW = ZOOMED_SIZE(x+drawWinW);
1485          execAnimatePixmapH = ZOOMED_SIZE(drawWinH);
1486 
1487          execAnimateRulerPixmapW = execAnimatePixmapW;
1488          execAnimateRulerPixmapH = rulerW-windowPadding;
1489          break;
1490       default:
1491          execAnimatePixmapW = ZOOMED_SIZE(drawWinW);
1492          execAnimatePixmapH = ZOOMED_SIZE(drawWinH);
1493          break;
1494       }
1495       execAnimatePixmap = XCreatePixmap(mainDisplay, mainWindow,
1496             execAnimatePixmapW, execAnimatePixmapH, mainDepth);
1497       if (execAnimatePixmap == None) {
1498          if (already_animating) {
1499             sprintf(gszMsgBox, TgLoadString(STID_CANNOT_ALLOC_XPM_NO_ANIM),
1500                   execAnimatePixmapW, execAnimatePixmapH);
1501             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1502          }
1503       } else {
1504          XGCValues values;
1505 
1506          values.foreground = GetDrawingBgPixel(INVALID, INVALID);
1507          values.function = GXcopy;
1508          values.fill_style = FillSolid;
1509          XChangeGC(mainDisplay, drawGC,
1510                GCForeground | GCFunction | GCFillStyle, &values);
1511          if (scrollingCanvas != INVALID) {
1512             int saved_win_w=drawWinW, saved_win_h=drawWinH, abort=FALSE;
1513 
1514             execAnimateRulerPixmap = XCreatePixmap(mainDisplay, mainWindow,
1515                   execAnimateRulerPixmapW, execAnimateRulerPixmapH, mainDepth);
1516             if (execAnimateRulerPixmap == None) {
1517                abort = TRUE;
1518             }
1519             drawWinW = ABS_SIZE(execAnimatePixmapW);
1520             drawWinH = ABS_SIZE(execAnimatePixmapH);
1521 
1522             SetDefaultDrawWinClipRecs();
1523 
1524             XFillRectangle(mainDisplay, execAnimatePixmap, drawGC,
1525                   0, 0, execAnimatePixmapW, execAnimatePixmapH);
1526             if (execAnimateRulerPixmap != None) {
1527                XFillRectangle(mainDisplay, execAnimateRulerPixmap, drawGC,
1528                      0, 0, execAnimateRulerPixmapW, execAnimateRulerPixmapH);
1529             }
1530             drawWinW = saved_win_w;
1531             drawWinH = saved_win_h;
1532             SetDefaultDrawWinClipRecs();
1533 
1534             if (abort) {
1535                XFreePixmap(mainDisplay, execAnimatePixmap);
1536                execAnimatePixmap = None;
1537             }
1538          } else {
1539             XFillRectangle(mainDisplay, execAnimatePixmap, drawGC,
1540                   0, 0, execAnimatePixmapW, execAnimatePixmapH);
1541          }
1542       }
1543    }
1544    if (execAnimatePixmap != None && scrollingCanvas != INVALID) {
1545       int saved_orig_x=drawOrigX, saved_orig_y=drawOrigY, x=0, y=0;
1546       int saved_win_w=drawWinW, saved_win_h=drawWinH, scroll_vertical=FALSE;
1547       int watch_cursor=watchCursorOnMainWindow;
1548 
1549       SaveStatusStrings();
1550       SetStringStatus(TgLoadCachedString(CSTID_CACHING_IMAGE));
1551       if (!watch_cursor) {
1552          SetWatchCursor(drawWindow);
1553          SetWatchCursor(mainWindow);
1554       }
1555       switch (scrollingCanvas) {
1556       case SCRL_UP:
1557       case SCRL_DN:
1558          x = 0;
1559          y = ZOOMED_SIZE(drawOrigY);
1560          drawOrigY = 0;
1561          drawWinH = ABS_SIZE(execAnimatePixmapH);
1562          scroll_vertical = TRUE;
1563          break;
1564       case SCRL_LF:
1565       case SCRL_RT:
1566          x = ZOOMED_SIZE(drawOrigX);
1567          y = 0;
1568          drawOrigX = 0;
1569          drawWinW = ABS_SIZE(execAnimatePixmapW);
1570          scroll_vertical = FALSE;
1571          break;
1572       }
1573       UpdDrawWinBBox();
1574       SetDefaultDrawWinClipRecs();
1575 
1576       DrawPaperBoundary(execAnimatePixmap);
1577       RedrawGridLines(execAnimatePixmap);
1578       RedrawPageLines(execAnimatePixmap);
1579 
1580       if (scroll_vertical) {
1581          RedrawVRuler(mainDisplay, execAnimateRulerPixmap);
1582       } else {
1583          RedrawHRuler(mainDisplay, execAnimateRulerPixmap);
1584       }
1585       AdjSplineVs();
1586 
1587       numRedrawBBox = 0;
1588       ShowInterrupt(DEF_CHECK_INTERVAL);
1589       for (obj_ptr = BotObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
1590          obj_ptr->tmp_parent = NULL;
1591          if (BBoxIntersect(obj_ptr->bbox, drawWinBBox)) {
1592             if (!TgAnyButtonDown(mainDisplay, drawWindow)) {
1593                /* canceled */
1594                Msg(TgLoadString(STID_SCROLLING_CANCELED));
1595                break;
1596             }
1597             if (!DrawObj(execAnimatePixmap, obj_ptr) && CheckInterrupt(TRUE)) {
1598                break;
1599             }
1600          }
1601       }
1602       HideInterrupt();
1603 
1604       XSetFunction(mainDisplay, drawGC, GXcopy);
1605       XCopyArea(mainDisplay, execAnimatePixmap, drawWindow, drawGC,
1606             x, y, initDrawWinW, initDrawWinH, 0, 0);
1607 
1608       drawOrigX = saved_orig_x;
1609       drawOrigY = saved_orig_y;
1610       drawWinW = saved_win_w;
1611       drawWinH = saved_win_h;
1612       UpdDrawWinBBox();
1613       SetDefaultDrawWinClipRecs();
1614 
1615       if (!watch_cursor) {
1616          SetDefaultCursor(mainWindow);
1617          ShowCursor();
1618       }
1619       RestoreStatusStrings();
1620    } else {
1621       DrawPaperBoundary(execAnimatePixmap==None ? drawWindow :
1622             execAnimatePixmap);
1623       RedrawGridLines(execAnimatePixmap==None ? drawWindow : execAnimatePixmap);
1624       RedrawPageLines(execAnimatePixmap==None ? drawWindow : execAnimatePixmap);
1625 
1626       numRedrawBBox = 0;
1627       ShowInterrupt(DEF_CHECK_INTERVAL);
1628       for (obj_ptr = BotObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
1629          obj_ptr->tmp_parent = NULL;
1630          if (BBoxIntersect(obj_ptr->bbox, drawWinBBox)) {
1631             if (!DrawObj(execAnimatePixmap==None ? drawWindow :
1632                   execAnimatePixmap, obj_ptr)) {
1633                break;
1634             }
1635             if (execAnimatePixmap == None && CheckInterrupt(TRUE)) {
1636                SetStringStatus(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
1637                Msg(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
1638                break;
1639             }
1640          }
1641       }
1642       HideInterrupt();
1643       if (execAnimatePixmap != None) {
1644          XSetFunction(mainDisplay, drawGC, GXcopy);
1645          XCopyArea(mainDisplay, execAnimatePixmap, drawWindow, drawGC,
1646                0, 0, execAnimatePixmapW, execAnimatePixmapH, 0, 0);
1647       }
1648       if (!skipCrossHair) {
1649          RedrawCrossHair();
1650       }
1651    }
1652 }
1653 
DrawAllOnPixmap(LtX,LtY,W,H,nRedraw)1654 Pixmap DrawAllOnPixmap(LtX, LtY, W, H, nRedraw)
1655    int *LtX, *LtY, *W, *H, nRedraw;
1656 {
1657    register struct ObjRec *obj_ptr;
1658    int ltx, lty, rbx, rby, w, h, saved_zoom_scale, saved_zoomed_in, found=FALSE;
1659    int saved_draw_orig_x, saved_draw_orig_y, saved_draw_win_w, saved_draw_win_h;
1660    Pixmap pixmap;
1661    XGCValues values;
1662 
1663    ltx = lty = rbx = rby = 0;
1664    for (obj_ptr = botObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
1665       obj_ptr->tmp_parent = NULL;
1666       GetBetterBBox(obj_ptr, &ltx, &lty, &rbx, &rby, &found);
1667    }
1668    if (!found) {
1669       *LtX = *LtY = *W = *H = 0;
1670       sprintf(gszMsgBox, "No objects to print!");
1671       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1672       return None;
1673    }
1674    *W = w = rbx - ltx + 1;
1675    *H = h = rby - lty + 1;
1676    *LtX = ltx;
1677    *LtY = lty;
1678 
1679    saved_draw_orig_x = drawOrigX; saved_draw_orig_y = drawOrigY;
1680    saved_draw_win_w = drawWinW; saved_draw_win_h = drawWinH;
1681    saved_zoom_scale = zoomScale;
1682    saved_zoomed_in = zoomedIn;
1683 
1684    drawOrigX = ltx; drawOrigY = lty;
1685    drawWinW = w; drawWinH = h;
1686    zoomScale = 0;
1687    zoomedIn = FALSE;
1688 
1689    SetDefaultDrawWinClipRecs();
1690 
1691    pixmap = XCreatePixmap(mainDisplay, mainWindow, w, h, mainDepth);
1692 
1693    if (pixmap == None) {
1694       FailAllocPixmapMessage(w, h);
1695       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_ALLOC_PIXMAP_OF_SIZE), w, h);
1696       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1697       return None;
1698    }
1699 
1700    values.foreground = GetDrawingBgPixel(INVALID, INVALID);
1701    values.function = GXcopy;
1702    values.fill_style = FillSolid;
1703    XChangeGC(mainDisplay, drawGC,
1704          GCForeground | GCFunction | GCFillStyle, &values);
1705    XFillRectangle(mainDisplay, pixmap, drawGC, 0, 0, w, h);
1706 
1707    AdjCaches();
1708    AdjSplineVs();
1709 
1710    checkBBox = FALSE;
1711    ShowInterrupt(DEF_CHECK_INTERVAL);
1712    for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
1713       obj_ptr->tmp_parent = NULL;
1714       if (!DrawObj(pixmap, obj_ptr)) {
1715          XFreePixmap(mainDisplay, pixmap);
1716          pixmap = None;
1717          break;
1718       }
1719       if (execAnimatePixmap == None && CheckInterrupt(TRUE)) {
1720          SetStringStatus(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
1721          Msg(TgLoadString(STID_USER_INTR_ABORT_REPAINT));
1722          XFreePixmap(mainDisplay, pixmap);
1723          pixmap = None;
1724          break;
1725       }
1726    }
1727    HideInterrupt();
1728    checkBBox = TRUE;
1729 
1730    drawOrigX = saved_draw_orig_x; drawOrigY = saved_draw_orig_y;
1731    drawWinW = saved_draw_win_w; drawWinH = saved_draw_win_h;
1732    zoomedIn = saved_zoomed_in;
1733    zoomScale = saved_zoom_scale;
1734 
1735    AdjSplineVs();
1736    AdjCaches();
1737    SetDefaultDrawWinClipRecs();
1738 
1739    skipCrossHair = TRUE;
1740    if (nRedraw) RedrawDrawWindow(botObj);
1741    skipCrossHair = FALSE;
1742 
1743    if (gpExportClipBBox != NULL) {
1744       int y, intersect_w=0, intersect_h=0;
1745       int src_offset_x=0, src_offset_y=0, dest_offset_x=0, dest_offset_y=0;
1746       int dest_w=gpExportClipBBox->rbx-gpExportClipBBox->ltx;
1747       int dest_h=gpExportClipBBox->rby-gpExportClipBBox->lty;
1748       Pixmap dest_pixmap=XCreatePixmap(mainDisplay, mainWindow, dest_w,
1749             dest_h, mainDepth);
1750       XImage *src_image=NULL, *dest_image=NULL;
1751       struct BBRec src_bbox, intersect_bbox;
1752 
1753       if (dest_pixmap == None) FailAllocBitmapMessage(dest_w, dest_h);
1754       XSetForeground(mainDisplay, drawGC, GetDrawingBgPixel(INVALID, INVALID));
1755       XFillRectangle(mainDisplay, dest_pixmap, drawGC, 0, 0, dest_w, dest_h);
1756 
1757       SetBBRec(&src_bbox, (*LtX), (*LtY), (*LtX)+(*W), (*LtY)+(*H));
1758       if (!IntersectRect(src_bbox, *gpExportClipBBox, &intersect_bbox)) {
1759          XFreePixmap(mainDisplay, pixmap);
1760          return dest_pixmap;
1761       }
1762       dest_image = XGetImage(mainDisplay, dest_pixmap, 0, 0, dest_w, dest_h,
1763             AllPlanes, ZPixmap);
1764       if (dest_image == NULL) FailAllocMessage();
1765 
1766       src_image = XGetImage(mainDisplay, pixmap, 0, 0, (*W), (*H), AllPlanes,
1767             ZPixmap);
1768       if (src_image == NULL) FailAllocMessage();
1769 
1770       intersect_w = intersect_bbox.rbx-intersect_bbox.ltx;
1771       intersect_h = intersect_bbox.rby-intersect_bbox.lty;
1772       src_offset_x = intersect_bbox.ltx-src_bbox.ltx;
1773       src_offset_y = intersect_bbox.lty-src_bbox.lty;
1774       dest_offset_x = intersect_bbox.ltx-gpExportClipBBox->ltx;
1775       dest_offset_y = intersect_bbox.lty-gpExportClipBBox->lty;
1776 
1777       for (y=0; y < intersect_h; y++) {
1778          int x;
1779 
1780          for (x=0; x < intersect_w; x++) {
1781             XPutPixel(dest_image, x+dest_offset_x, y+dest_offset_y,
1782                   XGetPixel(src_image, x+src_offset_x, y+src_offset_y));
1783          }
1784       }
1785       XPutImage(mainDisplay, dest_pixmap, xpmGC, dest_image, 0, 0, 0, 0,
1786             dest_w, dest_h);
1787       XDestroyImage(dest_image);
1788       XDestroyImage(src_image);
1789       XFreePixmap(mainDisplay, pixmap);
1790       *LtX = gpExportClipBBox->ltx;
1791       *LtY = gpExportClipBBox->lty;
1792       *W = gpExportClipBBox->rbx-(*LtX);
1793       *H = gpExportClipBBox->rby-(*LtY);
1794       return dest_pixmap;
1795    }
1796    return pixmap;
1797 }
1798 
ClearAndRedrawDrawWindow()1799 void ClearAndRedrawDrawWindow()
1800 {
1801    if (mainDisplay == NULL || disableRedraw) return;
1802 
1803    XClearWindow(mainDisplay, drawWindow);
1804    if (execAnimatePixmap != None) {
1805       XGCValues values;
1806 
1807       values.foreground = GetDrawingBgPixel(INVALID, INVALID);
1808       values.function = GXcopy;
1809       values.fill_style = FillSolid;
1810       XChangeGC(mainDisplay, drawGC,
1811             GCForeground | GCFunction | GCFillStyle, &values);
1812       XFillRectangle(mainDisplay, execAnimatePixmap, drawGC,
1813             0, 0, execAnimatePixmapW, execAnimatePixmapH);
1814    }
1815    somethingHighLighted = FALSE;
1816    skipCrossHair = TRUE;
1817    RedrawDrawWindow(botObj);
1818    skipCrossHair = FALSE;
1819    ResetDirtyBBoxInfo();
1820    RedrawCurText();
1821    if (!execAnimating) HighLightForward();
1822    RedrawCrossHair();
1823 }
1824 
ClearAndRedrawDrawWindowNoCurT()1825 void ClearAndRedrawDrawWindowNoCurT()
1826    /* use to be ClearAndRedrawDrawWindowDontDrawCurText() */
1827 {
1828    if (mainDisplay == NULL || disableRedraw) return;
1829 
1830    XClearWindow(mainDisplay, drawWindow);
1831    if (execAnimatePixmap != None) {
1832       XGCValues values;
1833 
1834       values.foreground = GetDrawingBgPixel(INVALID, INVALID);
1835       values.function = GXcopy;
1836       values.fill_style = FillSolid;
1837       XChangeGC(mainDisplay, drawGC,
1838             GCForeground | GCFunction | GCFillStyle, &values);
1839       XFillRectangle(mainDisplay, execAnimatePixmap, drawGC,
1840             0, 0, execAnimatePixmapW, execAnimatePixmapH);
1841    }
1842    somethingHighLighted = FALSE;
1843    skipCrossHair = TRUE;
1844    RedrawDrawWindow(botObj);
1845    skipCrossHair = FALSE;
1846    HighLightForward();
1847    RedrawCrossHair();
1848 }
1849 
BeginExecAnimate()1850 int BeginExecAnimate()
1851 {
1852    execAnimating = TRUE;
1853    execAnimateRedraw = TRUE;
1854    RedrawDrawWindow(botObj);
1855 
1856    if (execAnimatePixmap == None) {
1857       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_ALLOC_PIXMAP_OF_SIZE),
1858             execAnimatePixmapW, execAnimatePixmapH);
1859       if (scrollingCanvas == INVALID) {
1860          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1861       } else {
1862          SetStringStatus(gszMsgBox);
1863       }
1864       execAnimatePixmapW = execAnimatePixmapH = 0;
1865       execAnimating = execAnimateRedraw = FALSE;
1866       return FALSE;
1867    }
1868    return TRUE;
1869 }
1870 
EndExecAnimate()1871 void EndExecAnimate()
1872 {
1873    if (execAnimatePixmap != None) {
1874       XFreePixmap(mainDisplay, execAnimatePixmap);
1875    }
1876    if (execAnimateRulerPixmap != None) {
1877       XFreePixmap(mainDisplay, execAnimateRulerPixmap);
1878    }
1879    execAnimatePixmap = execAnimateRulerPixmap = None;
1880    execAnimatePixmapW = execAnimatePixmapH = 0;
1881    execAnimatePixmapDataW = execAnimatePixmapDataH = 0;
1882    execAnimating = execAnimateRedraw = FALSE;
1883 }
1884 
CleanUpDrawingWindow()1885 void CleanUpDrawingWindow()
1886 {
1887    FreeEditAttrInfo(gpEditAttrInEditorAttrInfo);
1888    gpEditAttrInEditorAttrInfo = NULL;
1889 
1890    if (execAnimatePixmap != None) {
1891       Msg(TgLoadString(STID_FORCING_END_ANIMATE));
1892       EndExecAnimate();
1893    }
1894    SetCurChoice(NOTHING);
1895    if (topSel != NULL) {
1896       if (!deserializingFile) HighLightReverse();
1897       RemoveAllSel();
1898    }
1899    if (tgifObj != NULL && tgifObj->fattr != NULL) {
1900       DelAllAttrs(tgifObj->fattr);
1901       tgifObj->fattr = tgifObj->lattr = NULL;
1902    }
1903    DelAllPages();
1904    ResetRotatePivotValidInfo();
1905 }
1906 
1907 static
GetElapseTime(long start_sec,long start_msec,long end_sec,long end_msec)1908 long GetElapseTime(long start_sec, long start_msec, long end_sec, long end_msec)
1909 {
1910    long diff_sec=end_sec-start_sec;
1911    long diff_msec=end_msec-start_msec;
1912 
1913    if (diff_msec < 0) {
1914       diff_sec--;
1915       diff_msec += 1000;
1916    }
1917    return ((diff_sec*1000)+diff_msec);
1918 }
1919 
1920 static
BenchMark()1921 void BenchMark()
1922 {
1923    static int count=0;
1924    int need_to_check_auto_exec=FALSE, i=0;
1925 
1926    while (XPending(mainDisplay)) {
1927       i++;
1928       TryProcessAnXEvent(&need_to_check_auto_exec);
1929    }
1930    /* debug, do not translate */
1931    fprintf(stderr, "%1d BenchMark Ready (%1d events processed)!\n", count, i);
1932    if (count++ < 3) {
1933       SendCommandToSelf(CMDID_BENCHMARK, INVALID);
1934    } else {
1935       long start_sec=0L, start_msec=0L, end_sec=0L, end_msec=0L;
1936       long elapsed_msec=0L;
1937       int x=0, y=0, z=0, w=64, x_end=(min(drawWinW,drawWinH)-64), total=1000000;
1938       XRectangle rectangles[1000];
1939 
1940       XSetForeground(mainDisplay, defaultGC, colorPixels[y%maxColors]);
1941       UtilGetMilliSecTime(&start_sec, &start_msec);
1942       for (i=0; i < total; i++) {
1943          XDrawRectangle(mainDisplay, drawWindow, defaultGC, x+y, x, w, w);
1944          if (x++ >= x_end) {
1945             x=0;
1946             if (y++ >= x_end) {
1947                y=0;
1948                XSetForeground(mainDisplay, defaultGC,
1949                      colorPixels[(++z)%maxColors]);
1950             }
1951          }
1952       }
1953       XSetForeground(mainDisplay, defaultGC, myFgPixel);
1954       UtilGetMilliSecTime(&end_sec, &end_msec);
1955       elapsed_msec = GetElapseTime(start_sec, start_msec, end_sec, end_msec);
1956       if (elapsed_msec > 0) {
1957          double avg=((double)total)*((double)1000)/((double)elapsed_msec);
1958 
1959          /* debug, do not translate */
1960          fprintf(stderr, "Took %ld ms to draw %1d rectangles (%.2f %s).\n",
1961                elapsed_msec, total, avg, "rectangles per second");
1962       }
1963       x = y = z = 0;
1964       XSetForeground(mainDisplay, defaultGC, colorPixels[y%maxColors]);
1965       UtilGetMilliSecTime(&start_sec, &start_msec);
1966       for (i=0; i < 1000; i++) {
1967          rectangles[i].width = rectangles[i].height = w;
1968       }
1969       w = 0;
1970       for (i=0; i < total; i++) {
1971          if (w < 1000) {
1972             rectangles[w].x = x+y;
1973             rectangles[w].y = x;
1974             w++;
1975          } else {
1976             XDrawRectangles(mainDisplay, drawWindow, defaultGC, rectangles,
1977                   1000);
1978             w = 0;
1979          }
1980          if (x++ >= x_end) {
1981             x=0;
1982             if (y++ >= x_end) {
1983                y=0;
1984                XSetForeground(mainDisplay, defaultGC,
1985                      colorPixels[(++z)%maxColors]);
1986             }
1987          }
1988       }
1989       XSetForeground(mainDisplay, defaultGC, myFgPixel);
1990       UtilGetMilliSecTime(&end_sec, &end_msec);
1991       elapsed_msec = GetElapseTime(start_sec, start_msec, end_sec, end_msec);
1992       if (elapsed_msec > 0) {
1993          double avg=((double)total)*((double)1000)/((double)elapsed_msec);
1994 
1995          /* debug, do not translate */
1996          fprintf(stderr, "Took %ld ms to draw %1d rectangles (%.2f %s).\n",
1997                elapsed_msec, total, avg, "rectangles per second");
1998       }
1999    }
2000 }
2001 
2002 static
ToggleShowChat()2003 void ToggleShowChat()
2004 {
2005    noChatWindow = !noChatWindow;
2006    if (noChatWindow) {
2007       XUnmapWindow(mainDisplay, chatWindow);
2008    } else {
2009       XMapWindow(mainDisplay, chatWindow);
2010    }
2011    Reconfigure(TRUE);
2012 }
2013 
2014 static
DoShortCut(key_ev,name,key_sym,state,args)2015 int DoShortCut(key_ev, name, key_sym, state, args)
2016    XKeyEvent *key_ev;
2017    char *name, *args;
2018    KeySym key_sym;
2019    unsigned int state;
2020    /* returns INVALID if the key event can be caught by other windows */
2021 {
2022    if (gnDisableShortcuts) {
2023       sprintf(gszMsgBox, TgLoadString(STID_TOOL_NOT_FINISH_WITH_EXEC),
2024             TOOL_NAME);
2025       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2026       return BAD;
2027    }
2028    if ((state & ControlMask) && (!(state & METAMASK))) {
2029       int rc=BAD;
2030 
2031       switch (key_sym&0xff) {
2032       case 'a': /*^a*/ SelAllObj(TRUE, FALSE); break;
2033       case 'b': /*^b*/ BackProc(); break;
2034       case 'c': /*^c*/ CopyToCutBuffer(); break;
2035       case 'd': /*^d*/ DupSelObj(); break;
2036       case 'e': /*^e*/ PushCurChoice(); break;
2037       case 'f': /*^f*/ FrontProc(); break;
2038       case 'g': /*^g*/ GroupSelObj(TRUE, TRUE, TRUE); break;
2039       case 'h': /*^h*/ return(INVALID);
2040       case 'i': /*^i*/ Instantiate(); break;
2041       case 'j': /*^j*/ return(INVALID);
2042       case 'k': /*^k*/ PopIcon(); break;
2043       case 'l': /*^l*/ AlignSelObjs(); break;
2044       case 'm': /*^m*/ return(INVALID);
2045       case 'n': /*^n*/ NewProc(); break;
2046       case 'o': /*^o*/
2047          OpenProc((args==NULL || *args=='\0') ? NULL : args);
2048          break;
2049       case 'p': /*^p*/ Dump(""); break;
2050       case 'q': /*^q*/ if ((rc=QuitProc())==INVALID) return BAD; return rc;
2051       case 'r': /*^r*/ ClearAndRedrawDrawWindow(); break;
2052       case 's': /*^s*/ SaveFile(); break;
2053       case 't': /*^t*/ AlignSelToGrid(); break;
2054       case 'u': /*^u*/ UngroupSelObj(TRUE, TRUE); break;
2055       case 'v': /*^v*/ PasteFromCutBuffer(); break;
2056       case 'w': /*^w*/ SetCurChoice(DRAWTEXT); break;
2057       case 'x': /*^x*/ CutToCutBuffer(); break;
2058       case 'y': /*^y*/ RedoCmd(); break;
2059       case 'z': /*^z*/ UndoCmd(); break;
2060       case ',': /*^,*/ ScrollLeft(NULL); break;
2061       case '.': /*^.*/ ScrollRight(NULL); break;
2062       case '-': /*^-*/ PrintWithCommand(""); break;
2063       case '1': /*^1*/ ScreenCapture(); break;
2064       case '2': /*^2*/ FullScreenCapture(); break;
2065 
2066       case ' ':
2067       case '\\':
2068          if (curChoice == DRAWTEXT && textCursorShown &&
2069                (canvasFontDoubleByte || gstCopyUTF8Info.double_byte_valid)) {
2070             if (textHighlight) {
2071                curTextModified = TRUE;
2072                DelSelText();
2073             }
2074             if (!canvasFontDoubleByte && gstCopyUTF8Info.double_byte_valid) {
2075                SwitchToDoubleByteFont(&gstCopyUTF8Info.double_byte_seg);
2076             }
2077             if (tgIMActiveOnCntrlSpace(mainDisplay, drawWindow)) {
2078                if (tgIMHandleCntrlSpace(mainDisplay, drawWindow)) {
2079                   if (gnInputMethod != TGIM_NONE && gnOverTheSpot) {
2080                      if (!tgIMTellCursorPosition(mainDisplay, drawWindow,
2081                            textCurX, textCurBaselineY+curStrBlock->seg->des)) {
2082                      }
2083                   }
2084                }
2085             } else {
2086                return INVALID;
2087             }
2088          }
2089          break;
2090       default: return INVALID;
2091       }
2092    } else if ((state & METAMASK) && (!(state & ControlMask))) {
2093       switch (key_sym&0xff) {
2094       case 'a': /*#a*/ AddAttrs(); break;
2095       case 'b': /*#b*/ return ProbeProc();
2096       case 'c': /*#c*/ RotateCounter(); break;
2097       case 'd': /*#d*/ DecGrid(); break;
2098       case 'e': /*#e*/ AnimateSel(); break;
2099       case 'f': /*#f*/ FlashSelColor(); break;
2100       case 'g': /*#f*/ ToggleGridShown(); break;
2101       case 'h': /*#h*/ FlipHorizontal(); break;
2102       case 'i': /*#i*/ IncGrid(); break;
2103       case 'j': /*#j*/ HideAllAttrNames(); break;
2104       case 'k': /*#k*/ SetCurChoice(NOTHING); break;
2105       case 'l': /*#l*/ DistrSelObjs(); break;
2106       case 'm': /*#m*/ MoveAttr(); break;
2107       case 'n': /*#n*/ ShowAllAttrNames(); break;
2108       case 'o': /*#o*/ ZoomOut(); break;
2109       case 'p': /*#p*/ ImportFile(); break;
2110       case 'q': /*#q*/ SetCurChoice(DRAWPOLY); break;
2111       case 'r': /*#r*/ SetCurChoice(DRAWBOX); break;
2112       case 's': /*#s*/ return SolveProc();
2113       case 't': /*#t*/ DetachAttrs(); break;
2114       case 'u': /*#u*/ return AnimateProc(); break;
2115       case 'v': /*#v*/ FlipVertical(); break;
2116       case 'w': /*#w*/ RotateClockWise(); break;
2117       case 'x': /*#x*/ return EscapeProc();
2118       case 'y': /*#y*/ return SimulateProc();
2119       case 'z': /*#z*/ ZoomIn(); break;
2120       case '9': /*#9*/ MakePreciseArc(); break;
2121       case '0': /*#0*/ UpdateSelObjs(); break;
2122       case ',': /*#,*/ ScrollUp(NULL); break;
2123       case '.': /*#.*/ ScrollDown(NULL); break;
2124       case '-': /*#-*/ ShowAllAttrs(); break;
2125       case '{': /*#{*/ AlignObjsTop(); break;
2126       case '+': /*#+*/ AlignObjsMiddle(); break;
2127       case '}': /*#}*/ AlignObjsBottom(); break;
2128       case '[': /*#[*/ AlignObjsLeft(); break;
2129       case '=': /*#=*/ AlignObjsCenter(); break;
2130       case ']': /*#]*/ AlignObjsRight(); break;
2131       case '"': /*#"*/ MakeRegularPolygon(); break;
2132       case '%': /*#%*/ SetPrintReduction(); break;
2133       case ':': /*#:*/ DefaultZoom(); break;
2134       case '`': /*#`*/ ZoomWayOut(); break;
2135       case '~': /*#~*/ SaveNewFile(TRUE, NULL); break;
2136       case ';': /*#;*/ CutMaps(); break;
2137       case '_': /*#_*/ AbutHorizontal(); break;
2138       case '|': /*#|*/ AbutVertical(); break;
2139       case '#': /*##*/
2140          BreakUpText((args==NULL || *args=='\0') ? NULL : args);
2141          break;
2142       case '^': /*#^*/ ScrollToOrigin(); break;
2143       case '@': /*#@*/ ToggleMoveMode(); break;
2144       case '$': /*#$*/ SetCurChoice(VERTEXMODE); break;
2145       case '&': /*#&*/ AlignSelToPage(); break;
2146       case '*': /*#**/ ChangeDomain(); break;
2147       case '(': /*#(*/
2148          ImportEPSFile(FALSE, (args==NULL || *args=='\0') ? NULL : args);
2149          break;
2150       case ')': /*#)*/ ScaleAllSelObj(); break;
2151       case '<': /*#<*/ LockSelObj(); break;
2152       case '>': /*#>*/ UnlockSelObj(); break;
2153       default: return INVALID;
2154       }
2155    } else if ((state & METAMASK) && (state & ControlMask)) {
2156       switch (key_sym&0xff) {
2157       case 'a': /*^#a*/ AddPoint(); break;
2158       case 'b': /*^#b*/ ChangeFontStyle(STYLE_BR); break;
2159       case 'c': /*^#c*/ ChangeFontJust(JUST_C); break;
2160       case 'd': /*^#d*/ DeletePoint(); break;
2161       case 'e': /*^#e*/ SetCurChoice(DRAWRCBOX); break;
2162       case 'f': /*^#f*/ InvertXBitmaps(); break;
2163       case 'g': /*^#g*/ ToggleSnapOn(); break;
2164       case 'h': /*^#h*/ HideAllAttrs(); break;
2165       case 'i': /*^#i*/ MakeIconic(NULL, TRUE); break;
2166       case 'j': /*^#j*/ UnMakeIconic(); break;
2167       case 'k': /*^#k*/ ToggleColorPostScript(); break;
2168       case 'l': /*^#l*/ ChangeFontJust(JUST_L); break;
2169       case 'm': /*^#m*/ MakeSymbolic(); break;
2170       case 'n': /*^#n*/ UnMakeSymbolic(); break;
2171       case 'o': /*^#o*/ ChangeFontStyle(STYLE_NR); break;
2172       case 'p': /*^#p*/ ChangeFontStyle(STYLE_BI); break;
2173       case 'q': /*^#q*/ SetCurChoice(DRAWPOLYGON); break;
2174       case 'r': /*^#r*/ ChangeFontJust(JUST_R); break;
2175       case 's': /*^#s*/
2176          SaveNewFile(FALSE, (args==NULL || *args=='\0') ? NULL : args);
2177          break;
2178       case 't': /*^#t*/ ChangeFontStyle(STYLE_NI); break;
2179       case 'u': /*^#u*/ UpdateSymbols(); break;
2180       case 'v': /*^#v*/ SetCurChoice(DRAWCORNEROVAL); break;
2181       case 'w': /*^#w*/ ToggleAllSelLineType(); break;
2182       case 'x': /*^#x*/ ToggleWhereToPrint(); break;
2183       case 'y': /*^#y*/ PushIcon(); break;
2184       case 'Y': /*^#Y*/ PasteCompoundText(); break;
2185       case 'z': /*^#z*/ SetCurChoice(DRAWARC); break;
2186       case '.': /*^#.*/ ImportXBitmapFile(); break;
2187       case ',': /*^#,*/ ImportXPixmapFile(); break;
2188       case '-': /*^#-*/ ToggleGridSystem(); break;
2189       case '=': /*^#=*/ FindAgain(); break;
2190       case '5': /*^#5*/ InsertRightSubscript(); break;
2191       case '6': /*^#6*/ InsertRightSuperscript(); break;
2192       case '7': /*^#7*/ ToggleEqAttrShown(); break;
2193       case '8': /*^#8*/
2194          if (inSlideShow) {
2195             LeaveSlideShow();
2196          } else {
2197             EnterSlideShow();
2198          }
2199          break;
2200       case '9': /*^#9*/ FindNoCase(); break;
2201       case '0': /*^#0*/ FindCaseSensitive(); break;
2202       default: return INVALID;
2203       }
2204    } else if (name != NULL && key_sym == '\0' && state == 0) {
2205       XButtonEvent button_ev;
2206 
2207       button_ev.state = ShiftMask;
2208 
2209       /* do not translate -- program constants */
2210       if (strcmp(name, "Delete()") == 0) {
2211          if (curChoice == DRAWTEXT && textCursorShown) {
2212             DelSelText();
2213          } else {
2214             DelAllSelObj();
2215          }
2216       } else if (strcmp(name, "DrawCornerOval()") == 0) {
2217          SetCurChoice(DRAWCORNEROVAL);
2218       } else if (strcmp(name, "DrawCenterOval()") == 0) {
2219          SetCurChoice(DRAWCENTEROVAL);
2220       } else if (strcmp(name, "DrawEdgeOval()") == 0) {
2221          SetCurChoice(DRAWEDGECIRCLE);
2222       } else if (strcmp(name, "DrawEdgeArc()") == 0) {
2223          SetCurChoice(DRAWEDGEARC);
2224       } else if (strcmp(name, "ScrollPageUp()") == 0) {
2225          ScrollUp(&button_ev);
2226       } else if (strcmp(name, "ScrollPageDown()") == 0) {
2227          ScrollDown(&button_ev);
2228       } else if (strcmp(name, "ScrollPageRight()") == 0) {
2229          ScrollRight(&button_ev);
2230       } else if (strcmp(name, "ScrollPageLeft()") == 0) {
2231          ScrollLeft(&button_ev);
2232       } else if (strcmp(name, "FlushUndoBuffer()") == 0) {
2233          FlushUndoBuffer();
2234       } else if (strcmp(name, "PrintMsgBuffer()") == 0) {
2235          PrintMsgBuffer();
2236       } else if (strcmp(name, "SaveOrigin()") == 0) {
2237          SaveOrigin();
2238       } else if (strcmp(name, "RestoreImageWH()") == 0) {
2239          RestoreImageWH();
2240       } else if (strcmp(name, "UpdateEPS()") == 0) {
2241          UpdateEPS();
2242       } else if (strcmp(name, "ToggleMapShown()") == 0) {
2243          ToggleMapShown();
2244       } else if (strcmp(name, "ToggleUseGrayScale()") == 0) {
2245          ToggleUseGray();
2246       } else if (strcmp(name, "FreeHandMode()") == 0) {
2247          SetCurChoice(FREEHAND);
2248       } else if (strcmp(name, "SaveSymInLibrary()") == 0) {
2249          SaveSymInLibrary();
2250       } else if (strcmp(name, "CenterAnEndPoint()") == 0 ||
2251             strcmp(name, "CenterAVertex()") == 0) {
2252          CenterAnEndPoint();
2253       } else if (strcmp(name, "NextPage()") == 0) {
2254          NextPage();
2255       } else if (strcmp(name, "PrevPage()") == 0) {
2256          PrevPage();
2257       } else if (strcmp(name, "NamePages()") == 0) {
2258          NamePages();
2259       } else if (strcmp(name, "GotoPage()") == 0) {
2260          GotoPage((args==NULL || *args=='\0') ? NULL : args);
2261       } else if (strcmp(name, "AddPageBefore()") == 0) {
2262          AddPageBefore();
2263       } else if (strcmp(name, "AddPageAfter()") == 0) {
2264          AddPageAfter();
2265       } else if (strcmp(name, "DeleteCurPage()") == 0) {
2266          DeleteCurPage();
2267       } else if (strcmp(name, "TogglePageLineShown()") == 0) {
2268          TogglePageLineShown();
2269       } else if (strcmp(name, "SpecifyDrawingSize()") == 0) {
2270          SpecifyDrawingSize();
2271       } else if (strcmp(name, "PrintOnePage()") == 0) {
2272          PrintOnePage();
2273       } else if (strcmp(name, "ToggleNamedAttrShown()") == 0) {
2274          if (args != NULL) {
2275             ToggleNamedAttrShown(args);
2276          }
2277       } else if (strcmp(name, "AttachFileAttrs()") == 0) {
2278          AddFileAttrs();
2279       } else if (strcmp(name, "DetachFileAttrs()") == 0) {
2280          DetachFileAttrs();
2281       } else if (strcmp(name, "EditFileAttrs()") == 0) {
2282          EditFileAttrs();
2283       } else if (strcmp(name, "PrintSelectedObjs()") == 0) {
2284          PrintSelectedObjs();
2285       } else if (strcmp(name, "InputPolyPts()") == 0) {
2286          InputPolyPts();
2287       } else if (strcmp(name, "InputPolygonPts()") == 0) {
2288          InputPolygonPts();
2289       } else if (strcmp(name, "EditAttrs()") == 0) {
2290          EditAttrs();
2291       } else if (strcmp(name, "ConvertIntSpline()") == 0) {
2292          ConvertIntSpline();
2293       } else if (strcmp(name, "PasteFromFile()") == 0) {
2294          PasteFromFile();
2295       } else if (strcmp(name, "ToggleShowMeasurement()") == 0) {
2296          ToggleShowMeasurement();
2297       } else if (strcmp(name, "SetMeasureUnit()") == 0) {
2298          SetMeasureUnit();
2299       } else if (strcmp(name, "Cut()") == 0) {
2300          CutToCutBuffer();
2301       } else if (strcmp(name, "ToggleSmoothHinge()") == 0) {
2302          ToggleSmoothHinge();
2303       } else if (strcmp(name, "ToggleShowMenubar()") == 0) {
2304          ToggleShowMenubar();
2305       } else if (strcmp(name, "ToggleShowStatus()") == 0) {
2306          ToggleShowStatus();
2307       } else if (strcmp(name, "BrowseXBitmap()") == 0) {
2308          BrowseXBitmap();
2309       } else if (strcmp(name, "BrowseXPixmap()") == 0) {
2310          BrowseXPixmap();
2311       } else if (strcmp(name, "SpecifyPaperSize()") == 0) {
2312          SpecifyPaperSize();
2313       } else if (strcmp(name, "ToggleOneMotionSelMove()") == 0) {
2314          ToggleOneMotionSelectMove();
2315       } else if (strcmp(name, "GoBack()") == 0) {
2316          NavigateBack();
2317       } else if (strcmp(name, "GoForward()") == 0) {
2318          NavigateForward();
2319       } else if (strcmp(name, "RefreshCurrent()") == 0) {
2320          NavigateRefresh();
2321       } else if (strcmp(name, "HotList()") == 0) {
2322          NavigateHotList();
2323       } else if (strcmp(name, "AddCurrentToHotList()") == 0) {
2324          NavigateAddToHotList();
2325       } else if (strcmp(name, "SessionHistory()") == 0) {
2326          NavigateSessionHistory();
2327       } else if (strcmp(name, "ToggleHyperSpace()") == 0) {
2328          ToggleHyperSpace (FALSE);
2329       } else if (strcmp(name, "EmbedEPSFile()") == 0) {
2330          ImportEPSFile(TRUE, NULL);
2331       } else if (strcmp(name, "SetSelLineWidth()") == 0) {
2332          SetSelLineWidth(NULL);
2333       } else if (strcmp(name, "AddColor()") == 0) {
2334          AddColor();
2335       } else if (strcmp(name, "ImportAttrs()") == 0) {
2336          ImportAttrs();
2337       } else if (strcmp(name, "ExportAttrs()") == 0) {
2338          ExportAttrs();
2339       } else if (strcmp(name, "MergeWithTable()") == 0) {
2340          MergeWithTable();
2341       } else if (strcmp(name, "ExportToTable()") == 0) {
2342          ExportToTable();
2343       } else if (strcmp(name, "DeletePages()") == 0) {
2344          DeletePages();
2345       } else if (strcmp(name, "PrintOneFilePerPage()") == 0) {
2346          PrintOneFilePerPage();
2347       } else if (strcmp(name, "ImportGIFFile()") == 0) {
2348          ImportGIFFile();
2349       } else if (strcmp(name, "ImportPNGFile()") == 0) {
2350          ImportPNGFile();
2351       } else if (strcmp(name, "ImportJPEGFile()") == 0) {
2352          ImportJPEGFile(TRUE, NULL);
2353       } else if (strcmp(name, "ImportPBMFile()") == 0) {
2354          ImportPBMFile();
2355       } else if (strcmp(name, "ImportPGMFile()") == 0) {
2356          ImportPGMFile();
2357       } else if (strcmp(name, "ImportPPMFile()") == 0) {
2358          ImportPPMFile();
2359       } else if (strcmp(name, "SetExportPixelTrim()") == 0) {
2360          SetExportPixelTrim(FALSE);
2361       } else if (strcmp(name, "ToggleColorLayers()") == 0) {
2362          ToggleColorLayers();
2363       } else if (strcmp(name, "ToggleStretchableText()") == 0) {
2364          ToggleStretchableText();
2365       } else if (strcmp(name, "BreakUpBit/Pixmap()") == 0) {
2366          BreakUpMaps();
2367       } else if (strcmp(name, "LayoutOnArc()") == 0) {
2368          LayoutOnArc();
2369       } else if (strcmp(name, "PreciseRotate()") == 0) {
2370          PreciseRotate();
2371       } else if (strcmp(name, "JoinPoly()") == 0) {
2372          JoinPoly();
2373       } else if (strcmp(name, "CutPoly()") == 0) {
2374          CutPoly();
2375       } else if (strcmp(name, "GetBoundingBox()") == 0) {
2376          GetBoundingBox();
2377       } else if (strcmp(name, "SetTemplate()") == 0) {
2378          SetTemplate();
2379       } else if (strcmp(name, "MakeGray()") == 0) {
2380          MakeGray();
2381       } else if (strcmp(name, "InvertColor()") == 0) {
2382          InvertColor();
2383       } else if (strcmp(name, "InterpolateColor()") == 0) {
2384          InterpolateColor();
2385       } else if (strcmp(name, "BrightenDarken()") == 0) {
2386          BrightenDarken();
2387       } else if (strcmp(name, "ChangeSaturation()") == 0) {
2388          ChangeSaturation();
2389       } else if (strcmp(name, "ChangeHue()") == 0) {
2390          ChangeHue();
2391       } else if (strcmp(name, "ContrastEnhance()") == 0) {
2392          ContrastEnhance();
2393       } else if (strcmp(name, "ColorBalance()") == 0) {
2394          ColorBalance();
2395       } else if (strcmp(name, "Gamma()") == 0) {
2396          Gamma(NULL);
2397       } else if (strcmp(name, "EdgeDetect()") == 0) {
2398          EdgeDetect();
2399       } else if (strcmp(name, "Emboss()") == 0) {
2400          Emboss();
2401       } else if (strcmp(name, "ReduceColors()") == 0) {
2402          ReduceColors();
2403       } else if (strcmp(name, "ReduceToPixmapColors()") == 0) {
2404          ReduceToPixmapColors();
2405       } else if (strcmp(name, "SetDefaultColorLevels()") == 0) {
2406          SetDefaultColorLevels();
2407       } else if (strcmp(name, "ReduceToDefaultColors()") == 0) {
2408          ReduceToDefaultColors();
2409       } else if (strcmp(name, "DefaultErrorDiffuse()") == 0) {
2410          DefaultErrorDiffuse();
2411       } else if (strcmp(name, "Spread()") == 0) {
2412          Spread();
2413       } else if (strcmp(name, "Sharpen()") == 0) {
2414          Sharpen();
2415       } else if (strcmp(name, "Blur3()") == 0) {
2416          Blur3();
2417       } else if (strcmp(name, "Blur5()") == 0) {
2418          Blur5();
2419       } else if (strcmp(name, "Blur7()") == 0) {
2420          Blur7();
2421       } else if (strcmp(name, "RunBggen()") == 0) {
2422          RunBggen();
2423       } else if (strcmp(name, "CircularBggen()") == 0) {
2424          CircularBggen();
2425       } else if (strcmp(name, "SimpleRectBggen()") == 0) {
2426          SimpleRectBggen();
2427       } else if (strcmp(name, "RegenerateImage()") == 0) {
2428          RegenerateImage();
2429       } else if (strcmp(name, "CropImage()") == 0) {
2430          CropImage();
2431       } else if (strcmp(name, "GetColor()") == 0) {
2432          GetColor();
2433       } else if (strcmp(name, "ReplaceColor()") == 0) {
2434          ReplaceColor();
2435       } else if (strcmp(name, "FloodFill()") == 0) {
2436          FloodFill();
2437       } else if (strcmp(name, "CreateContour()") == 0) {
2438          CreateContour();
2439       } else if (strcmp(name, "Subtract()") == 0) {
2440          Subtract();
2441       } else if (strcmp(name, "AlphaCombine()") == 0) {
2442          AlphaCombine();
2443       } else if (strcmp(name, "XorColors()") == 0) {
2444          XorColors();
2445       } else if (strcmp(name, "ImportOtherFile()") == 0) {
2446          ImportOtherFile();
2447       } else if (strcmp(name, "ImportOtherFileType()") == 0) {
2448          if (args != NULL) {
2449             ImportOtherFileType(args);
2450          }
2451       } else if (strcmp(name, "BrowseOther()") == 0) {
2452          BrowseOther();
2453       } else if (strcmp(name, "BrowseOtherType()") == 0) {
2454          if (args != NULL) {
2455             BrowseOtherType(args);
2456          }
2457       } else if (strcmp(name, "ToggleShowCrossHair()") == 0) {
2458          ToggleShowCrossHair();
2459       } else if (strcmp(name, "SetShapeShadow()") == 0) {
2460          SetShapeShadow();
2461       } else if (strcmp(name, "NoTransform()") == 0) {
2462          NoTransform();
2463       } else if (strcmp(name, "About()") == 0) {
2464          About();
2465       } else if (strcmp(name, "Copyright()") == 0) {
2466          Copyright();
2467       } else if (strcmp(name, "SetSelFontSize()") == 0) {
2468          SetSelFontSize(NULL);
2469       } else if (strcmp(name, "ZoomInAtCursor()") == 0) {
2470          if (key_ev != NULL) {
2471             int abs_x=ABS_X(key_ev->x);
2472             int abs_y=ABS_Y(key_ev->y);
2473 
2474             ZoomInAtCursor(abs_x, abs_y);
2475          }
2476       } else if (strcmp(name, "CenterAtCursor()") == 0) {
2477          if (key_ev != NULL) {
2478             int abs_x=ABS_X(key_ev->x);
2479             int abs_y=ABS_Y(key_ev->y);
2480 
2481             CenterAtCursor(abs_x, abs_y);
2482          }
2483       } else if (strcmp(name, "SetEditTextSize()") == 0) {
2484          SetEditTextSize();
2485       } else if (strcmp(name, "SetTextRotation()") == 0) {
2486          SetTextRotation(NULL);
2487       } else if (strcmp(name, "SetRotationIncrement()") == 0) {
2488          SetRotationIncrement(NULL);
2489       } else if (strcmp(name, "CurrentVersionInfo()") == 0 ||
2490             strcmp(name, "LatestReleaseInfo()") == 0) {
2491          LatestReleaseInfo();
2492       } else if (strcmp(name, "VectorWarp()") == 0) {
2493          VectorWarp();
2494       } else if (strcmp(name, "ConnectPins()") == 0) {
2495          ConnectPins();
2496       } else if (strcmp(name, "PasteCompoundText()") == 0) {
2497          PasteCompoundText();
2498       } else if (strcmp(name, "CopyProperties()") == 0) {
2499          CopyProperties(TRUE);
2500       } else if (strcmp(name, "SaveProperties()") == 0) {
2501          SaveProperties();
2502       } else if (strcmp(name, "PasteProperties()") == 0) {
2503          PasteProperties(TRUE);
2504       } else if (strcmp(name, "RestoreProperties()") == 0) {
2505          RestoreProperties();
2506       } else if (strcmp(name, "RotateShearMode()") == 0) {
2507          SetCurChoice(ROTATEMODE);
2508       } else if (strcmp(name, "ChangeAllSelFill()") == 0) {
2509          if (args != NULL) {
2510             ChangeAllSelFill(atoi(args), TRUE);
2511          }
2512       } else if (strcmp(name, "ChangeAllSelPen()") == 0) {
2513          if (args != NULL) {
2514             ChangeAllSelPen(atoi(args), TRUE);
2515          }
2516       } else if (strcmp(name, "ChangeAllSelLineWidth()") == 0) {
2517          if (args != NULL) {
2518             ChangeAllSelLineWidth(atoi(args), TRUE);
2519          }
2520       } else if (strcmp(name, "ChangeAllSelLineStyle()") == 0) {
2521          if (args != NULL) {
2522             ChangeAllSelLineStyle(atoi(args), TRUE);
2523          }
2524       } else if (strcmp(name, "ChangeAllSelLineType()") == 0) {
2525          if (args != NULL) {
2526             ChangeAllSelLineType(atoi(args), TRUE);
2527          }
2528       } else if (strcmp(name, "ChangeAllSelLineDash()") == 0) {
2529          if (args != NULL) {
2530             ChangeAllSelLineDash(atoi(args), TRUE);
2531          }
2532       } else if (strcmp(name, "ChangeAllSelFont()") == 0) {
2533          if (args != NULL) {
2534             ChangeFont(atoi(args), FALSE);
2535          }
2536       } else if (strcmp(name, "ChangeAllSelFontSize()") == 0) {
2537          if (args != NULL) {
2538             ChangeFontSize(atoi(args));
2539          }
2540       } else if (strcmp(name, "ChangeAllSelFontStyle()") == 0) {
2541          if (args != NULL) {
2542             ChangeFontStyle(atoi(args));
2543          }
2544       } else if (strcmp(name, "ChangeAllSelFontJust()") == 0) {
2545          if (args != NULL) {
2546             ChangeFontJust(atoi(args)-MAXFONTSTYLES-1);
2547          }
2548       } else if (strcmp(name, "ChangeAllSelColor()") == 0) {
2549          if (args != NULL) {
2550             ChangeAllSelColor(atoi(args), TRUE);
2551          }
2552       } else if (strcmp(name, "LanscapeMode()") == 0) {
2553          ChangePageStyle(LANDSCAPE);
2554       } else if (strcmp(name, "PortraitMode()") == 0) {
2555          ChangePageStyle(PORTRAIT);
2556       } else if (strcmp(name, "SetWhereToPrint()") == 0) {
2557          if (args != NULL) {
2558             SetWhereToPrint(atoi(args));
2559          }
2560       } else if (strcmp(name, "SetHoriAlign()") == 0) {
2561          if (args != NULL) {
2562             HoriAlignSubMenu(atoi(args));
2563          }
2564       } else if (strcmp(name, "SetVertAlign()") == 0) {
2565          if (args != NULL) {
2566             VertAlignSubMenu(atoi(args));
2567          }
2568       } else if (strcmp(name, "SetMoveMode()") == 0) {
2569          if (args != NULL) {
2570             MoveModeSubMenu(atoi(args));
2571          }
2572       } else if (strcmp(name, "SetStretchTextMode()") == 0) {
2573          if (args != NULL) {
2574             StretchableTextModeSubMenu(atoi(args));
2575          }
2576       } else if (strcmp(name, "CreateShape()") == 0) {
2577          if (args != NULL) {
2578             ShapeSubMenu(atoi(args));
2579          }
2580       } else if (strcmp(name, "SetPageLayoutMode()") == 0) {
2581          if (args != NULL) {
2582             PageLayoutSubMenu(atoi(args));
2583          }
2584       } else if (strcmp(name, "SetTransPatMode()") == 0) {
2585          if (args != NULL) {
2586             ChangeAllSelTransPat(atoi(args), TRUE);
2587          }
2588       } else if (strcmp(name, "ToggleShowMode()") == 0) {
2589          ToggleShowMode();
2590       } else if (strcmp(name, "SetSlideShowBorderColor()") == 0) {
2591          SetSlideShowBorderColor();
2592       } else if (strcmp(name, "SetSlideShowWindowOffsets()") == 0) {
2593          SetSlideShowWindowOffsets();
2594       } else if (strcmp(name, "ExportXPixmapDeckToGIF()") == 0) {
2595          ExportXPixmapDeckToGIF();
2596       } else if (strcmp(name, "ImportGIFToXPixmapDeck()") == 0) {
2597          ImportGIFToXPixmapDeck();
2598       } else if (strcmp(name, "InsertThinSpace()") == 0) {
2599          InsertThinSpace();
2600       } else if (strcmp(name, "InsertVerticalOffset()") == 0) {
2601          InsertVerticalOffset();
2602       } else if (strcmp(name, "RemoveVerticalOffset()") == 0) {
2603          RemoveVerticalOffset();
2604       } else if (strcmp(name, "InsertLeftSuperscript()") == 0) {
2605          InsertLeftSuperscript();
2606       } else if (strcmp(name, "InsertLeftSubscript()") == 0) {
2607          InsertLeftSubscript();
2608       } else if (strcmp(name, "InsertCenterSuperscript()") == 0) {
2609          InsertCenterSuperscript();
2610       } else if (strcmp(name, "InsertCenterSubscript()") == 0) {
2611          InsertCenterSubscript();
2612       } else if (strcmp(name, "SetScriptFraction()") == 0) {
2613          SetScriptFraction();
2614       } else if (strcmp(name, "FakeUserAgent()") == 0) {
2615          if (args != NULL) {
2616             FakeUserAgent(args);
2617          }
2618       } else if (strcmp(name, "FakeReferer()") == 0) {
2619          if (args != NULL) {
2620             FakeReferer(args);
2621          }
2622       } else if (strcmp(name, "ToggleKeepAlive()") == 0) {
2623          ToggleKeepAlive();
2624       } else if (strcmp(name, "SizeToWidest()") == 0) {
2625          SizeToWidest();
2626       } else if (strcmp(name, "SizeToNarrowest()") == 0) {
2627          SizeToNarrowest();
2628       } else if (strcmp(name, "SizeToTallest()") == 0) {
2629          SizeToTallest();
2630       } else if (strcmp(name, "SizeToShortest()") == 0) {
2631          SizeToShortest();
2632       } else if (strcmp(name, "SizeToGivenWidthHeight()") == 0) {
2633          SizeToGivenWidthHeight();
2634       } else if (strcmp(name, "SizeToGivenWidth()") == 0) {
2635          SizeToGivenWidth();
2636       } else if (strcmp(name, "SizeToGivenHeight()") == 0) {
2637          SizeToGivenHeight();
2638       } else if (strcmp(name, "ExecCmdsFromFile()") == 0) {
2639          if (args != NULL) {
2640             ExecCmdsFromFile(args);
2641          }
2642       } else if (strcmp(name, "StartExecCmdsFromFile()") == 0) {
2643          StartExecCmdsFromFile();
2644       } else if (strcmp(name, "CopyPlainTextAsObject()") == 0) {
2645          CopyPlainTextAsObject();
2646       } else if (strcmp(name, "SetTextFillPatternColor()") == 0) {
2647          SetTextFillPatternColor();
2648       } else if (strcmp(name, "AlignDirect()") == 0) {
2649          if (args != NULL) {
2650             AlignDirect(atoi(args));
2651          }
2652       } else if (strcmp(name, "DistributeDirect()") == 0) {
2653          if (args != NULL) {
2654             DistributeDirect(atoi(args));
2655          }
2656       } else if (strcmp(name, "ToggleVisibleGridInSlideShow()") == 0) {
2657          ToggleVisibleGridInSlideShow();
2658       } else if (strcmp(name, "ChangeScrollMode()") == 0) {
2659          if (args != NULL) {
2660             ChangeScrollMode(atoi(args));
2661          }
2662       } else if (strcmp(name, "SetAltEditTextBgColor()") == 0) {
2663          SetAltEditTextBgColor();
2664       } else if (strcmp(name, "SetAltEditTextHighlightColor()") == 0) {
2665          SetAltEditTextHighlightColor();
2666       } else if (strcmp(name, "ToggleAltEditTextBgColor()") == 0) {
2667          ToggleAltEditTextBgColor();
2668       } else if (strcmp(name, "ChangeAllSelFontUnderline()") == 0) {
2669          if (args != NULL) {
2670             ChangeFontUnderline(atoi(args)-MAXFONTSTYLES-MAXJUSTS-2);
2671          }
2672       } else if (strcmp(name, "ChangeAllSelFontOverline()") == 0) {
2673          if (args != NULL) {
2674             ChangeFontOverline(atoi(args)-MAXFONTSTYLES-MAXJUSTS-5);
2675          }
2676       } else if (strcmp(name, "EditPageFileNames()") == 0) {
2677          EditPageFileNames();
2678       } else if (strcmp(name, "ExportHalfToneBitmap()") == 0) {
2679          ExportHalfToneBitmap();
2680       } else if (strcmp(name, "ExportThresholdBitmap()") == 0) {
2681          ExportThresholdBitmap();
2682       } else if (strcmp(name, "SetExportBitmapThreshold()") == 0) {
2683          if (args != NULL) {
2684             SetExportBitmapThreshold(NULL);
2685          }
2686       } else if (strcmp(name, "PreciseScaleEverything()") == 0) {
2687          PreciseScaleEverything();
2688       } else if (strcmp(name, "SetPaperColor()") == 0) {
2689          SetPaperColor();
2690       } else if (strcmp(name, "DelayedFullScreenCapture()") == 0) {
2691          DelayedFullScreenCapture();
2692       } else if (strcmp(name, "ToggleHideDuringCapture()") == 0) {
2693          ToggleHideDuringCapture();
2694       } else if (strcmp(name, "EditDomainPaths()") == 0) {
2695          EditDomainPaths();
2696       } else if (strcmp(name, "SelectDefaultDomain()") == 0) {
2697          SelectDefaultDomain();
2698       } else if (strcmp(name, "AddADomain()") == 0) {
2699          AddADomain();
2700       } else if (strcmp(name, "DeleteADomain()") == 0) {
2701          DeleteADomain();
2702       } else if (strcmp(name, "ReloadDomainInfoFromX()") == 0) {
2703          ReloadDomainInfoFromX();
2704       } else if (strcmp(name, "EditIndexedAttrInEditor()") == 0) {
2705          if (args != NULL) {
2706             EditIndexedAttrInEditor(atoi(args));
2707          }
2708       } else if (strcmp(name, "EditIndexedAttrGroupInEditor()") == 0) {
2709          if (args != NULL) {
2710             EditIndexedAttrGroupInEditor(atoi(args));
2711          }
2712       } else if (strcmp(name, "GetProperty()") == 0) {
2713          if (args != NULL) {
2714             GetProperty(atoi(args));
2715          }
2716       } else if (strcmp(name, "PeekDimension()") == 0) {
2717          if (args != NULL) {
2718             PeekDimension(atoi(args));
2719          }
2720       } else if (strcmp(name, "SetHtmlExportTemplate()") == 0) {
2721          SetHtmlExportTemplate();
2722       } else if (strcmp(name, "PrintPages()") == 0) {
2723          PrintPages();
2724       } else if (strcmp(name, "GoHyperSpaceInSlideShow()") == 0) {
2725          GoHyperSpaceInSlideShow();
2726       } else if (strcmp(name, "FreehandModeInSlideShow()") == 0) {
2727          FreehandModeInSlideShow();
2728       } else if (strcmp(name, "OpenARecentlyUsedFile()") == 0) {
2729          if (args != NULL) {
2730             OpenARecentlyUsedFile(atoi(args));
2731          }
2732       } else if (strcmp(name, "MoveEditTextBox()") == 0) {
2733          MoveEditTextBox();
2734       } else if (strcmp(name, "ReplaceGraphic()") == 0) {
2735          ReplaceGraphic();
2736       } else if (strcmp(name, "ToggleShowMeasurementInTooltip()") == 0) {
2737          ToggleShowMeasurementInTooltip();
2738       } else if (strcmp(name, "ToggleAutoEPSPreviewBitmap()") == 0) {
2739          ToggleAutoEPSPreviewBitmap();
2740       } else if (strcmp(name, "CreateThumbnails()") == 0) {
2741          CreateThumbnails();
2742       } else if (strcmp(name, "ConnectTwoPortsByAWire()") == 0) {
2743          ConnectTwoPortsByAWire();
2744       } else if (strcmp(name, "RenameSignalNameForAPort()") == 0) {
2745          RenameSignalNameForAPort();
2746       } else if (strcmp(name, "ClearSignalNameForAPort()") == 0) {
2747          ClearSignalNameForAPort();
2748       } else if (strcmp(name, "ToggleShowWireSignalName()") == 0) {
2749          ToggleShowWireSignalName();
2750       } else if (strcmp(name, "ToggleShowChoicebar()") == 0) {
2751          ToggleShowChoicebar();
2752       } else if (strcmp(name, "MergePortsWithAnObject()") == 0) {
2753          MergePortsWithAnObject();
2754       } else if (strcmp(name, "RenumberObjectIds()") == 0) {
2755          RenumberObjectIds();
2756       } else if (strcmp(name, "RepeatConnectTwoPortsByAWire()") == 0) {
2757          RepeatConnectTwoPortsByAWire();
2758       } else if (strcmp(name, "ConnectPortsToBroadcastWire()") == 0) {
2759          ConnectPortsToBroadcastWire();
2760       } else if (strcmp(name, "ImportMultipageTextFile()") == 0) {
2761          ImportMultipageTextFile();
2762       } else if (strcmp(name, "SetMarginsForImportMultipageTextFile()") == 0) {
2763          SetMarginsForImportMultipageTextFile();
2764       } else if (strcmp(name,
2765             "ToggleWordWrapDuringImportMultipageTextFile()") == 0) {
2766          ToggleWordWrapDuringImportMultipageTextFile();
2767       } else if (strcmp(name, "HandleDataInMBuff()") == 0) {
2768          HandleDataInMBuff();
2769       } else if (strcmp(name, "BenchMark()") == 0) {
2770          BenchMark();
2771       } else if (strcmp(name, "ConvertToBezier()") == 0) {
2772          ConvertToBezier();
2773       } else if (strcmp(name, "SetBezierConvertNumSegs()") == 0) {
2774          SetBezierConvertNumSegs((args==NULL || *args=='\0') ? NULL : args);
2775       } else if (strcmp(name, "AddSquareTickMarks()") == 0) {
2776          AddTickMarks(CMDID_ADDSQUARETICKMARKS);
2777       } else if (strcmp(name, "AddTriangleTickMarks()") == 0) {
2778          AddTickMarks(CMDID_ADDTRIANGLETICKMARKS);
2779       } else if (strcmp(name, "AddCircleTickMarks()") == 0) {
2780          AddTickMarks(CMDID_ADDCIRCLETICKMARKS);
2781       } else if (strcmp(name, "AddXTickMarks()") == 0) {
2782          AddTickMarks(CMDID_ADDXTICKMARKS);
2783       } else if (strcmp(name, "AddDiamondTickMarks()") == 0) {
2784          AddTickMarks(CMDID_ADDDIAMONDTICKMARKS);
2785       } else if (strcmp(name, "AddBowtieTickMarks()") == 0) {
2786          AddTickMarks(CMDID_ADDBOWTIETICKMARKS);
2787       } else if (strcmp(name, "AddInvTriangleTickMarks()") == 0) {
2788          AddTickMarks(CMDID_ADDINVTRIANGLETICKMARKS);
2789       } else if (strcmp(name, "AddPlusTickMarks()") == 0) {
2790          AddTickMarks(CMDID_ADDPLUSTICKMARKS);
2791       } else if (strcmp(name, "AddHourGlassTickMarks()") == 0) {
2792          AddTickMarks(CMDID_ADDHOURGLASSTICKMARKS);
2793       } else if (strcmp(name, "SetTickMarkSize()") == 0) {
2794          SetTickMarkSize((args==NULL || *args=='\0') ? NULL : args);
2795       } else if (strcmp(name, "ToggleShowChat()") == 0) {
2796          ToggleShowChat();
2797       } else if (strcmp(name, "SavePagesAs()") == 0) {
2798          SavePagesAs();
2799       } else if (strcmp(name, "AddPageBeforeCopyAll()") == 0) {
2800          AddPageBeforeCopyAll();
2801       } else if (strcmp(name, "AddPageAfterCopyAll()") == 0) {
2802          AddPageAfterCopyAll();
2803       } else if (strcmp(name, "InsertHexOctalChar()") == 0) {
2804          InsertHexOctalChar();
2805       } else if (strcmp(name, "ResetInputMethod()") == 0) {
2806          ResetInputMethod();
2807       } else if (strcmp(name, "LinkExtJPEGFile()") == 0) {
2808          ImportJPEGFile(FALSE, NULL);
2809       } else if (strcmp(name, "NextSlide()") == 0) {
2810          NextSlide();
2811       } else if (strcmp(name, "PrevSlide()") == 0) {
2812          PrevSlide();
2813       } else if (strcmp(name, "SetObjectShadowColor()") == 0) {
2814          SetObjectShadowColor();
2815       } else if (strcmp(name, "SetObjectShadowOffsets()") == 0) {
2816          SetObjectShadowOffsets();
2817       } else if (strcmp(name, "AddObjectShadow()") == 0) {
2818          AddObjectShadow();
2819       } else if (strcmp(name, "RemoveObjectShadow()") == 0) {
2820          RemoveObjectShadow();
2821       } else if (strcmp(name, "CopyDoubleByteString()") == 0) {
2822          CopyDoubleByteString();
2823       } else if (strcmp(name, "PasteDoubleByteString()") == 0) {
2824          PasteDoubleByteString();
2825       } else if (strcmp(name, "ReduceToMobileWebSafeColors()") == 0) {
2826          ReduceToMobileWebSafeColors();
2827       } else if (strcmp(name, "CreatePixmapFromSelected()") == 0) {
2828          CreatePixmapFromSelected();
2829       } else if (strcmp(name, "ToggleAutoRotatePivot()") == 0) {
2830          ToggleAutoRotatePivot();
2831       } else if (strcmp(name, "SpecifyRotatePivot()") == 0) {
2832          SpecifyRotatePivot();
2833       } else if (strcmp(name, "ResetRotatePivot()") == 0) {
2834          ResetRotatePivot();
2835       } else if (strcmp(name, "NextPolyRotationPivot()") == 0) {
2836          NextPolyRotationPivot();
2837       } else if (strcmp(name, "MoveRotationPivotToArcCenter()") == 0) {
2838          MoveRotationPivotToArcCenter();
2839       } else if (strcmp(name, "MoveRotatePivotCenter()") == 0) {
2840          MoveRotatePivot(CORNER_NONE);
2841       } else if (strcmp(name, "MoveRotatePivotLeftTop()") == 0) {
2842          MoveRotatePivot(CORNER_LT);
2843       } else if (strcmp(name, "MoveRotatePivotRightTop()") == 0) {
2844          MoveRotatePivot(CORNER_RT);
2845       } else if (strcmp(name, "MoveRotatePivotLeftBottom()") == 0) {
2846          MoveRotatePivot(CORNER_LB);
2847       } else if (strcmp(name, "MoveRotatePivotRightBottom()") == 0) {
2848          MoveRotatePivot(CORNER_RB);
2849       } else if (strcmp(name, "MoveRotatePivotLeft()") == 0) {
2850          MoveRotatePivot(CORNER_LEFT);
2851       } else if (strcmp(name, "MoveRotatePivotRight()") == 0) {
2852          MoveRotatePivot(CORNER_RIGHT);
2853       } else if (strcmp(name, "MoveRotatePivotTop()") == 0) {
2854          MoveRotatePivot(CORNER_TOP);
2855       } else if (strcmp(name, "MoveRotatePivotBottom()") == 0) {
2856          MoveRotatePivot(CORNER_BOTTOM);
2857       } else if (strcmp(name, "ChooseRotatePivot()") == 0) {
2858          if (args != NULL) {
2859             AutoRotatePivotSubMenu(atoi(args));
2860          }
2861       } else if (strcmp(name, "ChooseColor()") == 0) {
2862          ChooseColor();
2863       } else if (strcmp(name, "ExtendSegment()") == 0) {
2864          ExtendSegment();
2865       } else if (strcmp(name, "InsertSymbol()") == 0) {
2866          InsertSymbol();
2867       } else if (strcmp(name, "ToggleRightMargin()") == 0) {
2868          ToggleRightMargin();
2869       } else if (strcmp(name, "SpecifyRightMargin()") == 0) {
2870          SpecifyRightMargin();
2871       } else if (strcmp(name, "ToggleFloodReplaceColorThreshold()") == 0) {
2872          ToggleFloodReplaceColorThreshold();
2873       } else if (strcmp(name, "SetFloodReplaceColorThreshold()") == 0) {
2874          SetFloodReplaceColorThreshold();
2875       } else if (strcmp(name, "RemoveTransparentPixel()") == 0) {
2876          RemoveTransparentPixel();
2877       } else if (strcmp(name, "ReplaceColorWithTrans()") == 0) {
2878          ReplaceColorWithTrans();
2879 #ifdef NOT_DEFINED
2880       } else if (strcmp(name, "ToggleTighterStructuredSplines()") == 0) {
2881          ToggleTighterStructuredSplines();
2882 #endif /* NOT_DEFINED */
2883       } else if (strcmp(name, "MakeBoxObjFromBoundingBox()") == 0) {
2884          MakeBoxObjFromBoundingBox();
2885       } else if (strcmp(name, "MakeRCBoxObjFromBoundingBox()") == 0) {
2886          MakeRCBoxObjFromBoundingBox();
2887       } else if (strcmp(name, "MakeOvalObjFromBoundingBox()") == 0) {
2888          MakeOvalObjFromBoundingBox();
2889       }
2890    }
2891    return BAD;
2892 }
2893 
ShortHand(input)2894 int ShortHand(input)
2895    XEvent *input;
2896    /*
2897     * returns BAD if the character is a <CONTROL> or a <META> character
2898     *       this will cause the event to be swollowed
2899     * returns INVALID if the character is a normal character, this means
2900     *       that the event it not processed and will be handled by a
2901     *       routine later
2902     * otherwise, returns the value of sub-functions, such as QuitProc()
2903     */
2904 {
2905    register int i;
2906    char buf[80], *name=NULL, args[MAXSTRING+1];
2907    int valid_shortcut=FALSE, have_ch;
2908    KeySym key_sym=(KeySym)0;
2909    XKeyEvent *key_ev;
2910 
2911    key_ev = (&(input->xkey));
2912    have_ch = XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
2913    TranslateKeys(buf, &key_sym);
2914 
2915    *args = '\0';
2916 
2917    if (key_ev->window == drawWindow && CharIsCntrlINS(key_ev, key_sym)) {
2918       CopyToCutBuffer();
2919       return BAD;
2920    } else if (key_ev->window == drawWindow && CharIsShiftINS(key_ev, key_sym)) {
2921       PasteFromCutBuffer();
2922       return BAD;
2923    } else if (key_sym >= '\040' && (key_ev->state & (ControlMask | METAMASK))) {
2924       valid_shortcut = TRUE;
2925    } else if (key_sym >= XK_F1 && key_sym <= XK_F12) {
2926       char code='\0';
2927       unsigned int state=0;
2928 
2929       valid_shortcut = FetchFuncKeyShortCut((int)(key_sym), &code, &state,
2930             &name, args, sizeof(args));
2931       if (valid_shortcut) {
2932          key_sym = code;
2933          key_ev->state = state;
2934       }
2935    } else if (((key_sym>'\040' && key_sym<='\177') ||
2936          (key_sym>0xa0 && key_sym<=0xff)) &&
2937          !(key_ev->state & (ControlMask | METAMASK)) &&
2938          curChoice != DRAWTEXT && !TidgetHasFocus()) {
2939       char code='\0';
2940       unsigned int state=0;
2941 
2942       for (i = 0; i < numExtraWins; i++) {
2943          if (key_ev->window == extraWinInfo[i].window &&
2944                extraWinInfo[i].window != None) {
2945             break;
2946          }
2947       }
2948       if (i == numExtraWins) {
2949          valid_shortcut = FetchShortCut((int)(key_sym&0xff),
2950                &code, &state, &name, args, sizeof(args));
2951          if (valid_shortcut) {
2952             key_sym = code;
2953             key_ev->state = state;
2954          }
2955       }
2956    }
2957    if (valid_shortcut) {
2958       int rc=0;
2959       int try_x_lookup_keysym=FALSE;
2960 
2961       Msg("");
2962 #ifndef _NO_XLOOKUPKEYSYM
2963       try_x_lookup_keysym = TRUE;
2964 #endif /* ~_NO_XLOOKUPKEYSYM */
2965       rc = DoShortCut(key_ev, name, key_sym, key_ev->state, args);
2966       if (rc == INVALID && try_x_lookup_keysym) {
2967          key_sym = XLookupKeysym(key_ev, 0);
2968 
2969          return DoShortCut(key_ev, name, key_sym, key_ev->state, args);
2970       }
2971       return rc;
2972    }
2973    return INVALID;
2974 }
2975 
ExecuteCmdById(nCmdId,nIndex)2976 int ExecuteCmdById(nCmdId, nIndex)
2977    int nCmdId, nIndex;
2978 {
2979    char *name=NULL, args[MAXSTRING+1], code='\0';
2980    unsigned int state;
2981    KeySym key_sym=(KeySym)0;
2982    XKeyEvent key_ev;
2983 
2984    *args = '\0';
2985    if (FetchCmdById(nCmdId, &code, &state, &name, args)) {
2986       if (*args == '\0') sprintf(args, "%d", nIndex);
2987       key_sym = code;
2988       key_ev.state = state;
2989       Msg("");
2990       return DoShortCut(&key_ev, name, key_sym, key_ev.state, args);
2991    } else if (cmdLineTgrm2 && ValidTangram2CmdId(nCmdId)) {
2992       return DoTangram2Cmd(nCmdId, NULL);
2993    }
2994    return INVALID;
2995 }
2996 
CallShortCut(name,argc,argv,code,state)2997 int CallShortCut(name, argc, argv, code, state)
2998    char *name, *argv[], *code;
2999    int argc;
3000    unsigned int state;
3001 {
3002    /* do not translate -- program constants */
3003    if (UtilStrICmp(name, "ZoomInAtCursor") == 0 ||
3004          UtilStrICmp(name, "CenterAtCursor") == 0) {
3005       return FALSE;
3006    }
3007    DoShortCut(NULL, name, (KeySym)(*code), state, (argc<=1 ? NULL : argv[1]));
3008    return TRUE;
3009 }
3010 
SomethingDirty()3011 int SomethingDirty()
3012 {
3013    register struct ObjRec *obj_ptr=topObj;
3014 
3015    for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
3016       if (obj_ptr->dirty) {
3017          return TRUE;
3018       }
3019    }
3020    return FALSE;
3021 }
3022 
3023 static char gszEditorCmd[MAXSTRING];
3024 
3025 static char gszDefEditorCmd[]="xterm -title '%s' -e vi '%s'";
3026 
3027 static
InitEditor()3028 void InitEditor()
3029 {
3030    static int stInitialized=FALSE;
3031 
3032    if (!stInitialized) {
3033       int count=0;
3034       char *psz=NULL;
3035 
3036       strcpy(gszEditorCmd, gszDefEditorCmd);
3037       if ((psz=XGetDefault(mainDisplay, TOOL_NAME, "Editor")) != NULL) {
3038          UtilStrCpyN(gszEditorCmd, sizeof(gszEditorCmd), psz);
3039       }
3040       UtilTrimBlanks(gszEditorCmd);
3041       for(psz=strstr(gszEditorCmd,"%s"); psz != NULL; psz=strstr(++psz,"%s")) {
3042          count++;
3043       }
3044       if (count != 2) {
3045          sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_STR),
3046                TOOL_NAME, "Editor", gszEditorCmd, gszDefEditorCmd);
3047          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3048          strcpy(gszEditorCmd, gszDefEditorCmd);
3049       }
3050       stInitialized = TRUE;
3051    }
3052 }
3053 
3054 typedef struct tagTmpFileRec {
3055    char tmp_fname[MAXPATHLENGTH];
3056    struct stat stat_buf;
3057 } TmpFileInfo;
3058 
3059 static
WriteAttrToTmp(attr_ptr,ptfi)3060 int WriteAttrToTmp(attr_ptr, ptfi)
3061    struct AttrRec *attr_ptr;
3062    TmpFileInfo *ptfi;
3063 {
3064    FILE *fp=NULL;
3065 
3066    if (MkTempFile(ptfi->tmp_fname, sizeof(ptfi->tmp_fname), tmpDir,
3067          TOOL_NAME) == NULL) {
3068       return FALSE;
3069    }
3070    if ((fp=fopen(ptfi->tmp_fname, "w")) == NULL) {
3071       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
3072             ptfi->tmp_fname);
3073       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3074       return FALSE;
3075    }
3076    writeFileFailed = FALSE;
3077    if (*attr_ptr->attr_name.s == '\0') {
3078       DumpMiniLinesInAscii(fp, &attr_ptr->obj->detail.t->minilines, NULL);
3079    } else {
3080       int need_to_free_tmp_buf=FALSE;
3081       MiniLineInfo *pMiniLine=attr_ptr->obj->detail.t->minilines.first;
3082       char *tmp_buf=NULL, *psz=NULL;
3083 
3084       tmp_buf = ConvertAttrNameFirstMiniLineToString(attr_ptr,
3085             &need_to_free_tmp_buf);
3086       psz = strchr(tmp_buf, '=');
3087       fprintf(fp, "%s\n", &psz[1]);
3088 
3089       for (pMiniLine=pMiniLine->next; pMiniLine != NULL;
3090             pMiniLine=pMiniLine->next) {
3091          DumpMiniLineInAscii(fp, pMiniLine, NULL);
3092          if (fprintf(fp, "\n") == EOF) writeFileFailed = TRUE;
3093       }
3094       if (need_to_free_tmp_buf) UtilFree(tmp_buf);
3095    }
3096    fclose(fp);
3097 
3098    if (writeFileFailed) {
3099       FailToWriteFileMessage(ptfi->tmp_fname);
3100       unlink(ptfi->tmp_fname);
3101       return FALSE;
3102    }
3103    if (tmpFileMode != 0 && chmod(ptfi->tmp_fname, tmpFileMode)) {
3104       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_CHMOD), ptfi->tmp_fname);
3105       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3106       unlink(ptfi->tmp_fname);
3107       return FALSE;
3108    }
3109    if (stat(ptfi->tmp_fname, &ptfi->stat_buf) != 0) {
3110       sprintf(gszMsgBox, TgLoadString(STID_STAT_FAIL_EDIT_ATTR_VAL_SAME),
3111             ptfi->tmp_fname);
3112       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3113       unlink(ptfi->tmp_fname);
3114       return FALSE;
3115    }
3116    return TRUE;
3117 }
3118 
3119 static
WriteNamedAttrsToTmp(obj_ptr,num_restricted,ppsz_restricted,ptfi,pn_num_exported)3120 int WriteNamedAttrsToTmp(obj_ptr, num_restricted, ppsz_restricted, ptfi,
3121       pn_num_exported)
3122    struct ObjRec *obj_ptr;
3123    int num_restricted, *pn_num_exported;
3124    char **ppsz_restricted;
3125    TmpFileInfo *ptfi;
3126 {
3127    int i=0, num_found=0;
3128    FILE *fp=NULL;
3129 
3130    if (MkTempFile(ptfi->tmp_fname, sizeof(ptfi->tmp_fname), tmpDir,
3131          TOOL_NAME) == NULL) {
3132       return FALSE;
3133    }
3134    if ((fp=fopen(ptfi->tmp_fname, "w")) == NULL) {
3135       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
3136             ptfi->tmp_fname);
3137       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3138       return FALSE;
3139    }
3140    sprintf(gszMsgBox, TgLoadCachedString(CSTID_WRITING_ATTR_TO_NAMED_FILE),
3141          ptfi->tmp_fname);
3142    Msg(gszMsgBox);
3143    writeFileFailed = FALSE;
3144 
3145    for (i=0; i < num_restricted; i++) {
3146       char *attr_name=ppsz_restricted[i];
3147       struct AttrRec *attr_ptr=FindObjAttrWithName(obj_ptr, attr_name);
3148 
3149       if (attr_ptr == NULL) {
3150          sprintf(gszMsgBox, TgLoadCachedString(CSTID_CANT_FIND_NAMED_ATTR),
3151                attr_name);
3152          Msg(gszMsgBox);
3153       } else {
3154          if (*attr_ptr->attr_name.s == '\0') {
3155             DumpMiniLinesInAscii(fp, &attr_ptr->obj->detail.t->minilines, NULL);
3156          } else {
3157             int need_to_free_tmp_buf=FALSE;
3158             MiniLineInfo *pMiniLine=attr_ptr->obj->detail.t->minilines.first;
3159             char *tmp_buf=NULL;
3160 
3161             num_found++;
3162             tmp_buf = ConvertAttrNameFirstMiniLineToString(attr_ptr,
3163                   &need_to_free_tmp_buf);
3164             fprintf(fp, "%s\n", tmp_buf);
3165 
3166             for (pMiniLine=pMiniLine->next; pMiniLine != NULL;
3167                   pMiniLine=pMiniLine->next) {
3168                DumpMiniLineInAscii(fp, pMiniLine, NULL);
3169                if (fprintf(fp, "\n") == EOF) writeFileFailed = TRUE;
3170             }
3171             if (need_to_free_tmp_buf) UtilFree(tmp_buf);
3172 
3173             if (fprintf(fp, "%s\n", gszAttrSeparator) == EOF) {
3174                writeFileFailed = TRUE;
3175             }
3176          }
3177       }
3178    }
3179    fclose(fp);
3180 
3181    if (writeFileFailed) {
3182       FailToWriteFileMessage(ptfi->tmp_fname);
3183       unlink(ptfi->tmp_fname);
3184       return FALSE;
3185    }
3186    if (tmpFileMode != 0 && chmod(ptfi->tmp_fname, tmpFileMode)) {
3187       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_CHMOD), ptfi->tmp_fname);
3188       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3189       unlink(ptfi->tmp_fname);
3190       return FALSE;
3191    }
3192    if (stat(ptfi->tmp_fname, &ptfi->stat_buf) != 0) {
3193       sprintf(gszMsgBox, TgLoadString(STID_STAT_FAIL_EDIT_ATTR_VAL_SAME),
3194             ptfi->tmp_fname);
3195       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3196       unlink(ptfi->tmp_fname);
3197       return FALSE;
3198    }
3199    sprintf(gszMsgBox, TgLoadString(STID_ATTR_EXPORTED_TO_NAMED_FILE),
3200          ptfi->tmp_fname);
3201    Msg(gszMsgBox);
3202 
3203    if (pn_num_exported != NULL) *pn_num_exported = num_found;
3204 
3205    return TRUE;
3206 }
3207 
3208 static
TmpFileChanged(ptfi)3209 int TmpFileChanged(ptfi)
3210    TmpFileInfo *ptfi;
3211 {
3212    struct stat stat_buf;
3213 
3214    memset(&stat_buf, 0, sizeof(struct stat));
3215    if (stat(ptfi->tmp_fname, &stat_buf) != 0) {
3216       sprintf(gszMsgBox, TgLoadString(STID_STAT_FAIL_EDIT_ATTR_VAL_SAME),
3217             ptfi->tmp_fname);
3218       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3219       return FALSE;
3220    }
3221    if (stat_buf.st_mtime == ptfi->stat_buf.st_mtime &&
3222          stat_buf.st_size == ptfi->stat_buf.st_size) {
3223       return FALSE;
3224    }
3225    return TRUE;
3226 }
3227 
3228 static
ReadAttrFromTmp(attr_ptr,ptfi)3229 int ReadAttrFromTmp(attr_ptr, ptfi)
3230    struct AttrRec *attr_ptr;
3231    TmpFileInfo *ptfi;
3232 {
3233    struct ObjRec *attr_owner_obj=attr_ptr->owner;
3234    FILE *fp=NULL;
3235 
3236    if ((fp=fopen(ptfi->tmp_fname, "r")) == NULL) {
3237       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
3238             ptfi->tmp_fname);
3239       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3240       return FALSE;
3241    }
3242    PrepareToReplaceAnObj(attr_owner_obj);
3243 
3244    JustReadFileIntoAttr(fp, attr_ptr, attr_owner_obj);
3245 
3246    fclose(fp);
3247 
3248    return TRUE;
3249 }
3250 
3251 static
ReadNamedAttrsFromTmp(obj_ptr,num_restricted,ppsz_restricted,ptfi)3252 int ReadNamedAttrsFromTmp(obj_ptr, num_restricted, ppsz_restricted, ptfi)
3253    struct ObjRec *obj_ptr;
3254    int num_restricted;
3255    char **ppsz_restricted;
3256    TmpFileInfo *ptfi;
3257 {
3258    FILE *fp=NULL;
3259    int rc=0;
3260 
3261    if ((fp=fopen(ptfi->tmp_fname, "r")) == NULL) {
3262       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
3263             ptfi->tmp_fname);
3264       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3265       return FALSE;
3266    }
3267    rc = ImportNamedAttrs(fp, obj_ptr, num_restricted, ppsz_restricted,
3268          ptfi->tmp_fname);
3269    fclose(fp);
3270 
3271    return rc;
3272 }
3273 
3274 static
AbortLaunch(pVoid)3275 int AbortLaunch(pVoid)
3276    void *pVoid;
3277 {
3278    if (MsgBox(TgLoadString(STID_CNTRL_C_ABORT_LAUNCH), TOOL_NAME, YNC_MB) ==
3279          MB_ID_YES) {
3280       return TRUE;
3281    }
3282    return FALSE;
3283 }
3284 
EditIndexedAttrInEditor(index)3285 void EditIndexedAttrInEditor(index)
3286    int index;
3287 {
3288    int i=0, num_attrs=0, total_attrs=0;
3289    int restricted=FALSE, num_restricted=0, actual_index=0, found=FALSE;
3290    char **attr_strings=NULL, cmd[MAXSTRING<<1], title[MAXSTRING];
3291    char **ppsz_restricted=NULL;
3292    struct AttrRec *attr_ptr=NULL, *restricted_attr=NULL;
3293    FILE *pfp=NULL;
3294    TmpFileInfo tfi;
3295 
3296    InitEditor();
3297 
3298    if (gpEditAttrInEditorAttrInfo == NULL || topSel == NULL ||
3299          topSel != botSel) {
3300       return;
3301    }
3302    for (attr_ptr=topSel->obj->fattr; attr_ptr != NULL;
3303          attr_ptr=attr_ptr->next, total_attrs++) {
3304    }
3305    attr_ptr = topSel->obj->fattr;
3306 
3307    num_attrs = gpEditAttrInEditorAttrInfo->num_attrs;
3308    attr_strings = gpEditAttrInEditorAttrInfo->attr_strings;
3309 
3310    if (total_attrs <= 0 || num_attrs <= 0 || attr_strings == NULL) return;
3311 
3312    restricted = HasEditAttrsInContextMenu(topSel->obj, &restricted_attr);
3313    if (restricted) {
3314       GetRestrictedAttrNames(restricted_attr->obj, &ppsz_restricted,
3315             &num_restricted);
3316       if (ppsz_restricted == NULL || num_restricted <= 0) {
3317          return;
3318       }
3319    }
3320    for (i=0; i < total_attrs; i++, attr_ptr=attr_ptr->next) {
3321       if (restricted) {
3322          if (!IsRestrictedAttr(attr_ptr->attr_name.s, ppsz_restricted,
3323                num_restricted)) {
3324             continue;
3325          }
3326       }
3327       if (actual_index == index) {
3328          found = TRUE;
3329          break;
3330       }
3331       actual_index++;
3332    }
3333    FreeRestrictedAttrNames(ppsz_restricted, num_restricted);
3334 
3335    if (!found) return;
3336 
3337    memset(&tfi, 0, sizeof(TmpFileInfo));
3338    if (!WriteAttrToTmp(attr_ptr, &tfi)) return;
3339 
3340    SaveStatusStrings();
3341    if (*attr_ptr->attr_name.s == '\0') {
3342       sprintf(title, TgLoadString(STID_EDIT_UNNAME_ATTR_DOTS));
3343       sprintf(cmd, gszEditorCmd, title, tfi.tmp_fname);
3344       sprintf(gszMsgBox, TgLoadString(STID_EDIT_UNNAME_ATTR_WITH_CMD), cmd);
3345    } else {
3346       sprintf(title, TgLoadString(STID_EDIT_VAL_OF_ATTR_DOTS),
3347             attr_ptr->attr_name.s);
3348       sprintf(cmd, gszEditorCmd, title, tfi.tmp_fname);
3349       sprintf(gszMsgBox, TgLoadString(STID_EDIT_VAL_OF_ATTR_WITH_CMD),
3350             attr_ptr->attr_name.s, cmd);
3351    }
3352    if (!FindProgramInPath(cmd, NULL, FALSE)) {
3353       RestoreStatusStrings();
3354       unlink(tfi.tmp_fname);
3355       return;
3356    }
3357    ShowInterrupt(DEF_CHECK_INTERVAL);
3358    SetStringStatus(gszMsgBox);
3359 
3360    EndMeasureTooltip(FALSE);
3361    if ((pfp=(FILE*)popen(cmd, "r")) == NULL) {
3362       sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_EXECUTE_CMD), cmd);
3363       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3364    } else {
3365       int quit=FALSE, got_eof=FALSE, fd=fileno(pfp);
3366 
3367       Msg(TgLoadCachedString(CSTID_CNTRL_C_TO_INTR_AND_ABEND));
3368       SetSocketBlockingState(&fd, FALSE);
3369 
3370       /*
3371        * Note: Calling WaitForEvent() with the second argument being
3372        *       TRUE can lose data in the pipe.  Can do this here
3373        *       because the data in the pipe is ignored.
3374        */
3375       while (WaitForEvent(pfp, TRUE, FALSE, &quit, EXPOSE_AND_ESC_X_EV_ONLY,
3376             AbortLaunch, NULL)) {
3377          if (quit) {
3378             break;
3379          } else if (PipeReachedEOF(pfp)) {
3380             got_eof = TRUE;
3381             break;
3382          }
3383       }
3384       if (quit && !got_eof) {
3385          sprintf(gszMsgBox,
3386                TgLoadString(STID_CMD_ABORT_LAUNCH_CLOSE_TOOL), cmd, TOOL_NAME);
3387          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3388       } else {
3389          pclose(pfp);
3390       }
3391    }
3392    RestoreStatusStrings();
3393    HideInterrupt();
3394 
3395    if (TmpFileChanged(&tfi)) {
3396       HighLightReverse();
3397       if (ReadAttrFromTmp(attr_ptr, &tfi)) {
3398          SetFileModified(TRUE);
3399       }
3400       HighLightForward();
3401    }
3402    unlink(tfi.tmp_fname);
3403 }
3404 
EditIndexedAttrGroupInEditor(index)3405 void EditIndexedAttrGroupInEditor(index)
3406    int index;
3407 {
3408    int num_attrs_in_attr_group=0, total_attrs_in_obj=0;
3409    int num_restricted=0, num_exported=0, done=FALSE;
3410    char **attr_name_array=NULL, cmd[MAXSTRING<<1], title[MAXSTRING];
3411    char **ppsz_restricted=NULL;
3412    struct AttrRec *attr_ptr=NULL;
3413    FILE *pfp=NULL;
3414    TmpFileInfo tfi;
3415 
3416    InitEditor();
3417 
3418    if (gpEditAttrInEditorAttrInfo == NULL || topSel == NULL ||
3419          topSel != botSel || index >= maxAttrGroups) {
3420       return;
3421    }
3422    for (attr_ptr=topSel->obj->fattr; attr_ptr != NULL;
3423          attr_ptr=attr_ptr->next, total_attrs_in_obj++) {
3424    }
3425    attr_ptr = topSel->obj->fattr;
3426 
3427    num_attrs_in_attr_group = gAttrGroupInfo[index]->num_attrs;
3428    attr_name_array = gAttrGroupInfo[index]->attr_name;
3429 
3430    if (total_attrs_in_obj <= 0 || num_attrs_in_attr_group <= 0 ||
3431          attr_name_array == NULL) {
3432       return;
3433    }
3434    /*
3435     * For this function, we do not need to call HasEditAttrsInContextMenu()
3436     *     because the "edit_attrs_in_context_menu=" attribute is only for the
3437     *     "Edit Attribute In Editor" submenu and *not* for the
3438     *     "Edit Attribute Group In Editor" submenu.
3439     * We just pretend that the "edit_attrs_in_context_menu=" attribute is
3440     *     there so we can reuse the code.
3441     */
3442    GetAttrGroupAttrNames(topSel->obj, index, &ppsz_restricted, &num_restricted);
3443    if (ppsz_restricted == NULL || num_restricted <= 0) {
3444       return;
3445    }
3446    memset(&tfi, 0, sizeof(TmpFileInfo));
3447    if (!WriteNamedAttrsToTmp(topSel->obj, num_restricted, ppsz_restricted,
3448          &tfi, &num_exported)) {
3449       FreeRestrictedAttrNames(ppsz_restricted, num_restricted);
3450       return;
3451    }
3452    if (num_restricted != num_exported) {
3453       sprintf(gszMsgBox, TgLoadString(STID_WARN_CANNOT_FIND_SOME_ATTRS),
3454                gAttrGroupInfo[index]->displayed_names);
3455       if (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB) != MB_ID_YES) {
3456          FreeRestrictedAttrNames(ppsz_restricted, num_restricted);
3457          unlink(tfi.tmp_fname);
3458          return;
3459       }
3460    }
3461    SaveStatusStrings();
3462    if (*attr_ptr->attr_name.s == '\0') {
3463       sprintf(title, TgLoadString(STID_EDIT_UNNAME_ATTR_DOTS));
3464       sprintf(cmd, gszEditorCmd, title, tfi.tmp_fname);
3465       sprintf(gszMsgBox, TgLoadString(STID_EDIT_UNNAME_ATTR_WITH_CMD), cmd);
3466    } else {
3467       sprintf(title, TgLoadString(STID_EDIT_VAL_OF_ATTR_DOTS),
3468             attr_ptr->attr_name.s);
3469       sprintf(cmd, gszEditorCmd, title, tfi.tmp_fname);
3470       sprintf(gszMsgBox, TgLoadString(STID_EDIT_VAL_OF_ATTR_WITH_CMD),
3471             attr_ptr->attr_name.s, cmd);
3472    }
3473    if (!FindProgramInPath(cmd, NULL, FALSE)) {
3474       RestoreStatusStrings();
3475       unlink(tfi.tmp_fname);
3476       return;
3477    }
3478    while (!done) {
3479       ShowInterrupt(DEF_CHECK_INTERVAL);
3480       SetStringStatus(gszMsgBox);
3481 
3482       EndMeasureTooltip(FALSE);
3483       if ((pfp=(FILE*)popen(cmd, "r")) == NULL) {
3484          sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_EXECUTE_CMD), cmd);
3485          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3486       } else {
3487          int quit=FALSE, got_eof=FALSE, fd=fileno(pfp);
3488 
3489          Msg(TgLoadCachedString(CSTID_CNTRL_C_TO_INTR_AND_ABEND));
3490          SetSocketBlockingState(&fd, FALSE);
3491 
3492          /*
3493           * Note: Calling WaitForEvent() with the second argument being
3494           *       TRUE can lose data in the pipe.  Can do this here
3495           *       because the data in the pipe is ignored.
3496           */
3497          while (WaitForEvent(pfp, TRUE, FALSE, &quit, EXPOSE_AND_ESC_X_EV_ONLY,
3498                AbortLaunch, NULL)) {
3499             if (quit) {
3500                break;
3501             } else if (PipeReachedEOF(pfp)) {
3502                got_eof = TRUE;
3503                break;
3504             }
3505          }
3506          if (quit && !got_eof) {
3507             sprintf(gszMsgBox,
3508                   TgLoadString(STID_CMD_ABORT_LAUNCH_CLOSE_TOOL), cmd,
3509                   TOOL_NAME);
3510             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3511          } else {
3512             pclose(pfp);
3513          }
3514       }
3515       RestoreStatusStrings();
3516       HideInterrupt();
3517 
3518       if (TmpFileChanged(&tfi)) {
3519          HighLightReverse();
3520          if (ReadNamedAttrsFromTmp(topSel->obj, num_restricted, ppsz_restricted,
3521                &tfi)) {
3522             done = TRUE;
3523          } else {
3524             /* get the file modified */
3525             if (stat(tfi.tmp_fname, &tfi.stat_buf) != 0) {
3526                sprintf(gszMsgBox,
3527                      TgLoadString(STID_STAT_FAIL_EDIT_ATTR_VAL_SAME),
3528                      tfi.tmp_fname);
3529                MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3530                unlink(tfi.tmp_fname);
3531                done = TRUE;
3532             }
3533          }
3534          HighLightForward();
3535       } else {
3536          done = TRUE;
3537       }
3538    }
3539    unlink(tfi.tmp_fname);
3540 }
3541 
CreateEditAttrInEditorMenu(parent_menu,X,Y,menu_info,status_str_xlated)3542 TgMenu *CreateEditAttrInEditorMenu(parent_menu, X, Y, menu_info,
3543       status_str_xlated)
3544    TgMenu *parent_menu;
3545    int X, Y;
3546    TgMenuInfo *menu_info;
3547    int status_str_xlated; /* ignored, always 0 */
3548 {
3549    TgMenu *menu=NULL;
3550 
3551    if (topSel == NULL || topSel != botSel) return NULL;
3552 
3553    FreeEditAttrInfo(gpEditAttrInEditorAttrInfo);
3554    gpEditAttrInEditorAttrInfo = NULL;
3555 
3556    gpEditAttrInEditorAttrInfo = CreateEditAttrInfo(topSel->obj);
3557 
3558    if (gpEditAttrInEditorAttrInfo == NULL) return NULL;
3559 
3560    menu = CreateAttrMenu(parent_menu, X, Y,
3561          gpEditAttrInEditorAttrInfo->num_attrs,
3562          gpEditAttrInEditorAttrInfo->attr_strings,
3563          gpEditAttrInEditorAttrInfo->status_strings,
3564          gpEditAttrInEditorAttrInfo->fore_colors);
3565    if (menu != NULL) {
3566       int i=0, num_items=menu->num_items;
3567       TgMenuItem *menuitems=menu->menuitems;
3568 
3569       for (i=0; i < num_items; i++) {
3570          menuitems[i].cmdid = CMDID_EDITATTRINEDITOR;
3571       }
3572    }
3573    return menu;
3574 }
3575 
CreateEditAttrGroupInEditorMenu(parent_menu,X,Y,menu_info,status_str_xlated)3576 TgMenu *CreateEditAttrGroupInEditorMenu(parent_menu, X, Y, menu_info,
3577       status_str_xlated)
3578    TgMenu *parent_menu;
3579    int X, Y;
3580    TgMenuInfo *menu_info;
3581    int status_str_xlated; /* ignored, always 0 */
3582 {
3583    TgMenu *menu=NULL;
3584 
3585    if (topSel == NULL || topSel != botSel) return NULL;
3586 
3587    FreeEditAttrInfo(gpEditAttrInEditorAttrInfo);
3588    gpEditAttrInEditorAttrInfo = NULL;
3589 
3590    gpEditAttrInEditorAttrInfo = CreateEditAttrGroupInfo(topSel->obj);
3591 
3592    if (gpEditAttrInEditorAttrInfo == NULL) return NULL;
3593 
3594    menu = CreateAttrMenu(parent_menu, X, Y,
3595          gpEditAttrInEditorAttrInfo->num_attrs,
3596          gpEditAttrInEditorAttrInfo->attr_strings,
3597          gpEditAttrInEditorAttrInfo->status_strings,
3598          gpEditAttrInEditorAttrInfo->fore_colors);
3599    if (menu != NULL) {
3600       int i=0, num_items=menu->num_items;
3601       TgMenuItem *menuitems=menu->menuitems;
3602 
3603       for (i=0; i < num_items; i++) {
3604          menuitems[i].cmdid = CMDID_EDITATTRGROUPINEDITOR;
3605       }
3606    }
3607    return menu;
3608 }
3609 
GetProperty(index)3610 void GetProperty(index)
3611    int index;
3612 {
3613    DoGetProperty(index);
3614 }
3615 
CreateGetPropertyMenu(parent_menu,X,Y,menu_info,status_str_xlated)3616 TgMenu *CreateGetPropertyMenu(parent_menu, X, Y, menu_info,
3617       status_str_xlated)
3618    TgMenu *parent_menu;
3619    int X, Y;
3620    TgMenuInfo *menu_info;
3621    int status_str_xlated; /* ignored, always 0 */
3622 {
3623    TgMenu *menu=NULL;
3624 
3625    if (topSel == NULL || topSel != botSel) return NULL;
3626 
3627    FreeEditAttrInfo(gpEditAttrInEditorAttrInfo);
3628    gpEditAttrInEditorAttrInfo = NULL;
3629 
3630    gpEditAttrInEditorAttrInfo = CreateGetPropertyInfo();
3631 
3632    if (gpEditAttrInEditorAttrInfo == NULL) return NULL;
3633 
3634    menu = CreateAttrMenu(parent_menu, X, Y,
3635          gpEditAttrInEditorAttrInfo->num_attrs,
3636          gpEditAttrInEditorAttrInfo->attr_strings,
3637          gpEditAttrInEditorAttrInfo->status_strings,
3638          gpEditAttrInEditorAttrInfo->fore_colors);
3639    if (menu != NULL) {
3640       int i=0, num_items=menu->num_items;
3641       TgMenuItem *menuitems=menu->menuitems;
3642 
3643       for (i=0; i < num_items; i++) {
3644          menuitems[i].cmdid = CMDID_GETPROPERTY;
3645       }
3646    }
3647    return menu;
3648 }
3649 
3650 /* --------------------- PeekDimension stuff --------------------- */
3651 
3652 static
SetPeekStrings(attr_strings,status_strings,i,menu_text,status_text)3653 void SetPeekStrings(attr_strings, status_strings, i, menu_text, status_text)
3654    char **attr_strings, **status_strings;
3655    int i;
3656    char *menu_text, *status_text;
3657 {
3658    attr_strings[i] = UtilStrDup(menu_text);
3659    status_strings[i] = UtilStrDup(status_text);
3660    if (attr_strings[i] == NULL || status_strings[i] == NULL) FailAllocMessage();
3661 }
3662 
3663 static
CanGetArea(obj_ptr)3664 int CanGetArea(obj_ptr)
3665    struct ObjRec *obj_ptr;
3666 {
3667    int type=obj_ptr->type;
3668 
3669    if (type == OBJ_GROUP || type == OBJ_SYM || type == OBJ_ICON ||
3670          type == OBJ_PIN) {
3671       if (obj_ptr->detail.r->first == obj_ptr->detail.r->last) {
3672          return CanGetArea(obj_ptr->detail.r->first);
3673       }
3674       return FALSE;
3675    }
3676    return (type == OBJ_BOX || type == OBJ_POLYGON);
3677 }
3678 
3679 static
GetPolygonArea(polygon_ptr)3680 double GetPolygonArea(polygon_ptr)
3681    struct PolygonRec *polygon_ptr;
3682 {
3683    int i=0, n=0, curved=polygon_ptr->curved;
3684    int num_smooth_points=0, num_hinge_points=0;
3685    double area=(double)0;
3686    IntPoint *vs=NULL;
3687    char *smooth=NULL;
3688 
3689    if (curved == LT_STRUCT_SPLINE) {
3690       n = polygon_ptr->ssn;
3691       vs = polygon_ptr->ssvlist;
3692       smooth = polygon_ptr->ssmooth;
3693    } else {
3694       n = polygon_ptr->n;
3695       vs = polygon_ptr->vlist;
3696       smooth = polygon_ptr->smooth;
3697    }
3698    switch (curved) {
3699    case LT_STRAIGHT:
3700    case LT_SPLINE:
3701    case LT_STRUCT_SPLINE:
3702       for (i=1; i < n; i++) {
3703          if (smooth[i]) {
3704             num_smooth_points++;
3705          } else {
3706             num_hinge_points++;
3707          }
3708       }
3709       if (num_smooth_points == 0) {
3710          for (i=0; i < n-1; i++) {
3711             area += (double)(((double)vs[i].x) * ((double)vs[i+1].y) -
3712                   ((double)vs[i+1].x) * ((double)vs[i].y));
3713          }
3714          area = area / ((double)2);
3715       } else {
3716          /* don't know how to calculate with smooth points */
3717       }
3718       break;
3719    case LT_INTSPLINE:
3720       /* don't know how to calculate with smooth points */
3721       break;
3722    }
3723    for (i=0; i < n-1; i++) {
3724       area += (double)(((double)vs[i].x) * ((double)vs[i+1].y) -
3725             ((double)vs[i+1].x) * ((double)vs[i].y));
3726    }
3727    area = area / ((double)2);
3728 
3729    return area;
3730 }
3731 
3732 static
GetArea(obj_ptr)3733 double GetArea(obj_ptr)
3734    struct ObjRec *obj_ptr;
3735 {
3736    int type=obj_ptr->type, w=0, h=0;
3737    double area=(double)0, scale_x=(double)0, scale_y=(double)0;
3738 
3739    if (type == OBJ_GROUP || type == OBJ_SYM || type == OBJ_ICON ||
3740          type == OBJ_PIN) {
3741       if (obj_ptr->detail.r->first == obj_ptr->detail.r->last) {
3742          return GetArea(obj_ptr->detail.r->first);
3743       }
3744    }
3745    switch (type) {
3746    case OBJ_BOX:
3747       if (obj_ptr->ctm == NULL) {
3748          w = obj_ptr->obbox.rbx-obj_ptr->obbox.ltx;
3749          h = obj_ptr->obbox.rby-obj_ptr->obbox.lty;
3750          area = (double)(((double)w)*((double)h));
3751       } else {
3752          w = obj_ptr->orig_obbox.rbx-obj_ptr->orig_obbox.ltx;
3753          h = obj_ptr->orig_obbox.rby-obj_ptr->orig_obbox.lty;
3754          area = (double)(((double)w)*((double)h));
3755          scale_x = (double) (((double)fabs(obj_ptr->ctm->m[CTM_SX])) /
3756                ((double)1000));
3757          scale_y = (double) (((double)fabs(obj_ptr->ctm->m[CTM_SY])) /
3758                ((double)1000));
3759          area = area * scale_x * scale_y;
3760       }
3761       break;
3762    case OBJ_POLYGON:
3763       area = GetPolygonArea(obj_ptr->detail.g);
3764       if (obj_ptr->ctm != NULL) {
3765          scale_x = (double) (((double)fabs(obj_ptr->ctm->m[CTM_SX])) /
3766                ((double)1000));
3767          scale_y = (double) (((double)fabs(obj_ptr->ctm->m[CTM_SY])) /
3768                ((double)1000));
3769          area = area * scale_x * scale_y;
3770       }
3771       break;
3772    }
3773    return area;
3774 }
3775 
3776 
3777 static
CreatePeekDimensionInfo()3778 EditAttrInfo *CreatePeekDimensionInfo()
3779 {
3780    EditAttrInfo *pEditAttrInfo=NULL;
3781    char **attr_strings=NULL, **status_strings=NULL;
3782    char menu_text[MAXSTRING], status_text[MAXSTRING];
3783    char buf[MAXSTRING], buf1[MAXSTRING], *psz=NULL, *psz1=NULL;
3784    int num_attrs=10, can_get_area=FALSE;
3785    struct ObjRec *obj_ptr=NULL;
3786 
3787    if (topSel == NULL) return NULL;
3788 
3789    obj_ptr = topSel->obj;
3790 
3791    can_get_area = CanGetArea(obj_ptr);
3792    if (can_get_area) {
3793       num_attrs += 2;
3794    }
3795    pEditAttrInfo = (EditAttrInfo*)malloc(sizeof(EditAttrInfo));
3796    if (pEditAttrInfo == NULL) FailAllocMessage();
3797    memset(pEditAttrInfo, 0, sizeof(EditAttrInfo));
3798 
3799    attr_strings = (char**)malloc(num_attrs*sizeof(char*));
3800    status_strings = (char**)malloc(num_attrs*sizeof(char*));
3801    if (attr_strings == NULL || status_strings == NULL) FailAllocMessage();
3802    memset(attr_strings, 0, num_attrs*sizeof(char*));
3803    memset(status_strings, 0, num_attrs*sizeof(char*));
3804 
3805    PixelToMeasurementUnit(buf, obj_ptr->obbox.rbx-obj_ptr->obbox.ltx);
3806    PixelToMeasurementUnit(buf1, obj_ptr->bbox.rbx-obj_ptr->bbox.ltx);
3807    psz = ((*buf) == '+' ? &buf[1] : buf);
3808    psz1 = ((*buf1) == '+' ? &buf1[1] : buf1);
3809    /* do not translate -- program constants */
3810    sprintf(menu_text, "width = %s (outer width = %s)", psz, psz1);
3811    strcpy(status_text, TgLoadString(STID_PEEK_DIM_WIDTH));
3812    SetPeekStrings(attr_strings, status_strings, 0, menu_text, status_text);
3813 
3814    PixelToMeasurementUnit(buf, obj_ptr->obbox.rby-obj_ptr->obbox.lty);
3815    PixelToMeasurementUnit(buf1, obj_ptr->bbox.rby-obj_ptr->bbox.lty);
3816    psz = ((*buf) == '+' ? &buf[1] : buf);
3817    psz1 = ((*buf1) == '+' ? &buf1[1] : buf1);
3818    /* do not translate -- program constants */
3819    sprintf(menu_text, "height = %s (outer height = %s)", psz, psz1);
3820    strcpy(status_text, TgLoadString(STID_PEEK_DIM_HEIGHT));
3821    SetPeekStrings(attr_strings, status_strings, 1, menu_text, status_text);
3822 
3823    attr_strings[2] = TGMUITEM_SEPARATOR;
3824 
3825    PixelToMeasurementUnit(buf, obj_ptr->obbox.ltx);
3826    PixelToMeasurementUnit(buf1, obj_ptr->bbox.ltx);
3827    psz = ((*buf) == '+' ? &buf[1] : buf);
3828    psz1 = ((*buf1) == '+' ? &buf1[1] : buf1);
3829    /* do not translate -- program constants */
3830    sprintf(menu_text, "left = %s (outer left = %s)", psz, psz1);
3831    strcpy(status_text, TgLoadString(STID_PEEK_DIM_LEFT));
3832    SetPeekStrings(attr_strings, status_strings, 3, menu_text, status_text);
3833 
3834    PixelToMeasurementUnit(buf, obj_ptr->obbox.lty);
3835    PixelToMeasurementUnit(buf1, obj_ptr->bbox.lty);
3836    psz = ((*buf) == '+' ? &buf[1] : buf);
3837    psz1 = ((*buf1) == '+' ? &buf1[1] : buf1);
3838    /* do not translate -- program constants */
3839    sprintf(menu_text, "top = %s (outer top = %s)", psz, psz1);
3840    strcpy(status_text, TgLoadString(STID_PEEK_DIM_TOP));
3841    SetPeekStrings(attr_strings, status_strings, 4, menu_text, status_text);
3842 
3843    PixelToMeasurementUnit(buf, obj_ptr->obbox.rbx);
3844    PixelToMeasurementUnit(buf1, obj_ptr->bbox.rbx);
3845    psz = ((*buf) == '+' ? &buf[1] : buf);
3846    psz1 = ((*buf1) == '+' ? &buf1[1] : buf1);
3847    /* do not translate -- program constants */
3848    sprintf(menu_text, "right = %s (outer right = %s)", psz, psz1);
3849    strcpy(status_text, TgLoadString(STID_PEEK_DIM_RIGHT));
3850    SetPeekStrings(attr_strings, status_strings, 5, menu_text, status_text);
3851 
3852    PixelToMeasurementUnit(buf, obj_ptr->obbox.rby);
3853    PixelToMeasurementUnit(buf1, obj_ptr->bbox.rby);
3854    psz = ((*buf) == '+' ? &buf[1] : buf);
3855    psz1 = ((*buf1) == '+' ? &buf1[1] : buf1);
3856    /* do not translate -- program constants */
3857    sprintf(menu_text, "bottom = %s (outer bottom = %s)", psz, psz1);
3858    strcpy(status_text, TgLoadString(STID_PEEK_DIM_BOTTOM));
3859    SetPeekStrings(attr_strings, status_strings, 6, menu_text, status_text);
3860 
3861    attr_strings[7] = TGMUITEM_SEPARATOR;
3862 
3863    PixelToMeasurementUnit(buf, ((obj_ptr->obbox.rbx+obj_ptr->obbox.ltx)>>1));
3864    psz = ((*buf) == '+' ? &buf[1] : buf);
3865    /* do not translate -- program constants */
3866    sprintf(menu_text, "cx = %s", psz);
3867    strcpy(status_text, TgLoadString(STID_PEEK_DIM_CX));
3868    SetPeekStrings(attr_strings, status_strings, 8, menu_text, status_text);
3869 
3870    PixelToMeasurementUnit(buf, ((obj_ptr->obbox.rby+obj_ptr->obbox.lty)>>1));
3871    psz = ((*buf) == '+' ? &buf[1] : buf);
3872    /* do not translate -- program constants */
3873    sprintf(menu_text, "cy = %s", psz);
3874    strcpy(status_text, TgLoadString(STID_PEEK_DIM_CY));
3875    SetPeekStrings(attr_strings, status_strings, 9, menu_text, status_text);
3876 
3877    if (can_get_area) {
3878       double area=GetArea(obj_ptr);
3879 
3880       attr_strings[10] = TGMUITEM_SEPARATOR;
3881 
3882       SquarePixelToMeasurementUnit(buf, round(area));
3883       psz = ((*buf) == '+' ? &buf[1] : buf);
3884       /* do not translate -- program constants */
3885       sprintf(menu_text, "area = %s", psz);
3886       strcpy(status_text, TgLoadString(STID_PEEK_AREA));
3887       SetPeekStrings(attr_strings, status_strings, 11, menu_text, status_text);
3888    }
3889    pEditAttrInfo->num_attrs = num_attrs;
3890    pEditAttrInfo->fore_colors = NULL;
3891    pEditAttrInfo->attr_indices = NULL;
3892    pEditAttrInfo->attr_names = NULL;
3893    pEditAttrInfo->attr_values = NULL;
3894    pEditAttrInfo->attr_strings = attr_strings;
3895    pEditAttrInfo->status_strings = status_strings;
3896 
3897    return pEditAttrInfo;
3898 }
3899 
PeekDimension(index)3900 void PeekDimension(index)
3901    int index;
3902 {
3903    /* There's really nothing to do! */
3904 }
3905 
CreatePeekDimensionMenu(parent_menu,X,Y,menu_info,status_str_xlated)3906 TgMenu *CreatePeekDimensionMenu(parent_menu, X, Y, menu_info,
3907       status_str_xlated)
3908    TgMenu *parent_menu;
3909    int X, Y;
3910    TgMenuInfo *menu_info;
3911    int status_str_xlated; /* ignored, always 0 */
3912 {
3913    TgMenu *menu=NULL;
3914 
3915    if (topSel == NULL || topSel != botSel) return NULL;
3916 
3917    FreeEditAttrInfo(gpEditAttrInEditorAttrInfo);
3918    gpEditAttrInEditorAttrInfo = NULL;
3919 
3920    gpEditAttrInEditorAttrInfo = CreatePeekDimensionInfo();
3921 
3922    if (gpEditAttrInEditorAttrInfo == NULL) return NULL;
3923 
3924    menu = CreateAttrMenu(parent_menu, X, Y,
3925          gpEditAttrInEditorAttrInfo->num_attrs,
3926          gpEditAttrInEditorAttrInfo->attr_strings,
3927          gpEditAttrInEditorAttrInfo->status_strings,
3928          gpEditAttrInEditorAttrInfo->fore_colors);
3929    if (menu != NULL) {
3930       int i=0, num_items=menu->num_items;
3931       TgMenuItem *menuitems=menu->menuitems;
3932 
3933       for (i=0; i < num_items; i++) {
3934          menuitems[i].cmdid = CMDID_GETPROPERTY;
3935       }
3936    }
3937    return menu;
3938 }
3939 
3940 /* --------------------- RefreshContextMenu() --------------------- */
3941 
RefreshContextMenu(menu)3942 int RefreshContextMenu(menu)
3943    TgMenu *menu;
3944 {
3945    int ok=TRUE;
3946 
3947    if (topSel == NULL || topSel != botSel) return FALSE;
3948 
3949    /* ImageProc submenu */
3950    ok &= TgEnableMenuItemById(menu, MENU_IMAGEPROC, CanPerformImageProc());
3951 
3952    /* Edit Attribute In Editor */
3953    ok &= TgEnableMenuItemBySubMenuInfoPtr(menu, &editAttrInEditorMenuInfo,
3954          topSel->obj->fattr != NULL);
3955 
3956    /* Edit Attribute Group In Editor */
3957    ok &= TgEnableMenuItemBySubMenuInfoPtr(menu, &editAttrGroupInEditorMenuInfo,
3958          topSel->obj->fattr != NULL && maxAttrGroups > 0);
3959 
3960    /* Get Property */
3961    ok &= TgEnableMenuItemBySubMenuInfoPtr(menu, &getPropertyMenuInfo,
3962          !(topSel->obj->type == OBJ_XPM || (topSel->obj->type == OBJ_XBM &&
3963          topSel->obj->detail.xbm->real_type==XBM_EPS)));
3964 
3965    /* Get Dimension */
3966    ok &= TgEnableMenuItemBySubMenuInfoPtr(menu, &peekDimensionMenuInfo,
3967          topSel != NULL);
3968 
3969    return ok;
3970 }
3971 
CreateContextMenu(parent_menu,X,Y,menu_info,status_str_xlated)3972 TgMenu *CreateContextMenu(parent_menu, X, Y, menu_info, status_str_xlated)
3973    TgMenu *parent_menu;
3974    int X, Y;
3975    TgMenuInfo *menu_info;
3976    int status_str_xlated; /* ignored, always 0 */
3977 {
3978    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, X, Y, menu_info, FALSE);
3979 
3980    if (menu != NULL) {
3981       if (!RefreshContextMenu(menu)) {
3982          return TgDestroyMenu(menu, TRUE);
3983       }
3984       menu->refresh_proc = ((RefreshMenuFunc*)RefreshContextMenu);
3985    }
3986    return menu;
3987 }
3988 
RefreshEditTextContextMenu(menu)3989 int RefreshEditTextContextMenu(menu)
3990    TgMenu *menu;
3991 {
3992    int ok=TRUE;
3993 
3994    /* Copy */
3995    ok &= TgEnableMenuItemById(menu, CMDID_COPY, textHighlight);
3996    /* CopyPlainTextAsObject */
3997    ok &= TgEnableMenuItemById(menu, CMDID_COPYPLAINTEXTASOBJECT,
3998          (curChoice == DRAWTEXT && textHighlight));
3999    /* Cut */
4000    ok &= TgEnableMenuItemById(menu, CMDID_CUT, textHighlight);
4001    /* Duplicate */
4002    ok &= TgEnableMenuItemById(menu, CMDID_DUPLICATE, textHighlight);
4003    /* Delete */
4004    ok &= TgEnableMenuItemById(menu, CMDID_DELETE, textHighlight);
4005 
4006    return ok;
4007 }
4008 
CreateEditTextContextMenu(parent_menu,X,Y,menu_info,status_str_xlated)4009 TgMenu *CreateEditTextContextMenu(parent_menu, X, Y, menu_info,
4010       status_str_xlated)
4011    TgMenu *parent_menu;
4012    int X, Y;
4013    TgMenuInfo *menu_info;
4014    int status_str_xlated; /* ignored, always 0 */
4015 {
4016    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, X, Y, menu_info, FALSE);
4017 
4018    if (menu != NULL) {
4019       if (!RefreshEditTextContextMenu(menu)) {
4020          return TgDestroyMenu(menu, TRUE);
4021       }
4022       menu->refresh_proc = ((RefreshMenuFunc*)RefreshContextMenu);
4023    }
4024    return menu;
4025 }
4026 
ContextMenu(X,Y,TrackMenubar)4027 int ContextMenu(X, Y, TrackMenubar)
4028    int X, Y, TrackMenubar;
4029 {
4030    int rc=INVALID;
4031    TgMenu *menu=NULL;
4032 
4033    if (curChoice == DRAWTEXT && textCursorShown) {
4034       menu = (editTextContextMenuInfo.create_proc)(NULL, X, Y,
4035             &editTextContextMenuInfo, INVALID);
4036    } else {
4037       menu = (baseContextMenuInfo.create_proc)(NULL, X, Y, &baseContextMenuInfo,
4038             INVALID);
4039    }
4040    activeMenu = INVALID;
4041    if (menu != NULL) {
4042       menu->track_menubar = TrackMenubar;
4043 
4044       rc = TgMenuLoop(menu);
4045       TgDestroyMenu(menu, TRUE);
4046    }
4047    return rc;
4048 }
4049 
HandleMotionForPortInDrawWindow(mouse_x,mouse_y)4050 void HandleMotionForPortInDrawWindow(mouse_x, mouse_y)
4051    int mouse_x, mouse_y;
4052 {
4053    int need_to_highlight=FALSE, something_changed=FALSE;
4054    struct ObjRec *owner_obj=NULL, *obj_ptr, *obj_under_cursor=NULL;
4055    char port_name[MAXSTRING];
4056 
4057    obj_ptr = FindAnObj(mouse_x, mouse_y, &owner_obj, &obj_under_cursor,
4058          port_name);
4059    if (drawPolyHighlightedNode != NULL) {
4060       if (obj_under_cursor != drawPolyHighlightedNode) {
4061          /* un-highlight */
4062          SelBox(drawWindow, revGrayGC,
4063                OFFSET_X(drawPolyHighlightedNode->bbox.ltx)-2,
4064                OFFSET_Y(drawPolyHighlightedNode->bbox.lty)-2,
4065                OFFSET_X(drawPolyHighlightedNode->bbox.rbx)+2,
4066                OFFSET_Y(drawPolyHighlightedNode->bbox.rby)+2);
4067          /* do not translate -- program constants */
4068          if (obj_under_cursor != NULL && ObjIsAPort(obj_under_cursor)) {
4069             drawPolyHighlightedNode = obj_under_cursor;
4070             SetWiringNodeInfo(obj_under_cursor, owner_obj, port_name, TRUE);
4071          } else {
4072             drawPolyHighlightedNode = NULL;
4073             SetWiringNodeInfo(NULL, NULL, NULL, TRUE);
4074          }
4075          if (drawPolyHighlightedNode != NULL) {
4076             need_to_highlight = TRUE;
4077          }
4078          something_changed = TRUE;
4079       }
4080    } else if (obj_under_cursor != NULL) {
4081       if (ObjIsAPort(obj_under_cursor)) {
4082          drawPolyHighlightedNode = obj_under_cursor;
4083          SetWiringNodeInfo(obj_under_cursor, owner_obj, port_name, TRUE);
4084       } else {
4085          drawPolyHighlightedNode = NULL;
4086          SetWiringNodeInfo(NULL, NULL, NULL, TRUE);
4087       }
4088       if (drawPolyHighlightedNode != NULL) {
4089          need_to_highlight = TRUE;
4090          something_changed = TRUE;
4091       }
4092    }
4093    if (need_to_highlight) {
4094       SelBox(drawWindow, revGrayGC,
4095             OFFSET_X(drawPolyHighlightedNode->bbox.ltx)-2,
4096             OFFSET_Y(drawPolyHighlightedNode->bbox.lty)-2,
4097             OFFSET_X(drawPolyHighlightedNode->bbox.rbx)+2,
4098             OFFSET_Y(drawPolyHighlightedNode->bbox.rby)+2);
4099    }
4100    if (something_changed) {
4101       if (*gstWiringInfo.first_port_name != '\0') {
4102          char signal_name[MAXSTRING];
4103          struct AttrRec *first_attr_ptr=FindAttrWithName(
4104                gstWiringInfo.first_port_obj, "signal_name=", NULL);
4105 
4106          *signal_name = '\0';
4107          if (first_attr_ptr != NULL) {
4108             UtilStrCpyN(signal_name, sizeof(signal_name),
4109                   first_attr_ptr->attr_value.s);
4110          }
4111          if (gstWiringInfo.num_ports_to_connect == 99) {
4112             /* rename signal_name */
4113             SetHyperSpaceCursor(drawWindow);
4114             sprintf(gszMsgBox,
4115                   TgLoadCachedString(CSTID_SET_SIGNAME_FOR_NAMED_PORT),
4116                   signal_name, gstWiringInfo.first_port_name);
4117          } else if (gstWiringInfo.num_ports_to_connect == 999) {
4118             /* clear signal_name */
4119             SetHyperSpaceCursor(drawWindow);
4120             sprintf(gszMsgBox,
4121                   TgLoadCachedString(CSTID_CLEAR_SIGNAME_FOR_NAMED_PORT),
4122                   signal_name, gstWiringInfo.first_port_name);
4123          } else {
4124             sprintf(gszMsgBox,
4125                   TgLoadCachedString(CSTID_START_A_WIRE_FROM_NAMED_PORT),
4126                   gstWiringInfo.first_port_name);
4127          }
4128          SetStringStatus(gszMsgBox);
4129       } else {
4130          if (gstWiringInfo.num_ports_to_connect == 99 ||
4131                gstWiringInfo.num_ports_to_connect == 999) {
4132             SetHandCursor(drawWindow);
4133          }
4134          ShowCurChoiceMouseStatus(DRAWPOLY, 0, FALSE);
4135       }
4136    }
4137 }
4138 
4139 static int motionCursorIsMoveCursor=FALSE;
4140 
4141 static
HandleMotionInDrawWindow(input)4142 void HandleMotionInDrawWindow(input)
4143    XEvent *input;
4144 {
4145    int mouse_x=0, mouse_y=0, grid_x=0, grid_y=0, cursor_is_move_cursor=FALSE;
4146    int saved_motion_cursor_is_move_cursor=motionCursorIsMoveCursor;
4147    unsigned int state=0;
4148    XEvent ev;
4149 
4150    while (XCheckWindowEvent(mainDisplay,drawWindow,PointerMotionMask,&ev)) ;
4151 
4152    state = (input->xmotion).state;
4153    mouse_x = (input->xmotion).x;
4154    mouse_y = (input->xmotion).y;
4155    GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
4156    simpleMotionInDrawWin = TRUE;
4157    MarkRulers(grid_x, grid_y);
4158    simpleMotionInDrawWin = FALSE;
4159    if (curChoice == DRAWPOLY && gstWiringInfo.num_ports_to_connect > 0) {
4160       HandleMotionForPortInDrawWindow(mouse_x, mouse_y);
4161 #ifdef _NOT_DEFINED
4162    /*
4163     * drawPolyToConnectPins is only set to > 0 in "pin.c"
4164     * what's in "pin.c" is not used at this time
4165     */
4166    } else if (curChoice == DRAWPOLY && drawPolyToConnectPins > 0) {
4167       HandlePinHighlights(mouse_x, mouse_y);
4168       if (drawPolyHighlightedNode != NULL) {
4169          gpStartPin = drawPolyHighlightedNode;
4170       }
4171 #endif /* _NOT_DEFINED */
4172    } else if (!inHyperSpace && !btn1Warp &&
4173          !(inSlideShow && !goHyperSpaceInSlideShow)) {
4174       if (curChoice == DRAWTEXT && textCursorShown && MouseInCurText(input)) {
4175          if (MouseOnCurTextBoundary(input)) {
4176             SetCurChoiceMouseStatusStrings(curChoice, FALSE, NULL, TRUE, state);
4177             cursor_is_move_cursor = TRUE;
4178          } else {
4179             SetCurChoiceMouseStatusStrings(curChoice, FALSE, curTextObj, TRUE,
4180                   state);
4181          }
4182       } else {
4183          struct ObjRec *obj_ptr=NULL, *owner_obj=NULL;
4184 
4185          if ((obj_ptr=FindAnObj(mouse_x, mouse_y, &owner_obj, NULL, NULL)) !=
4186                NULL) {
4187             if (owner_obj != NULL) obj_ptr = owner_obj;
4188          }
4189          ShowCursor();
4190          SetCurChoiceMouseStatusStrings(curChoice, FALSE, obj_ptr, FALSE,
4191                state);
4192       }
4193    } else if (inHyperSpace || btn1Warp) {
4194       struct ObjRec *obj_ptr=NULL, *owner_obj=NULL;
4195       struct AttrRec *attr_ptr=NULL;
4196 
4197       if ((obj_ptr=FindAnObj(mouse_x, mouse_y, &owner_obj, NULL, NULL)) !=
4198             NULL) {
4199          if (owner_obj != NULL) obj_ptr = owner_obj;
4200          /* do not translate -- program constants */
4201          if ((attr_ptr=FindAttrWithName(obj_ptr, TELEPORT_ATTR, NULL)) !=
4202                NULL || (((attr_ptr=FindAttrWithName(obj_ptr, "href=",
4203                NULL)) != NULL) && *attr_ptr->attr_value.s != '\0')) {
4204             char fname[MAXPATHLENGTH+1];
4205 
4206             SetHyperSpaceCursor(drawWindow);
4207             if (FormNewFileName(curDir, attr_ptr->attr_value.s,
4208                   (strcmp(attr_ptr->attr_name.s,TELEPORT_ATTR)==0 ?
4209                   OBJ_FILE_EXT : NULL), fname, NULL)) {
4210                SetStringStatus(fname);
4211             }
4212          } else if ((allowLaunchInHyperSpace &&
4213                (attr_ptr=FindAttrWithName(obj_ptr, LAUNCH_ATTR, NULL)) !=
4214                NULL) || (attr_ptr=FindAttrWithName(obj_ptr, EXEC_ATTR,
4215                NULL)) != NULL) {
4216             SetHyperSpaceCursor(drawWindow);
4217             sprintf(gszMsgBox, "%s%s", attr_ptr->attr_name.s,
4218                   (*attr_ptr->attr_value.s=='\0' ? "..." :
4219                   attr_ptr->attr_value.s));
4220             SetStringStatus(gszMsgBox);
4221          } else {
4222             ShowCursor();
4223             ShowCurChoiceMouseStatus(INVALID, 0, FALSE);
4224          }
4225       } else {
4226          ShowCursor();
4227          ShowCurChoiceMouseStatus(INVALID, 0, FALSE);
4228       }
4229    }
4230    if (cursor_is_move_cursor != saved_motion_cursor_is_move_cursor) {
4231       if (cursor_is_move_cursor) {
4232          XDefineCursor(mainDisplay, drawWindow, moveCursor);
4233       } else {
4234          ShowCursor();
4235       }
4236       motionCursorIsMoveCursor = cursor_is_move_cursor;
4237    }
4238 }
4239 
HandlePressForPortInDrawWindow(cancel)4240 int HandlePressForPortInDrawWindow(cancel)
4241    int cancel;
4242 {
4243    if (drawPolyHighlightedNode != NULL) {
4244       /* un-highlight */
4245       SelBox(drawWindow, revGrayGC,
4246             OFFSET_X(drawPolyHighlightedNode->bbox.ltx)-2,
4247             OFFSET_Y(drawPolyHighlightedNode->bbox.lty)-2,
4248             OFFSET_X(drawPolyHighlightedNode->bbox.rbx)+2,
4249             OFFSET_Y(drawPolyHighlightedNode->bbox.rby)+2);
4250       if (cancel) {
4251          drawPolyHighlightedNode = NULL;
4252          SetWiringNodeInfo(NULL, NULL, NULL, TRUE);
4253       }
4254    }
4255    if (cancel) {
4256       if (connectingPortsByWire) {
4257          MakeQuiescent();
4258          Msg(TgLoadString(STID_CONNECT_PORTS_CANCEL_BY_USER));
4259       }
4260       return FALSE;
4261    }
4262    return TRUE;
4263 }
4264 
4265 static
HandlePressInDrawWindow(input,pn_status)4266 int HandlePressInDrawWindow(input, pn_status)
4267    XEvent *input;
4268    int *pn_status;
4269 {
4270    XButtonEvent *button_ev;
4271 
4272    button_ev = &(input->xbutton);
4273    if (enableMouseWheel &&
4274          (button_ev->button == Button4 || button_ev->button == Button5)) {
4275       if ((button_ev->state & METAMASK) == METAMASK) {
4276          if (button_ev->button == Button4) {
4277             ScrollLeft(button_ev);
4278          } else if (button_ev->button == Button5) {
4279             ScrollRight(button_ev);
4280          }
4281       } else {
4282          if (button_ev->button == Button4) {
4283             ScrollUp(button_ev);
4284          } else if (button_ev->button == Button5) {
4285             ScrollDown(button_ev);
4286          }
4287       }
4288       *pn_status = INVALID;
4289       return TRUE;
4290    }
4291    if ((button_ev->state & ShiftMask) && (button_ev->state & ControlMask)) {
4292       int abs_x=ABS_X(button_ev->x);
4293       int abs_y=ABS_Y(button_ev->y);
4294 
4295       if (button_ev->button == Button1) {
4296          ZoomInAtCursor(abs_x, abs_y);
4297       } else if (button_ev->button == Button2) {
4298          CenterAtCursor(abs_x, abs_y);
4299       } else if (button_ev->button == Button3) {
4300          ZoomOut();
4301       }
4302       *pn_status = INVALID;
4303       return TRUE;
4304    } else if (button_ev->button == Button3 &&
4305          (button_ev->state & ShiftMask)) {
4306       SetCurChoice(NOTHING);
4307       *pn_status = INVALID;
4308       return TRUE;
4309    } else if (button_ev->button == Button2 && curChoice == DRAWTEXT &&
4310          textCursorShown) {
4311       if (((button_ev->state & ControlMask) == ControlMask &&
4312             MouseInCurText(input)) || MouseOnCurTextBoundary(input)) {
4313          MoveEditText(input);
4314          *pn_status = INVALID;
4315       } else if (btn2PopupMainMenu) {
4316          *pn_status = MainMenu();
4317       } else {
4318          *pn_status = INVALID;
4319       }
4320       return TRUE;
4321    } else if ((button_ev->button == Button2 && curChoice == NOTHING &&
4322          (button_ev->state & ShiftMask)) ||
4323          (inHyperSpace && button_ev->button == Button1)) {
4324       Teleport(button_ev);
4325       *pn_status = INVALID;
4326       return TRUE;
4327    } else if (button_ev->button == Button1 && curChoice == NOTHING &&
4328          ((button_ev->state & (ShiftMask | ControlMask)) == 0) &&
4329          btn1Warp) {
4330       Teleport(button_ev);
4331       *pn_status = INVALID;
4332       return TRUE;
4333    } else if (button_ev->button == Button1 && !inHyperSpace && !btn1Warp &&
4334          !(inSlideShow && !goHyperSpaceInSlideShow) && curChoice == DRAWTEXT &&
4335          textCursorShown && MouseOnCurTextBoundary(input)) {
4336       MoveEditText(input);
4337       *pn_status = INVALID;
4338       return TRUE;
4339    } else if (button_ev->button == Button2) {
4340       if (curChoice == DRAWPOLY && gstWiringInfo.num_ports_to_connect > 0) {
4341          return HandlePressForPortInDrawWindow(TRUE);
4342       } else if (btn2PopupMainMenu) {
4343          *pn_status = MainMenu();
4344       } else {
4345          *pn_status = INVALID;
4346       }
4347       return TRUE;
4348    } else if (button_ev->button == Button3) {
4349       /* context-sensitive menu? */
4350       if (curChoice == DRAWPOLY && gstWiringInfo.num_ports_to_connect > 0) {
4351          return HandlePressForPortInDrawWindow(TRUE);
4352       }
4353       if (btn3PopupModeMenu) {
4354          ModeMenu(button_ev->x_root, button_ev->y_root, FALSE);
4355       } else if (!inHyperSpace &&
4356             !(inSlideShow && !goHyperSpaceInSlideShow)) {
4357          if (curChoice == DRAWTEXT && textCursorShown &&
4358                MouseInCurText(input)) {
4359             ContextMenu(button_ev->x_root, button_ev->y_root, FALSE);
4360          } else {
4361             struct ObjRec *obj_ptr=NULL, *owner_obj=NULL;
4362 
4363             if ((obj_ptr=FindAnObj(button_ev->x, button_ev->y, &owner_obj,
4364                   NULL, NULL)) != NULL) {
4365                if (owner_obj != NULL) obj_ptr = owner_obj;
4366             }
4367             if (obj_ptr == NULL) {
4368                ModeMenu(button_ev->x_root, button_ev->y_root, FALSE);
4369             } else {
4370                int obj_may_not_exist=FALSE;
4371 
4372                if (curChoice == DRAWTEXT && textCursorShown &&
4373                      obj_ptr == curTextObj) {
4374                   obj_may_not_exist = TRUE;
4375                }
4376                if (!(topSel != NULL && topSel == botSel &&
4377                      topSel->obj == obj_ptr)) {
4378                   TieLooseEnds();
4379                   if (obj_may_not_exist && textDrawn) {
4380                      obj_may_not_exist = FALSE;
4381                   }
4382                   SetCurChoice(NOTHING);
4383                   if (topSel != NULL) {
4384                      HighLightReverse();
4385                      RemoveAllSel();
4386                   }
4387                   if (obj_may_not_exist) {
4388                      UpdSelBBox();
4389                   } else {
4390                      AddNewSelObj(obj_ptr);
4391                      UpdSelBBox();
4392                      justDupped = FALSE;
4393                      HighLightForward();
4394                   }
4395                }
4396                ContextMenu(button_ev->x_root, button_ev->y_root, FALSE);
4397             }
4398          }
4399       } else if (inSlideShow) {
4400          SlideShowModeMenu(button_ev->x_root, button_ev->y_root, FALSE);
4401       }
4402       *pn_status = INVALID;
4403       return TRUE;
4404    }
4405    return FALSE;
4406 }
4407 
DrawingEventHandler(input)4408 int DrawingEventHandler(input)
4409    XEvent *input;
4410 {
4411    XEvent ev;
4412 
4413    if (input->type == Expose) {
4414       XSync(mainDisplay, False);
4415       while (XCheckWindowEvent(mainDisplay, drawWindow, ExposureMask, &ev)) ;
4416 
4417       if (topSel != NULL || curChoice == VERTEXMODE || SomethingDirty()) {
4418          ClearAndRedrawDrawWindow();
4419       } else {
4420          RedrawDrawWindow(botObj);
4421          ResetDirtyBBoxInfo();
4422          RedrawCurText();
4423       }
4424       return INVALID;
4425    } else if (input->type == ClientMessage) {
4426       if (curChoice == DRAWTEXT && canvasFontDoubleByte &&
4427             textCursorShown && tgIMExpectClientMessage(mainDisplay,
4428             drawWindow)) {
4429          if (tgIMHandleClientMessage(mainDisplay,
4430                drawWindow, (XClientMessageEvent*)input, NULL, NULL)) {
4431          }
4432       }
4433       return INVALID;
4434    } else if (input->type == EnterNotify) {
4435       if (input->xcrossing.mode == NotifyNormal) {
4436          RestoreDrawWinDrawTextInfo(FALSE);
4437          if (curChoice == DRAWTEXT && textCursorShown) {
4438             tgIMFocusIn(mainDisplay, drawWindow);
4439          }
4440       }
4441       ShowCurChoiceMouseStatus(curChoice, 0, FALSE);
4442       return INVALID;
4443    } else if (input->type == LeaveNotify) {
4444       EndMeasureTooltip(FALSE);
4445 
4446       if (input->xcrossing.mode == NotifyNormal) {
4447          SaveDrawWinDrawTextInfo(FALSE);
4448          if (curChoice == DRAWTEXT && textCursorShown) {
4449             tgIMFocusOut(mainDisplay, drawWindow);
4450          }
4451       }
4452       return INVALID;
4453    } else if (input->type == MotionNotify) {
4454       HandleMotionInDrawWindow(input);
4455       return INVALID;
4456    }
4457 
4458    if (input->type == ButtonPress) {
4459       int rc=INVALID;
4460 
4461       EndMeasureTooltip(FALSE);
4462       if (HandlePressInDrawWindow(input, &rc)) {
4463          return rc;
4464       }
4465       Msg("");
4466    }
4467    if (input->type == KeyPress && inSlideShow && !goHyperSpaceInSlideShow) {
4468       XKeyEvent *key_ev=(&(input->xkey));
4469       KeySym key_sym=(KeySym)0;
4470       char buf[80];
4471       int has_ch=XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
4472 
4473       TranslateKeys(buf, &key_sym);
4474       if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
4475          LeaveSlideShow();
4476          return INVALID;
4477       } else if (CharIsCRorLF(key_ev, buf, key_sym, &has_ch)) {
4478          /*
4479           * For now, this only goes to the next page.  In the future,
4480           *         this would single step.
4481           */
4482          NextSlide();
4483          return INVALID;
4484       } else if (key_sym == XK_Left || key_sym == XK_KP_Left ||
4485             key_sym == XK_Up || key_sym == XK_KP_Up ||
4486             key_sym == XK_Right || key_sym == XK_KP_Right ||
4487             key_sym == XK_Down || key_sym == XK_KP_Down) {
4488          switch (key_sym) {
4489          case XK_Left: PrevSlide(); break;
4490          case XK_KP_Left: PrevSlide(); break;
4491          case XK_Up: PrevSlide(); break;
4492          case XK_KP_Up: PrevSlide(); break;
4493          case XK_Right: NextSlide(); break;
4494          case XK_KP_Right: NextSlide(); break;
4495          case XK_Down: NextSlide(); break;
4496          case XK_KP_Down: NextSlide(); break;
4497          }
4498          return INVALID;
4499       } else if (key_sym == XK_Page_Up || key_sym == XK_KP_Page_Up ||
4500             key_sym == XK_Page_Down || key_sym == XK_KP_Page_Down) {
4501          switch (key_sym) {
4502          case XK_Page_Up: PrevSlide(); break;
4503          case XK_KP_Page_Up: PrevSlide(); break;
4504          case XK_Page_Down: NextSlide(); break;
4505          case XK_KP_Page_Down: NextSlide(); break;
4506          }
4507          return INVALID;
4508       }
4509    }
4510    switch(curChoice) {
4511    case NOTHING: Select(input); break;
4512    case DRAWTEXT: DrawText(input); break;
4513    case DRAWBOX: DrawBox(input); break;
4514    case DRAWCORNEROVAL: DrawOval(input); break;
4515    case DRAWCENTEROVAL: DrawOval(input); break;
4516    case DRAWEDGECIRCLE: DrawOval(input); break;
4517    case DRAWPOLY: DrawPoly(input); break;
4518    case DRAWPOLYGON: DrawPolygon(input); break;
4519    case DRAWARC: DrawArc(input); break;
4520    case DRAWEDGEARC: DrawArc(input); break;
4521    case DRAWRCBOX: DrawRCBox(input); break;
4522    case FREEHAND: DrawPoly(input); break;
4523    case VERTEXMODE: Select(input); break;
4524    case ROTATEMODE: Select(input); break;
4525    }
4526    return INVALID;
4527 }
4528 
4529