True graphical promotion popup for XBoard
[xboard.git] / xengineoutput.c
1 /*
2  * Engine output (PV)
3  *
4  * Author: Alessandro Scotti (Dec 2005)
5  *
6  * Copyright 2005 Alessandro Scotti
7  *
8  * Enhancements Copyright 2009 Free Software Foundation, Inc.
9  *
10  * ------------------------------------------------------------------------
11  *
12  * GNU XBoard is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, either version 3 of the License, or (at
15  * your option) any later version.
16  *
17  * GNU XBoard is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see http://www.gnu.org/licenses/.
24  *
25  * ------------------------------------------------------------------------
26  ** See the file ChangeLog for a revision history.  */
27
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <sys/types.h>
34
35 #if STDC_HEADERS
36 # include <stdlib.h>
37 # include <string.h>
38 #else /* not STDC_HEADERS */
39 extern char *getenv();
40 # if HAVE_STRING_H
41 #  include <string.h>
42 # else /* not HAVE_STRING_H */
43 #  include <strings.h>
44 # endif /* not HAVE_STRING_H */
45 #endif /* not STDC_HEADERS */
46
47 #if HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50
51 #include <X11/Intrinsic.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Shell.h>
54 #include <X11/Xaw/Dialog.h>
55 #include <X11/Xaw/Form.h>
56 #include <X11/Xaw/List.h>
57 #include <X11/Xaw/Label.h>
58 #include <X11/Xaw/SimpleMenu.h>
59 #include <X11/Xaw/SmeBSB.h>
60 #include <X11/Xaw/SmeLine.h>
61 #include <X11/Xaw/Box.h>
62 #include <X11/Xaw/Paned.h>
63 #include <X11/Xaw/MenuButton.h>
64 #include <X11/cursorfont.h>
65 #include <X11/Xaw/Text.h>
66 #include <X11/Xaw/AsciiText.h>
67 #include <X11/Xaw/Viewport.h>
68 #include <X11/Xatom.h>
69 #include <X11/Xmu/Atoms.h>
70
71 #include "common.h"
72 #include "frontend.h"
73 #include "backend.h"
74 #include "xboard.h"
75 #include "engineoutput.h"
76 #include "gettext.h"
77
78 #ifdef ENABLE_NLS
79 # define  _(s) gettext (s)
80 # define N_(s) gettext_noop (s)
81 #else
82 # define  _(s) (s)
83 # define N_(s)  s
84 #endif
85
86 #include <X11/xpm.h>
87
88 // [HGM] pixmaps of some ICONS used in the engine-outut window
89 #include "pixmaps/WHITE_14.xpm"
90 #include "pixmaps/BLACK_14.xpm"
91 #include "pixmaps/CLEAR_14.xpm"
92 #include "pixmaps/UNKNOWN_14.xpm"
93 #include "pixmaps/THINKING_14.xpm"
94 #include "pixmaps/PONDER_14.xpm"
95 #include "pixmaps/ANALYZING_14.xpm"
96
97 #ifdef SNAP
98 #include "wsnap.h"
99 #endif
100
101 #define _LL_ 100
102
103 // imports from xboard.c
104 extern Widget formWidget, boardWidget, menuBarWidget;
105 extern Window xBoardWindow;
106 extern int squareSize;
107 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
108 extern char *layoutName;
109
110 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
111 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
112
113 void EngineOutputPopDown();
114 void engineOutputPopUp();
115 int  EngineOutputIsUp();
116 void SetEngineColorIcon( int which );
117
118 /* Imports from backend.c */
119 extern int opponentKibitzes;
120
121 /* Imports from xboard.c */
122 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
123
124 //extern WindowPlacement wpEngineOutput;
125
126 Position engineOutputX = -1, engineOutputY = -1;
127 Dimension engineOutputW, engineOutputH;
128 Widget engineOutputShell;
129 static int engineOutputDialogUp;
130
131 /* Module variables */
132 int  windowMode = 1;
133
134 typedef struct {
135     char * name;
136     int which;
137     int depth;
138     u64 nodes;
139     int score;
140     int time;
141     char * pv;
142     char * hint;
143     int an_move_index;
144     int an_move_count;
145 } EngineOutputData;
146
147 //static void UpdateControls( EngineOutputData * ed );
148
149 void ReadIcon(char *pixData[], int iconNr)
150 {
151     int r;
152
153 //      if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
154 //                                     pixData,
155 //                                     &(icons[iconNr]),
156 //                                     NULL, NULL /*&attr*/)) != 0) {
157 //        fprintf(stderr, _("Error %d loading icon image\n"), r);
158 //        exit(1); 
159 //      }       
160 }
161
162 static void InitializeEngineOutput()
163 { int i;
164
165         ReadIcon(WHITE_14,   nColorWhite);
166         ReadIcon(BLACK_14,   nColorBlack);
167         ReadIcon(UNKNOWN_14, nColorUnknown);
168
169         ReadIcon(CLEAR_14,   nClear);
170         ReadIcon(PONDER_14,  nPondering);
171         ReadIcon(THINK_14,   nThinking);
172         ReadIcon(ANALYZE_14, nAnalyzing);
173 }
174
175 void DoSetWindowText(int which, int field, char *s_label)
176
177         Arg arg;
178
179         XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
180         XtSetValues(outputField[which][field], &arg, 1);
181 }
182
183 void InsertIntoMemo( int which, char * text, int where )
184 {
185         Arg arg; XawTextBlock t; Widget edit;
186
187         /* the backend adds \r\n, which is needed for winboard, 
188          * for xboard we delete them again over here */
189         if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
190
191         t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
192         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
193         XawTextReplace(edit, where, where, &t);
194 //      XtSetArg(arg, XtNstring, (XtArgVal) text);
195 //      XtSetValues(outputField[which][nMemo], &arg, 1);
196 }
197
198 void SetIcon( int which, int field, int nIcon )
199 {
200     Arg arg;
201
202     if( nIcon != 0 ) {
203         XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
204         XtSetValues(outputField[which][field], &arg, 1);
205     }
206 }
207
208 void DoClearMemo(int which)
209
210     Arg args[16];
211     int j;
212     Widget edit;
213
214         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
215         XtCallActionProc(edit, "select-all", NULL, NULL, 0);
216         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
217 }
218
219 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
220
221 extern char *selected_fen_position;
222
223 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
224                  Atom *type_return, XtPointer *value_return,
225                  unsigned long *length_return, int *format_return); // from xboard.c
226 void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
227
228 char memoTranslations[] =
229 ":Ctrl<Key>c: CopyMemoProc() \n";
230
231 static void
232 MemoCB(Widget w, XtPointer client_data, Atom *selection,
233            Atom *type, XtPointer value, unsigned long *len, int *format)
234 {
235   if (value==NULL || *len==0) return; /* nothing had been selected to copy */
236   selected_fen_position = value;
237   selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
238 //    XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
239 //                 CurrentTime,
240 //                 SendPositionSelection,
241 //                 NULL/* lose_ownership_proc */ ,
242 //                 NULL/* transfer_done_proc */);
243 }
244
245 void CopyMemoProc(w, event, prms, nprms)
246   Widget w;
247   XEvent *event;
248   String *prms;
249   Cardinal *nprms;
250 {
251     if(appData.pasteSelection) return;
252     if (selected_fen_position) free(selected_fen_position);
253     XtGetSelectionValue(menuBarWidget, 
254       XA_PRIMARY, XA_STRING,
255       /* (XtSelectionCallbackProc) */ MemoCB,
256       NULL, /* client_data passed to PastePositionCB */
257
258       /* better to use the time field from the event that triggered the
259        * call to this function, but that isn't trivial to get
260        */
261       CurrentTime
262     );
263 }
264
265 // The following routines are mutated clones of the commentPopUp routines
266
267 void PositionControlSet(which, shell, form, bw_width)
268      int which;
269      Widget shell, form;
270      Dimension bw_width;
271 {
272     Arg args[16];
273     Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
274     int j, mutable=1;
275     j = 0;
276     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
277     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;
278     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
279     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
280     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;
281     XtSetArg(args[j], XtNright,     XtChainLeft); j++;
282     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
283     XtSetArg(args[j], XtNwidth,     (XtArgVal) 17); j++;
284     outputField[which][nColorIcon] = ColorWidget =
285       XtCreateManagedWidget("Color", labelWidgetClass,
286                      form, args, j);
287
288     j = 0;
289     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
290     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
291     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
292     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
293     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
294     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;
295     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
296     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 57); j++;
297     outputField[which][nLabel] = NameWidget =
298       XtCreateManagedWidget("Engine", labelWidgetClass,
299                      form, args, j);
300
301     j = 0;
302     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
303     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;
304     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
305     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
306     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
307     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
308     XtSetArg(args[j], XtNwidth,     (XtArgVal) 20); j++;
309     outputField[which][nStateIcon] = ModeWidget =
310       XtCreateManagedWidget("Mode", labelWidgetClass,
311                      form, args, j);
312
313     j = 0;
314     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
315     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
316     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;
317     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
318     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
319     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
320     XtSetArg(args[j], XtNright,     XtChainRight); j++;
321     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
322     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 102); j++;
323     outputField[which][nStateData] = MoveWidget =
324       XtCreateManagedWidget("Move", labelWidgetClass,
325                      form, args, j);
326
327     j = 0;
328     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
329     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyRight); j++;
330     XtSetArg(args[j], XtNlabel,     (XtArgVal) _("NPS")); j++;
331     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
332     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
333     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
334     XtSetArg(args[j], XtNleft,      XtChainRight); j++;
335     XtSetArg(args[j], XtNright,     XtChainRight); j++;
336     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
337     XtSetArg(args[j], XtNwidth,     (XtArgVal) 100); j++;
338     outputField[which][nLabelNPS] = NodesWidget =
339       XtCreateManagedWidget("Nodes", labelWidgetClass,
340                      form, args, j);
341
342     // create "text" within "form"
343     j = 0;
344     if (mutable) {
345         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
346         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
347     }
348     XtSetArg(args[j], XtNstring, "");  j++;
349     XtSetArg(args[j], XtNdisplayCaret, False);  j++;
350     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
351     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
352     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
353     XtSetArg(args[j], XtNright, XtChainRight);  j++;
354     XtSetArg(args[j], XtNresizable, True);  j++;
355     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/
356     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
357     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
358     XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded);  j++;
359 //    XtSetArg(args[j], XtNautoFill, True);  j++;
360 //    XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
361     outputField[which][nMemo] = edit =
362       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
363
364     XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
365     XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
366
367     j = 0;
368     XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
369 //    XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
370     XtSetValues(edit, args, j);
371 }
372
373 Widget EngineOutputCreate(name, text)
374      char *name, *text;
375 {
376     Arg args[16];
377     Widget shell, layout, form, form2, edit;
378     Dimension bw_width, bw_height;
379     int j;
380
381     // get board width
382     j = 0;
383     XtSetArg(args[j], XtNwidth,  &bw_width);  j++;
384     XtSetArg(args[j], XtNheight, &bw_height);  j++;
385     XtGetValues(boardWidget, args, j);
386
387     // define form within layout within shell.
388     j = 0;
389     XtSetArg(args[j], XtNresizable, True);  j++;
390     shell =
391 #if TOPLEVEL 
392       //     XtCreatePopupShell(name, topLevelShellWidgetClass,
393 #else
394       //      XtCreatePopupShell(name, transientShellWidgetClass,
395 #endif
396       //                         shellWidget, args, j);
397 //    layout =
398 //      XtCreateManagedWidget(layoutName, formWidgetClass, shell,
399 //                          layoutArgs, XtNumber(layoutArgs));
400     // divide window vertically into two equal parts, by creating two forms
401     form =
402       XtCreateManagedWidget("form", formWidgetClass, layout,
403                             formArgs, XtNumber(formArgs));
404     form2 =
405       XtCreateManagedWidget("form2", formWidgetClass, layout,
406                             formArgs, XtNumber(formArgs));
407     j = 0;
408     XtSetArg(args[j], XtNfromVert,  (XtArgVal) form); j++;
409     XtSetValues(form2, args, j);
410     // make sure width is known in advance, for better placement of child widgets
411     j = 0;
412     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width-16); j++;
413     XtSetArg(args[j], XtNheight,    (XtArgVal) bw_height/2); j++;
414     XtSetValues(shell, args, j);
415
416     // fill up both forms with control elements
417     PositionControlSet(0, shell, form,  bw_width);
418     PositionControlSet(1, shell, form2, bw_width);
419
420     XtRealizeWidget(shell);
421
422     if(wpEngineOutput.width > 0) {
423       engineOutputW = wpEngineOutput.width;
424       engineOutputH = wpEngineOutput.height;
425       engineOutputX = wpEngineOutput.x;
426       engineOutputY = wpEngineOutput.y;
427     }
428
429     if (engineOutputX == -1) {
430         int xx, yy;
431         Window junk;
432         Dimension pw_height;
433         Dimension ew_height;
434         engineOutputH = bw_height/2;
435         engineOutputW = bw_width-16;
436
437         //      XSync(xDisplay, False);
438 #ifdef NOTDEF
439         /* This code seems to tickle an X bug if it is executed too soon
440            after xboard starts up.  The coordinates get transformed as if
441            the main window was positioned at (0, 0).
442            */
443 //      XtTranslateCoords(shellWidget,
444 //                        (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
445 //                        &engineOutputX, &engineOutputY);
446 #else  /*!NOTDEF*/
447 //        XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
448 //                            RootWindowOfScreen(XtScreen(shellWidget)),
449 //                            (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
450 //                            &xx, &yy, &junk);
451         engineOutputX = xx;
452         engineOutputY = yy;
453 #endif /*!NOTDEF*/
454         if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
455     }
456     j = 0;
457     XtSetArg(args[j], XtNheight, engineOutputH);  j++;
458     XtSetArg(args[j], XtNwidth, engineOutputW);  j++;
459     XtSetArg(args[j], XtNx, engineOutputX);  j++;
460     XtSetArg(args[j], XtNy, engineOutputY);  j++;
461     XtSetValues(shell, args, j);
462 //    XtSetKeyboardFocus(shell, edit);
463
464     return shell;
465 }
466
467 void ResizeWindowControls(mode)
468         int mode;
469 {
470     Widget form1, form2;
471     Arg args[16];
472     int j;
473     Dimension ew_height, tmp;
474     Widget shell = engineOutputShell;
475
476     form1 = XtNameToWidget(shell, "*form");
477     form2 = XtNameToWidget(shell, "*form2");
478
479     j = 0;
480     XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
481     XtGetValues(form1, args, j);
482     j = 0;
483     XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
484     XtGetValues(form2, args, j);
485     ew_height += tmp; // total height
486
487     if(mode==0) {
488         j = 0;
489         XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
490         XtSetValues(form2, args, j);
491         j = 0;
492         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
493         XtSetValues(form1, args, j);
494     } else {
495         j = 0;
496         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
497         XtSetValues(form1, args, j);
498         j = 0;
499         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
500         XtSetValues(form2, args, j);
501     }
502 }
503
504 void 
505 EngineOutputPopUp()
506 {
507   return;
508   //TODO
509     Arg args[16];
510     int j;
511     Widget edit;
512     static int  needInit = TRUE;
513     static char *title = _("Engine output"), *text = _("This feature is experimental");
514
515     if (engineOutputShell == NULL) {
516         engineOutputShell =
517           EngineOutputCreate(title, text);
518         XtRealizeWidget(engineOutputShell);
519         //      CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
520         if( needInit ) {
521             InitializeEngineOutput();
522             needInit = FALSE;
523         }
524         SetEngineColorIcon( 0 );
525         SetEngineColorIcon( 1 );
526         SetEngineState( 0, STATE_IDLE, "" );
527         SetEngineState( 1, STATE_IDLE, "" );
528     } else {
529         edit = XtNameToWidget(engineOutputShell, "*form.text");
530         j = 0;
531         XtSetArg(args[j], XtNstring, text); j++;
532         XtSetValues(edit, args, j);
533         j = 0;
534         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
535         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
536         XtSetValues(engineOutputShell, args, j);
537     }
538
539     XtPopup(engineOutputShell, XtGrabNone);
540     //    XSync(xDisplay, False);
541
542     j=0;
543     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
544     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
545                 args, j);
546
547     engineOutputDialogUp = True;
548     ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
549 }
550
551 void EngineOutputPopDown()
552 {
553   return;
554   //TODO
555
556     Arg args[16];
557     int j;
558
559     if (!engineOutputDialogUp) return;
560     DoClearMemo(1);
561     j = 0;
562     XtSetArg(args[j], XtNx, &engineOutputX); j++;
563     XtSetArg(args[j], XtNy, &engineOutputY); j++;
564     XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
565     XtSetArg(args[j], XtNheight, &engineOutputH); j++;
566     XtGetValues(engineOutputShell, args, j);
567     wpEngineOutput.x = engineOutputX - 4;
568     wpEngineOutput.y = engineOutputY - 23;
569     wpEngineOutput.width = engineOutputW;
570     wpEngineOutput.height = engineOutputH;
571     XtPopdown(engineOutputShell);
572     //    XSync(xDisplay, False);
573     j=0;
574     XtSetArg(args[j], XtNleftBitmap, None); j++;
575     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
576                 args, j);
577
578     engineOutputDialogUp = False;
579     ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
580 }
581
582 int EngineOutputIsUp()
583 {
584     return engineOutputDialogUp;
585 }
586
587 int EngineOutputDialogExists()
588 {
589     return engineOutputShell != NULL;
590 }
591
592 void
593 EngineOutputProc(w, event, prms, nprms)
594      Widget w;
595      XEvent *event;
596      String *prms;
597      Cardinal *nprms;
598 {
599   if (engineOutputDialogUp) {
600     EngineOutputPopDown();
601   } else {
602     EngineOutputPopUp();
603   }
604 }