added missing sounds files to be able to compile on windows
[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
69 #include "common.h"
70 #include "frontend.h"
71 #include "backend.h"
72 #include "xboard.h"
73 #include "engineoutput.h"
74 #include "gettext.h"
75
76 #ifdef ENABLE_NLS
77 # define  _(s) gettext (s)
78 # define N_(s) gettext_noop (s)
79 #else
80 # define  _(s) (s)
81 # define N_(s)  s
82 #endif
83
84 #include <X11/xpm.h>
85
86 // [HGM] pixmaps of some ICONS used in the engine-outut window
87 #include "pixmaps/WHITE_14.xpm"
88 #include "pixmaps/BLACK_14.xpm"
89 #include "pixmaps/CLEAR_14.xpm"
90 #include "pixmaps/UNKNOWN_14.xpm"
91 #include "pixmaps/THINKING_14.xpm"
92 #include "pixmaps/PONDER_14.xpm"
93 #include "pixmaps/ANALYZING_14.xpm"
94
95 #ifdef SNAP
96 #include "wsnap.h"
97 #endif
98
99 #define _LL_ 100
100
101 // imports from xboard.c
102 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
103 extern Display *xDisplay;
104 extern Window xBoardWindow;
105 extern int squareSize;
106 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
107 extern char *layoutName;
108
109 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
110 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
111
112 void EngineOutputPopDown();
113 void engineOutputPopUp();
114 int  EngineOutputIsUp();
115 void SetEngineColorIcon( int which );
116
117 /* Imports from backend.c */
118 extern int opponentKibitzes;
119
120 /* Imports from xboard.c */
121 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
122
123 //extern WindowPlacement wpEngineOutput;
124
125 Position engineOutputX = -1, engineOutputY = -1;
126 Dimension engineOutputW, engineOutputH;
127 Widget engineOutputShell;
128 static int engineOutputDialogUp;
129
130 /* Module variables */
131 int  windowMode = 1;
132
133 typedef struct {
134     char * name;
135     int which;
136     int depth;
137     u64 nodes;
138     int score;
139     int time;
140     char * pv;
141     char * hint;
142     int an_move_index;
143     int an_move_count;
144 } EngineOutputData;
145
146 //static void UpdateControls( EngineOutputData * ed );
147
148 void ReadIcon(char *pixData[], int iconNr)
149 {
150     int r;
151
152         if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
153                                        pixData,
154                                        &(icons[iconNr]),
155                                        NULL, NULL /*&attr*/)) != 0) {
156           fprintf(stderr, _("Error %d loading icon image\n"), r);
157           exit(1); 
158         }       
159 }
160
161 static void InitializeEngineOutput()
162 { int i;
163
164         ReadIcon(WHITE_14,   nColorWhite);
165         ReadIcon(BLACK_14,   nColorBlack);
166         ReadIcon(UNKNOWN_14, nColorUnknown);
167
168         ReadIcon(CLEAR_14,   nClear);
169         ReadIcon(PONDER_14,  nPondering);
170         ReadIcon(THINK_14,   nThinking);
171         ReadIcon(ANALYZE_14, nAnalyzing);
172 }
173
174 void DoSetWindowText(int which, int field, char *s_label)
175
176         Arg arg;
177
178         XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
179         XtSetValues(outputField[which][field], &arg, 1);
180 }
181
182 void InsertIntoMemo( int which, char * text, int where )
183 {
184         Arg arg; XawTextBlock t; Widget edit;
185
186         /* the backend adds \r\n, which is needed for winboard, 
187          * for xboard we delete them again over here */
188         if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
189
190         t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
191         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
192         XawTextReplace(edit, where, where, &t);
193 //      XtSetArg(arg, XtNstring, (XtArgVal) text);
194 //      XtSetValues(outputField[which][nMemo], &arg, 1);
195 }
196
197 void SetIcon( int which, int field, int nIcon )
198 {
199     Arg arg;
200
201     if( nIcon != 0 ) {
202         XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
203         XtSetValues(outputField[which][field], &arg, 1);
204     }
205 }
206
207 void DoClearMemo(int which)
208
209     Arg args[16];
210     int j;
211     Widget edit;
212
213         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
214         XtCallActionProc(edit, "select-all", NULL, NULL, 0);
215         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
216 }
217
218 // The following routines are mutated clones of the commentPopUp routines
219
220 void PositionControlSet(which, form, bw_width)
221      int which;
222      Widget form;
223      Dimension bw_width;
224 {
225     Arg args[16];
226     Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
227     int j, mutable=1;
228     j = 0;
229     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
230     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;
231     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
232     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
233     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;
234     XtSetArg(args[j], XtNright,     XtChainLeft); j++;
235     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
236     XtSetArg(args[j], XtNwidth,     (XtArgVal) 17); j++;
237     outputField[which][nColorIcon] = ColorWidget =
238       XtCreateManagedWidget("Color", labelWidgetClass,
239                      form, args, j);
240
241     j = 0;
242     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
243     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
244     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
245     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
246     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
247     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;
248     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
249     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 57); j++;
250     outputField[which][nLabel] = NameWidget =
251       XtCreateManagedWidget("Engine", labelWidgetClass,
252                      form, args, j);
253
254     j = 0;
255     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
256     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;
257     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
258     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
259     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
260     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
261     XtSetArg(args[j], XtNwidth,     (XtArgVal) 20); j++;
262     outputField[which][nStateIcon] = ModeWidget =
263       XtCreateManagedWidget("Mode", labelWidgetClass,
264                      form, args, j);
265
266     j = 0;
267     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
268     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
269     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;
270     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
271     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
272     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
273     XtSetArg(args[j], XtNright,     XtChainRight); j++;
274     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
275     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 102); j++;
276     outputField[which][nStateData] = MoveWidget =
277       XtCreateManagedWidget("Move", labelWidgetClass,
278                      form, args, j);
279
280     j = 0;
281     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
282     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyRight); j++;
283     XtSetArg(args[j], XtNlabel,     (XtArgVal) _("NPS")); j++;
284     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
285     XtSetArg(args[j], XtNtop,       XtChainTop); j++;
286     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;
287     XtSetArg(args[j], XtNleft,      XtChainRight); j++;
288     XtSetArg(args[j], XtNright,     XtChainRight); j++;
289     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;
290     XtSetArg(args[j], XtNwidth,     (XtArgVal) 100); j++;
291     outputField[which][nLabelNPS] = NodesWidget =
292       XtCreateManagedWidget("Nodes", labelWidgetClass,
293                      form, args, j);
294
295     // create "text" within "form"
296     j = 0;
297     if (mutable) {
298         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
299         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
300     }
301     XtSetArg(args[j], XtNstring, "");  j++;
302     XtSetArg(args[j], XtNdisplayCaret, False);  j++;
303     XtSetArg(args[j], XtNtop, XtChainTop);  j++;
304     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;
305     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;
306     XtSetArg(args[j], XtNright, XtChainRight);  j++;
307     XtSetArg(args[j], XtNresizable, True);  j++;
308     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/
309     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
310     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;
311     XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded);  j++;
312 //    XtSetArg(args[j], XtNautoFill, True);  j++;
313 //    XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
314     outputField[which][nMemo] = edit =
315       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
316
317     j = 0;
318     XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
319 //    XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
320     XtSetValues(edit, args, j);
321 }
322
323 Widget EngineOutputCreate(name, text)
324      char *name, *text;
325 {
326     Arg args[16];
327     Widget shell, layout, form, form2, edit;
328     Dimension bw_width, bw_height;
329     int j;
330
331     // get board width
332     j = 0;
333     XtSetArg(args[j], XtNwidth,  &bw_width);  j++;
334     XtSetArg(args[j], XtNheight, &bw_height);  j++;
335     XtGetValues(boardWidget, args, j);
336
337     // define form within layout within shell.
338     j = 0;
339     XtSetArg(args[j], XtNresizable, True);  j++;
340     shell =
341 #if TOPLEVEL 
342      XtCreatePopupShell(name, topLevelShellWidgetClass,
343 #else
344       XtCreatePopupShell(name, transientShellWidgetClass,
345 #endif
346                          shellWidget, args, j);
347     layout =
348       XtCreateManagedWidget(layoutName, formWidgetClass, shell,
349                             layoutArgs, XtNumber(layoutArgs));
350     // divide window vertically into two equal parts, by creating two forms
351     form =
352       XtCreateManagedWidget("form", formWidgetClass, layout,
353                             formArgs, XtNumber(formArgs));
354     form2 =
355       XtCreateManagedWidget("form2", formWidgetClass, layout,
356                             formArgs, XtNumber(formArgs));
357     j = 0;
358     XtSetArg(args[j], XtNfromVert,  (XtArgVal) form); j++;
359     XtSetValues(form2, args, j);
360     // make sure width is known in advance, for better placement of child widgets
361     j = 0;
362     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width-16); j++;
363     XtSetArg(args[j], XtNheight,    (XtArgVal) bw_height/2); j++;
364     XtSetValues(shell, args, j);
365
366     // fill up both forms with control elements
367     PositionControlSet(0, form,  bw_width);
368     PositionControlSet(1, form2, bw_width);
369
370     XtRealizeWidget(shell);
371
372     if(wpEngineOutput.width > 0) {
373       engineOutputW = wpEngineOutput.width;
374       engineOutputH = wpEngineOutput.height;
375       engineOutputX = wpEngineOutput.x;
376       engineOutputY = wpEngineOutput.y;
377     }
378
379     if (engineOutputX == -1) {
380         int xx, yy;
381         Window junk;
382         Dimension pw_height;
383         Dimension ew_height;
384         engineOutputH = bw_height/2;
385         engineOutputW = bw_width-16;
386
387         XSync(xDisplay, False);
388 #ifdef NOTDEF
389         /* This code seems to tickle an X bug if it is executed too soon
390            after xboard starts up.  The coordinates get transformed as if
391            the main window was positioned at (0, 0).
392            */
393         XtTranslateCoords(shellWidget,
394                           (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
395                           &engineOutputX, &engineOutputY);
396 #else  /*!NOTDEF*/
397         XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
398                               RootWindowOfScreen(XtScreen(shellWidget)),
399                               (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
400                               &xx, &yy, &junk);
401         engineOutputX = xx;
402         engineOutputY = yy;
403 #endif /*!NOTDEF*/
404         if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
405     }
406     j = 0;
407     XtSetArg(args[j], XtNheight, engineOutputH);  j++;
408     XtSetArg(args[j], XtNwidth, engineOutputW);  j++;
409     XtSetArg(args[j], XtNx, engineOutputX);  j++;
410     XtSetArg(args[j], XtNy, engineOutputY);  j++;
411     XtSetValues(shell, args, j);
412 //    XtSetKeyboardFocus(shell, edit);
413
414     return shell;
415 }
416
417 void ResizeWindowControls(mode)
418         int mode;
419 {
420     Widget form1, form2;
421     Arg args[16];
422     int j;
423     Dimension ew_height, tmp;
424     Widget shell = engineOutputShell;
425
426     form1 = XtNameToWidget(shell, "*form");
427     form2 = XtNameToWidget(shell, "*form2");
428
429     j = 0;
430     XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
431     XtGetValues(form1, args, j);
432     j = 0;
433     XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
434     XtGetValues(form2, args, j);
435     ew_height += tmp; // total height
436
437     if(mode==0) {
438         j = 0;
439         XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
440         XtSetValues(form2, args, j);
441         j = 0;
442         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
443         XtSetValues(form1, args, j);
444     } else {
445         j = 0;
446         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
447         XtSetValues(form1, args, j);
448         j = 0;
449         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
450         XtSetValues(form2, args, j);
451     }
452 }
453
454 void 
455 EngineOutputPopUp()
456 {
457     Arg args[16];
458     int j;
459     Widget edit;
460     static int  needInit = TRUE;
461     static char *title = _("Engine output"), *text = _("This feature is experimental");
462
463     if (engineOutputShell == NULL) {
464         engineOutputShell =
465           EngineOutputCreate(title, text);
466         XtRealizeWidget(engineOutputShell);
467         CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
468         if( needInit ) {
469             InitializeEngineOutput();
470             needInit = FALSE;
471         }
472         SetEngineColorIcon( 0 );
473         SetEngineColorIcon( 1 );
474         SetEngineState( 0, STATE_IDLE, "" );
475         SetEngineState( 1, STATE_IDLE, "" );
476     } else {
477         edit = XtNameToWidget(engineOutputShell, "*form.text");
478         j = 0;
479         XtSetArg(args[j], XtNstring, text); j++;
480         XtSetValues(edit, args, j);
481         j = 0;
482         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;
483         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;
484         XtSetValues(engineOutputShell, args, j);
485     }
486
487     XtPopup(engineOutputShell, XtGrabNone);
488     XSync(xDisplay, False);
489
490     j=0;
491     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
492     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
493                 args, j);
494
495     engineOutputDialogUp = True;
496     ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
497 }
498
499 void EngineOutputPopDown()
500 {
501     Arg args[16];
502     int j;
503
504     if (!engineOutputDialogUp) return;
505     DoClearMemo(1);
506     j = 0;
507     XtSetArg(args[j], XtNx, &engineOutputX); j++;
508     XtSetArg(args[j], XtNy, &engineOutputY); j++;
509     XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
510     XtSetArg(args[j], XtNheight, &engineOutputH); j++;
511     XtGetValues(engineOutputShell, args, j);
512     wpEngineOutput.x = engineOutputX - 4;
513     wpEngineOutput.y = engineOutputY - 23;
514     wpEngineOutput.width = engineOutputW;
515     wpEngineOutput.height = engineOutputH;
516     XtPopdown(engineOutputShell);
517     XSync(xDisplay, False);
518     j=0;
519     XtSetArg(args[j], XtNleftBitmap, None); j++;
520     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
521                 args, j);
522
523     engineOutputDialogUp = False;
524     ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
525 }
526
527 int EngineOutputIsUp()
528 {
529     return engineOutputDialogUp;
530 }
531
532 int EngineOutputDialogExists()
533 {
534     return engineOutputShell != NULL;
535 }
536
537 void
538 EngineOutputProc(w, event, prms, nprms)
539      Widget w;
540      XEvent *event;
541      String *prms;
542      Cardinal *nprms;
543 {
544   if (engineOutputDialogUp) {
545     EngineOutputPopDown();
546   } else {
547     EngineOutputPopUp();
548   }
549 }