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