1 /*
2 Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9     - Redistributions of source code must retain the above copyright
10       notice, this list of conditions and the following disclaimer.
11 
12     - Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the
15       distribution.
16 
17     - Neither the name of The Numerical ALgorithms Group Ltd. nor the
18       names of its contributors may be used to endorse or promote products
19       derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 #define _CONTROL2D_C
35 #include "fricas_c_macros.h"
36 
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <X11/X.h>
42 #include <X11/Xlib.h>
43 #include <X11/Xutil.h>
44 
45 #include "header2.h"
46 #include "buttons2d.H1"
47 #include "all_2d.H1"
48 #include "Gfun.H1"
49 #include "XSpadFill.H1"
50 #include "util.H1"
51 #include "strutil.h"
52 
53 #include "mouse11.bitmap"
54 #include "mouse11.mask"
55 
56 /* Defines the pixmap for the arrow displayed in the scale window */
57 
58 #define scaleArrowN 11
59 static XPoint scaleArrow[scaleArrowN] = {
60   {55,14},{64,23},{59,23},
61   {66,45},{79,45},
62   {55,69},
63   {31,45},{44,45},
64   {51,23},{46,23},{55,14} };
65 
66 /* Defines the pixmap for the arrows displayed in the translate window */
67 
68 #define translateArrowN 25
69 static XPoint translateArrow[translateArrowN] = {
70   {55,2},{60,10},{58,10},{58,37},
71   {85,37},{85,35},{93,40},{85,45},{85,43},{58,43},
72   {58,70},{60,70},{55,78},{50,70},{52,70},{52,43},
73   {25,43}, {25,45}, {17,40},  {25,35}, {25,37}, {52,37},
74   {52,10},{50,10},{55,2} };
75 
76 /****************************
77  * void writeControlTitle() *
78  ****************************/
79 
80 void
writeControlTitle(void)81 writeControlTitle(void)
82 {
83 
84   int strlength;
85 
86   s = viewport->title;
87   strlength = strlen(s);
88   XClearArea(dsply,control->controlWindow,0,0,controlWidth,potA,False);
89   GSetForeground(anotherGC,(float)controlTitleColor,Xoption);
90   GDrawImageString(anotherGC,control->controlWindow,
91                    centerX(anotherGC,s,strlength,controlWidth),
92                    15,s,strlength,Xoption);
93 
94 } /* writeControlTitle() */
95 
96 void
makeMessageFromData(int whichGraph)97 makeMessageFromData(int whichGraph)
98 {
99   if (viewport->haveControl) {
100     if ((graphStateArray[whichGraph].scaleX) > 99.0) {
101       strcpy(scaleXReport,"big");
102     } else {
103       fricas_sprintf_to_buf1(scaleXReport, "%4.1f",
104                              graphStateArray[whichGraph].scaleX);
105     }
106     if ((graphStateArray[whichGraph].scaleY) > 99.0) {
107       strcpy(scaleYReport,"big");
108     } else {
109       fricas_sprintf_to_buf1(scaleYReport, "%4.1f",
110                              graphStateArray[whichGraph].scaleY);
111     }
112     if ((graphStateArray[whichGraph].centerX) > 999.0) {
113       strcpy(deltaXReport,"+big");
114     } else if ((graphStateArray[whichGraph].centerX) < -999.0) {
115       strcpy(deltaXReport,"-big");
116     } else {
117       fricas_sprintf_to_buf1(deltaXReport, "%4.0f",
118               -graphStateArray[whichGraph].centerX /
119               graphArray[whichGraph].unitX);
120     }
121     if ((graphStateArray[whichGraph].centerY) > 999.0) {
122       strcpy(deltaYReport,"+big");
123     } else if ((graphStateArray[whichGraph].centerY) < -999.0) {
124       strcpy(deltaYReport,"-big");
125     } else {
126       fricas_sprintf_to_buf1(deltaYReport, "%4.0f",
127               -graphStateArray[whichGraph].centerY /
128               graphArray[whichGraph].unitY);
129     }
130     sprintf(viewport->controlPanel->message,"[%s,%s] >%d< [%s,%s]",
131             scaleXReport,scaleYReport,whichGraph+1,deltaXReport,deltaYReport);
132   }  /* if haveControl */
133 
134 } /* makeMessageFromData() */
135 
136 
137 void
writeControlMessage(void)138 writeControlMessage(void)
139 {
140   int                strlength;
141   controlPanelStruct *cp;
142   XWindowAttributes  cwInfo;
143 
144   cp = viewport->controlPanel;
145   XGetWindowAttributes(dsply,cp->controlWindow,&cwInfo);
146   strlength = strlen(cp->message);
147 
148 
149 
150   GDrawImageString(controlMessageGC,cp->controlWindow,
151                    centerX(globalGC1,cp->message,strlength,controlWidth),
152                    controlMessageY + globalFont->max_bounds.ascent - 2,
153                    cp->message,strlength,Xoption);
154 }
155 
156 /*********************************/
157 /***  void drawControlPanel()  ***/
158 /*********************************/
159 
160 void
drawControlPanel(void)161 drawControlPanel(void)
162 {
163 
164   controlPanelStruct *cp;
165   int i,strlength;
166   char *s;
167 
168   cp = viewport->controlPanel;
169   /* Draw border lines to separate the potentiometer, message, graph select
170      and button regions of the control panel. */
171   GSetForeground(trashGC,(float)foregroundColor,Xoption);
172   GSetLineAttributes(trashGC,3,LineSolid,CapButt,JoinMiter,Xoption);
173   GDrawLine(trashGC, cp->controlWindow, 0, potA, controlWidth, potA, Xoption);
174   GSetLineAttributes(trashGC,2,LineSolid,CapButt,JoinMiter,Xoption);
175   GDrawLine(trashGC, cp->controlWindow, 0, potB, controlWidth, potB, Xoption);
176   GDrawLine(trashGC, cp->controlWindow, 0, messageBot,
177             controlWidth, messageBot, Xoption);
178   GDrawLine(trashGC, cp->controlWindow, 0, 286, controlWidth, 286, Xoption);
179 
180   /** put the line width as 1 last because used below as well **/
181   GSetLineAttributes(trashGC,1,LineSolid,CapButt,JoinMiter,Xoption);
182   GDrawRectangle(trashGC,cp->controlWindow,closeLeft,closeTop,
183                  (controlWidth-closeLeft+8),(controlHeight-closeTop+8),Xoption);
184 
185   /* Write potentiometer titles on the control panel. */
186   writeControlTitle();
187   GSetForeground(globGC,(float)controlPotHeaderColor,Xoption);
188   s = "Scale";
189   strlength = strlen(s);
190   GDrawString(globGC,cp->controlWindow,
191               centerX(globGC,s,strlength,
192                       cp->buttonQueue[scale2D].buttonWidth) +
193               cp->buttonQueue[scale2D].buttonX, 31+headerHeight,s,strlength,Xoption);
194 
195   s = "Translate";
196   strlength = strlen(s);
197   GDrawString(globGC,cp->controlWindow,
198               centerX(globGC,s,strlength,
199                       cp->buttonQueue[translate2D].buttonWidth) +
200               cp->buttonQueue[translate2D].buttonX,
201               31+headerHeight,s,strlen(s),Xoption);
202 
203   GSetForeground(globGC,(float)controlColorColor,Xoption);
204 
205   /* Write title of the graph selection window. */
206   s = "Graphs";
207   strlength = strlen(s);
208   GDrawString(globGC,cp->controlWindow,
209               centerX(globGC,s,strlength,controlWidth),graphHeaderHeight,
210               s,strlength,Xoption);
211 
212   /* Write titles on regular buttons and draw pixmaps on potentiometers. */
213 
214   for (i=0; i<(maxButtons2D); i++) {
215     if ((cp->buttonQueue[i]).pot) {
216 
217       GSetForeground(globalGC1,(float)buttonColor,Xoption);
218       GDrawRectangle(globalGC1,cp->controlWindow,
219                      (cp->buttonQueue[i]).buttonX,
220                      (cp->buttonQueue[i]).buttonY,
221                      (cp->buttonQueue[i]).buttonWidth,
222                      (cp->buttonQueue[i]).buttonHeight,Xoption);
223 
224       GSetForeground(trashGC,
225                      (float)monoColor((cp->buttonQueue[i]).textColor),Xoption);
226 
227       GDrawLine(globalGC1,cp->controlWindow, /* trashGC, */
228                 (cp->buttonQueue[i]).buttonX + (cp->buttonQueue[i]).xHalf,
229                 (cp->buttonQueue[i]).buttonY,
230                 (cp->buttonQueue[i]).buttonX + (cp->buttonQueue[i]).xHalf,
231                 (cp->buttonQueue[i]).buttonY + 2*(cp->buttonQueue[i]).yHalf,Xoption);
232       GDrawLine(globalGC1,cp->controlWindow, /* trashGC, */
233                 (cp->buttonQueue[i]).buttonX,
234                 (cp->buttonQueue[i]).buttonY + (cp->buttonQueue[i]).yHalf,
235                 (cp->buttonQueue[i]).buttonX + 2*(cp->buttonQueue[i]).xHalf,
236                 (cp->buttonQueue[i]).buttonY + (cp->buttonQueue[i]).yHalf,Xoption);
237       switch (i) {
238       case scale2D:
239         GDrawLines(trashGC,cp->controlWindow,scaleArrow,
240                    scaleArrowN,CoordModeOrigin,Xoption);
241         break;
242       case translate2D:
243         GDrawLines(trashGC,cp->controlWindow,translateArrow,
244                    translateArrowN,CoordModeOrigin,Xoption);
245         break;
246       } /* switch i */
247     } else if (cp->buttonQueue[i].graphNum) {
248 
249       if (mono) {
250         if (graphStateArray[i-graphStart].showing) {
251           GSetForeground(graphGC,(float)backgroundColor,Xoption);
252           GSetBackground(graphGC,(float)foregroundColor,Xoption);
253         } else {
254           GSetForeground(graphGC,(float)foregroundColor,Xoption);
255           GSetBackground(graphGC,(float)backgroundColor,Xoption);
256         }
257         strlength = strlen((cp->buttonQueue[i]).text);
258         GDrawImageString(graphGC,cp->controlWindow,
259                          (cp->buttonQueue[i]).buttonX +
260                          centerX(graphGC,cp->buttonQueue[i].text,
261                                  strlength,(cp->buttonQueue[i]).buttonWidth),
262                          (cp->buttonQueue[i]).buttonY +
263                          centerY(graphGC,(cp->buttonQueue[i]).buttonHeight),
264                          cp->buttonQueue[i].text,strlength,Xoption);
265       } else {
266         if (graphStateArray[i-graphStart].showing)
267           GSetForeground(graphGC,(float)graphBarShowingColor,Xoption);
268         else
269           GSetForeground(graphGC,(float)graphBarHiddenColor,Xoption);
270         strlength = strlen((cp->buttonQueue[i]).text);
271         GDrawString(graphGC,cp->controlWindow,
272                     (cp->buttonQueue[i]).buttonX +
273                     centerX(graphGC,cp->buttonQueue[i].text,
274                             strlength,(cp->buttonQueue[i]).buttonWidth),
275                     (cp->buttonQueue[i]).buttonY +
276                     centerY(graphGC,(cp->buttonQueue[i]).buttonHeight),
277                     cp->buttonQueue[i].text,strlength,Xoption);
278         }
279     } else if (cp->buttonQueue[i].graphSelect) {
280       /* The select characters are defined as: "^" for on and "-" for off. */
281       if (graphStateArray[i-graphSelectStart].selected) {
282         GSetForeground(graphGC,(float)graphBarSelectColor,Xoption);
283         strcpy((cp->buttonQueue[i]).text,"^");
284       } else {
285         GSetForeground(graphGC,(float)graphBarNotSelectColor,Xoption);
286         *(cp->buttonQueue[i]).text = '-';
287         strcpy((cp->buttonQueue[i]).text,"-");
288       }
289        GDrawString(graphGC,cp->controlWindow,
290                  (cp->buttonQueue[i]).buttonX +
291                  centerX(graphGC,cp->buttonQueue[i].text,
292                          strlength,(cp->buttonQueue[i]).buttonWidth),
293                  (cp->buttonQueue[i]).buttonY +
294                  centerY(graphGC,(cp->buttonQueue[i]).buttonHeight),
295                  cp->buttonQueue[i].text,strlength,Xoption);
296     }
297     else {  /* a regular button */
298       int isOn = 1;
299 
300       switch(i) {
301         case pointsOnOff:
302           isOn = pointsON = graphStateArray[0].pointsOn;
303           if (graphStateArray[0].pointsOn)
304             strcpy((cp->buttonQueue[i]).text,"Pts On ");
305           else
306             strcpy((cp->buttonQueue[i]).text,"Pts Off");
307           break;
308 
309         case spline2D:
310           isOn = splineON = graphStateArray[0].splineOn;
311           if (graphStateArray[0].splineOn)
312             strcpy((cp->buttonQueue[i]).text, "Box On ");
313           else
314             strcpy((cp->buttonQueue[i]).text, "Box Off");
315           break;
316 
317         case connectOnOff:
318           isOn = connectON = graphStateArray[0].connectOn;
319           if (graphStateArray[0].connectOn)
320             strcpy((cp->buttonQueue[i]).text, "Lines On ");
321           else
322             strcpy((cp->buttonQueue[i]).text, "Lines Off");
323           break;
324 
325         case axesOnOff2D:
326           isOn = axesON = graphStateArray[0].axesOn;
327           if (graphStateArray[0].axesOn)
328             strcpy((cp->buttonQueue[i]).text , "Axes On ");
329           else
330             strcpy((cp->buttonQueue[i]).text , "Axes Off");
331           break;
332 
333         case unitsOnOff2D:
334           isOn = unitsON = graphStateArray[0].unitsOn;
335           if (graphStateArray[0].unitsOn)
336            strcpy( (cp->buttonQueue[i]).text , "Units On ");
337           else
338            strcpy( (cp->buttonQueue[i]).text , "Units Off");
339           break;
340         case closeAll2D:
341           isOn = 0;
342 
343         default:
344           break;
345       } /* switch i */
346 
347       s = (cp->buttonQueue[i]).text;
348       strlength = strlen(s);
349 
350       GDrawPushButton(dsply, globalGC1, trashGC, processGC, cp->controlWindow,
351           (cp->buttonQueue[i]).buttonX, (cp->buttonQueue[i]).buttonY,
352           (cp->buttonQueue[i]).buttonWidth, (cp->buttonQueue[i]).buttonHeight,
353           isOn, s,buttonColor,
354           monoColor((cp->buttonQueue[i]).textColor), Xoption);
355 
356     } /* else a regular button */
357   } /* for each button */
358 
359   /* Refresh the latest message */
360   makeMessageFromData(0);
361   writeControlMessage();
362   XFlush(dsply);
363 
364 }    /*** drawControlPanel ***/
365 
366 controlXY
getControlXY(int whereDoYouWantPanel)367 getControlXY(int whereDoYouWantPanel)
368 {
369   XWindowAttributes wAttr, wAttrib;
370   controlXY         cXY;
371   int               tmp=1;
372   Window            rootW, parentW, *childrenWs, tmpW;
373   unsigned int      nChildren;
374 
375   tmpW = viewport->titleWindow;
376   while(tmp) {
377     XQueryTree(dsply,tmpW,&rootW,&parentW,&childrenWs,&nChildren);
378     XFree(childrenWs);
379     if (parentW == rtWindow) tmp = 0;
380     else tmpW = parentW;
381   }
382   XGetWindowAttributes(dsply,tmpW,&wAttrib);
383 
384   XGetWindowAttributes(dsply,viewport->titleWindow,&wAttr);
385   if (whereDoYouWantPanel) {
386     switch (whereDoYouWantPanel) {
387     case 1: /* right */
388       cXY.putX = wAttrib.x + wAttrib.width;
389       cXY.putY = wAttrib.y;
390       break;
391     case 2: /* bottom */
392       cXY.putX = wAttrib.x + (wAttr.width - controlWidth)/2;  /* center it */
393       cXY.putY = wAttrib.y + wAttrib.height;
394       break;
395     case 3: /* left */
396       cXY.putX = wAttrib.x - controlWidth - borderWidth;
397       cXY.putY = wAttrib.y;
398       break;
399     case 4: /* top */
400       cXY.putX = wAttrib.x + (wAttr.width - controlWidth)/2;
401       cXY.putY = wAttrib.y - controlHeight - borderHeight;
402     }
403   } else {
404     if ((physicalWidth - (wAttrib.x + wAttr.width)) >= controlWidth) {
405       cXY.putX = wAttrib.x + wAttrib.width;
406       cXY.putY = wAttrib.y;
407     } else if ((physicalHeight - (wAttrib.y + wAttr.height)) >=
408                controlHeight) {
409       cXY.putX = wAttrib.x + (wAttr.width - controlWidth)/2;
410       cXY.putY = wAttrib.y + wAttrib.height;
411     } else if (wAttrib.x >= controlWidth) {
412       cXY.putX = wAttrib.x - controlWidth - borderWidth;
413       cXY.putY = wAttrib.y;
414     } else if (wAttrib.y >= controlHeight) {
415       cXY.putX = wAttrib.x + (wAttr.width - controlWidth)/2;
416       cXY.putY = wAttrib.y - controlHeight - borderHeight;
417     } else {                       /* put inside of viewport */
418       cXY.putX = wAttrib.x + wAttr.width - controlWidth;
419       cXY.putY = wAttrib.y + wAttr.height - controlHeight;
420     }
421   }
422   return(cXY);
423 
424 }
425 
426 /************************************************/
427 /***  controlPanelStruct *makeControlPanel()  ***/
428 /************************************************/
429 
430 controlPanelStruct *
makeControlPanel(void)431 makeControlPanel(void)
432 {
433 
434   Window cw;
435   int                  i,num;
436   controlPanelStruct   *control;
437   buttonStruct         *buttons;
438   controlXY            cXY;
439   XSetWindowAttributes cwAttrib, controlAttrib;
440   XSizeHints           sizehints;
441   Pixmap               mousebits,mousemask;
442   XColor               foreColor, backColor;
443 
444   if (!(control = (controlPanelStruct *)malloc(sizeof(controlPanelStruct)))) {
445     fprintf(stderr,"Ran out of memory trying to create a control panel.\n");
446     exitWithAck(RootWindow(dsply,scrn),Window,-1);
447   }
448 
449   cXY = getControlXY(0);
450 
451   /* Define and assign a mouse cursor. */
452   mousebits = XCreateBitmapFromData(dsply,rtWindow,mouseBitmap_bits,
453                                     mouseBitmap_width,mouseBitmap_height);
454   mousemask = XCreateBitmapFromData(dsply,rtWindow,mouseMask_bits,
455                                     mouseMask_width,mouseMask_height);
456   cwAttrib.background_pixel = backgroundColor; /* controlBackground; */
457   cwAttrib.border_pixel = foregroundColor;
458   cwAttrib.backing_store = WhenMapped;
459   cwAttrib.event_mask = controlMASK;
460   cwAttrib.colormap = colorMap;
461   cwAttrib.override_redirect = overrideManager;
462   foreColor.pixel = controlCursorForeground;
463   XQueryColor(dsply,colorMap,&foreColor);
464   backColor.pixel = controlCursorBackground;
465   XQueryColor(dsply,colorMap,&backColor);
466   cwAttrib.cursor = XCreatePixmapCursor(dsply,mousebits,mousemask,
467                                         &foreColor,&backColor,
468                                         mouseBitmap_x_hot,mouseBitmap_y_hot);
469 
470   cw = XCreateWindow(dsply,rtWindow,
471                      cXY.putX,cXY.putY,controlWidth,controlHeight,3,
472                      CopyFromParent,InputOutput,CopyFromParent,
473                      controlCreateMASK,&cwAttrib);
474 
475   sizehints.flags  = PPosition | PSize;
476   sizehints.x      = cXY.putX;
477   sizehints.y      = cXY.putY;
478   sizehints.width  = controlWidth;
479   sizehints.height = controlHeight;
480 
481   /*** the None stands for icon pixmap...change.... ***/
482 
483   XSetNormalHints(dsply,cw,&sizehints);
484   XSetStandardProperties(dsply,cw,"2D Control Panel","2D Control Panel",
485                          None,NULL,0,&sizehints);
486 
487   control->controlWindow = cw;
488   num = initButtons(control->buttonQueue);
489   control->numOfButtons = num;
490   buttons = control->buttonQueue;
491 
492   for (i=0; i<num; i++) {
493     controlAttrib.event_mask = (control->buttonQueue[i]).mask;
494     (control->buttonQueue[i]).self = XCreateWindow(dsply,cw,
495                                        (control->buttonQueue[i]).buttonX,
496                                        (control->buttonQueue[i]).buttonY,
497                                        (control->buttonQueue[i]).buttonWidth,
498                                        (control->buttonQueue[i]).buttonHeight,
499                                        0,0,InputOnly,CopyFromParent,
500                                        buttonCreateMASK,&controlAttrib);
501 
502     XMakeAssoc(dsply,table,(control->buttonQueue[i]).self,
503                &((control->buttonQueue[i]).buttonKey));
504    /* Use buttonKey instead of i because buttonKey has a permanent address */
505     XMapWindow(dsply,(control->buttonQueue[i]).self);
506   }
507 
508            /* Create message window */
509   control->messageWindow = XCreateWindow(dsply,cw,0,controlMessageY,
510                                          controlWidth,controlMessageHeight,
511                                          0,0,InputOnly,CopyFromParent,
512                                          messageCreateMASK,&cwAttrib);
513   XMapWindow(dsply,control->messageWindow);
514 
515   for (i=0; i<scaleArrowN; i++) {
516     scaleArrow[i].x += buttons[scale2D].buttonX;
517     scaleArrow[i].y += buttons[scale2D].buttonY;
518   }
519   for (i=0; i<translateArrowN; i++) {
520     translateArrow[i].x += buttons[translate2D].buttonX;
521     translateArrow[i].y += buttons[translate2D].buttonY;
522   }
523 
524   viewport->justMadeControl = yes;
525   return(control);
526 
527 } /* makeControlPanel() */
528 
529 
530 
531 
532 
533 
534 /*****************************************/
535 /***  void putControlPanelSomewhere()  ***/
536 /*****************************************/
537 
538 /* This routine puts up the control panel associated with the viewport
539    passed in.  It first tries to put it to the right of the viewport. If
540    there isn't enough room there, it tries the bottom and so on going
541    clockwise. If the viewport is too big and there is no room to put the
542    control panel outside of it, it placed the control panel in the bottom
543    right hand corner of the viewport window. */
544 
545 void
putControlPanelSomewhere(int whereDoesPanelGo)546 putControlPanelSomewhere(int whereDoesPanelGo)
547 {
548   controlPanelStruct *control;
549   controlXY          whereControl;
550 
551   control = viewport->controlPanel;
552   whereControl = getControlXY(whereDoesPanelGo);
553 
554   viewport->haveControl = yes;
555 
556   XRaiseWindow(dsply,control->controlWindow);
557   XMoveWindow(dsply,control->controlWindow,whereControl.putX,
558               whereControl.putY);
559 
560   drawControlPanel();
561   if (viewport->justMadeControl) {
562     XMapWindow(dsply,control->controlWindow);
563     viewport->justMadeControl = no;
564   }
565   XMapWindow(dsply,control->controlWindow);
566 }
567 
568 
569 
570 
571 
572 /************************************/
573 /***  void clearControlMessage()  ***/
574 /************************************/
575 
576 void
clearControlMessage(void)577 clearControlMessage(void)
578 {
579 
580   strcpy(viewport->controlPanel->message,"");
581 
582   XClearArea(dsply,viewport->controlPanel->controlWindow,
583              0,controlMessageY-2,controlWidth,controlMessageHeight,False);
584 }
585