4 * Author: Alessandro Scotti (Dec 2005)
6 * Copyright 2005 Alessandro Scotti
8 * Enhancements Copyright 2009 Free Software Foundation, Inc.
10 * ------------------------------------------------------------------------
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.
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.
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/.
25 * ------------------------------------------------------------------------
26 ** See the file ChangeLog for a revision history. */
33 #include <sys/types.h>
38 #else /* not STDC_HEADERS */
39 extern char *getenv();
42 # else /* not HAVE_STRING_H */
44 # endif /* not HAVE_STRING_H */
45 #endif /* not STDC_HEADERS */
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>
73 // Add xengineo.h later
77 # define _(s) gettext (s)
78 # define N_(s) gettext_noop (s)
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"
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;
109 // temporary kludge to avoid compile errors untill all Windows code has been replaced
113 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way
114 #define nColorBlack 1
115 #define nColorWhite 2
116 #define nColorUnknown 3
122 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
124 // [HGM] same for output fields (note that there are two of each type, one per color)
132 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
134 void EngineOutputPopDown();
135 void engineOutputPopUp(char *title, char *text);
136 int EngineOutputIsUp();
137 static void SetEngineColorIcon( int which );
139 #define SHOW_PONDERING
141 /* Imports from backend.c */
142 char * SavePart(char *str);
143 extern int opponentKibitzes;
145 /* Imports from winboard.c */
146 //extern HWND engineOutputDialog;
147 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
149 //extern WindowPlacement wpEngineOutput;
151 Position engineOutputX = -1, engineOutputY = -1;
152 Dimension engineOutputW, engineOutputH;
153 Widget engineOutputShell;
154 int engineOutputDialogUp;
156 /* Module variables */
159 #define LABEL_V_DISTANCE 1 /* Distance between label and memo */
160 #define SPLITTER_SIZE 4 /* Distance between first memo and second label */
164 #define STATE_UNKNOWN -1
165 #define STATE_THINKING 0
167 #define STATE_PONDERING 2
168 #define STATE_ANALYZING 3
170 static int windowMode = 1;
172 static int needInit = TRUE;
174 static int lastDepth[2] = { -1, -1 };
175 static int lastForwardMostMove[2] = { -1, -1 };
176 static int engineState[2] = { -1, -1 };
191 static int VerifyDisplayMode();
192 static void UpdateControls( EngineOutputData * ed );
193 static SetEngineState( int which, int state, char * state_data );
195 void ReadIcon(char *pixData[], int iconNr)
199 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
202 NULL, NULL /*&attr*/)) != 0) {
203 fprintf(stderr, _("Error %d loading icon image\n"), r);
208 static void InitializeEngineOutput()
211 ReadIcon(WHITE_14, nColorWhite);
212 ReadIcon(BLACK_14, nColorBlack);
213 ReadIcon(UNKNOWN_14, nColorUnknown);
215 ReadIcon(CLEAR_14, nClear);
216 ReadIcon(PONDER_14, nPondering);
217 ReadIcon(THINK_14, nThinking);
218 ReadIcon(ANALYZE_14, nAnalyzing);
221 void DoSetWindowText(int which, int field, char *s_label)
225 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
226 XtSetValues(outputField[which][field], &arg, 1);
229 static void InsertIntoMemo( int which, char * text )
231 Arg arg; XawTextBlock t; Widget edit;
233 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
234 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
235 XawTextReplace(edit, 0, 0, &t);
236 // XtSetArg(arg, XtNstring, (XtArgVal) text);
237 // XtSetValues(outputField[which][nMemo], &arg, 1);
240 static void SetIcon( int which, int field, int nIcon )
245 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
246 XtSetValues(outputField[which][field], &arg, 1);
250 void DoClearMemo(int which)
256 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
257 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
258 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
261 // The following routines are mutated clones of the commentPopUp routines
263 void PositionControlSet(which, form, bw_width)
269 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
272 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
273 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
274 XtSetArg(args[j], XtNtop, XtChainTop); j++;
275 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
276 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
277 XtSetArg(args[j], XtNright, XtChainLeft); j++;
278 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
279 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
280 outputField[which][nColorIcon] = ColorWidget =
281 XtCreateManagedWidget("Color", labelWidgetClass,
285 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
286 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
287 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
288 XtSetArg(args[j], XtNtop, XtChainTop); j++;
289 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
290 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
291 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
292 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
293 outputField[which][nLabel] = NameWidget =
294 XtCreateManagedWidget("Engine", labelWidgetClass,
298 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
299 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
300 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
301 XtSetArg(args[j], XtNtop, XtChainTop); j++;
302 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
303 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
304 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
305 outputField[which][nStateIcon] = ModeWidget =
306 XtCreateManagedWidget("Mode", labelWidgetClass,
310 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
311 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
312 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
313 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
314 XtSetArg(args[j], XtNtop, XtChainTop); j++;
315 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
316 XtSetArg(args[j], XtNright, XtChainRight); j++;
317 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
318 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
319 outputField[which][nStateData] = MoveWidget =
320 XtCreateManagedWidget("Move", labelWidgetClass,
324 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
325 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
326 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
327 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
328 XtSetArg(args[j], XtNtop, XtChainTop); j++;
329 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
330 XtSetArg(args[j], XtNleft, XtChainRight); j++;
331 XtSetArg(args[j], XtNright, XtChainRight); j++;
332 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
333 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
334 outputField[which][nLabelNPS] = NodesWidget =
335 XtCreateManagedWidget("Nodes", labelWidgetClass,
338 // create "text" within "form"
341 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
342 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
344 XtSetArg(args[j], XtNstring, ""); j++;
345 XtSetArg(args[j], XtNdisplayCaret, False); j++;
346 XtSetArg(args[j], XtNtop, XtChainTop); j++;
347 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
348 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
349 XtSetArg(args[j], XtNright, XtChainRight); j++;
350 XtSetArg(args[j], XtNresizable, True); j++;
351 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
353 XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded); j++;
355 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
356 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
357 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);
365 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
366 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
367 XtSetValues(edit, args, j);
370 Widget EngineOutputCreate(name, text)
374 Widget shell, layout, form, form2, edit;
375 Dimension bw_width, bw_height;
380 XtSetArg(args[j], XtNwidth, &bw_width); j++;
381 XtSetArg(args[j], XtNheight, &bw_height); j++;
382 XtGetValues(boardWidget, args, j);
384 // define form within layout within shell.
386 XtSetArg(args[j], XtNresizable, True); j++;
388 XtCreatePopupShell(name, transientShellWidgetClass,
389 shellWidget, args, j);
391 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
392 layoutArgs, XtNumber(layoutArgs));
393 // divide window vertically into two equal parts, by creating two forms
395 XtCreateManagedWidget("form", formWidgetClass, layout,
396 formArgs, XtNumber(formArgs));
398 XtCreateManagedWidget("form2", formWidgetClass, layout,
399 formArgs, XtNumber(formArgs));
401 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
402 XtSetValues(form2, args, j);
403 // make sure width is known in advance, for better placement of child widgets
405 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
406 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
407 XtSetValues(shell, args, j);
409 // fill up both forms with control elements
410 PositionControlSet(0, form, bw_width);
411 PositionControlSet(1, form2, bw_width);
413 XtRealizeWidget(shell);
415 if (engineOutputX == -1) {
422 XtSetArg(args[j], XtNheight, &ew_height); j++;
423 XtGetValues(edit, args, j);
426 XtSetArg(args[j], XtNheight, &pw_height); j++;
427 XtGetValues(shell, args, j);
428 engineOutputH = pw_height + (lines - 1) * ew_height;
429 engineOutputW = bw_width - 16;
431 engineOutputH = bw_height/2;
432 engineOutputW = bw_width-16;
435 XSync(xDisplay, False);
437 /* This code seems to tickle an X bug if it is executed too soon
438 after xboard starts up. The coordinates get transformed as if
439 the main window was positioned at (0, 0).
441 XtTranslateCoords(shellWidget,
442 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
443 &engineOutputX, &engineOutputY);
445 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
446 RootWindowOfScreen(XtScreen(shellWidget)),
447 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
452 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
455 XtSetArg(args[j], XtNheight, engineOutputH); j++;
456 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
457 XtSetArg(args[j], XtNx, engineOutputX); j++;
458 XtSetArg(args[j], XtNy, engineOutputY); j++;
459 XtSetValues(shell, args, j);
460 // XtSetKeyboardFocus(shell, edit);
465 void ResizeWindowControls(shell, mode)
472 Dimension ew_height, tmp;
474 form1 = XtNameToWidget(shell, "*form");
475 form2 = XtNameToWidget(shell, "*form2");
478 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
479 XtGetValues(form1, args, j);
481 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
482 XtGetValues(form2, args, j);
483 ew_height += tmp; // total height
487 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
488 XtSetValues(form2, args, j);
490 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
491 XtSetValues(form1, args, j);
494 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
495 XtSetValues(form1, args, j);
497 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
498 XtSetValues(form2, args, j);
502 void EngineOutputPopUp(title, text)
509 if (engineOutputShell == NULL) {
511 EngineOutputCreate(title, text);
512 XtRealizeWidget(engineOutputShell);
513 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
515 InitializeEngineOutput();
518 SetEngineColorIcon( 0 );
519 SetEngineColorIcon( 1 );
520 SetEngineState( 0, STATE_IDLE, "" );
521 SetEngineState( 1, STATE_IDLE, "" );
523 edit = XtNameToWidget(engineOutputShell, "*form.text");
525 XtSetArg(args[j], XtNstring, text); j++;
526 XtSetValues(edit, args, j);
528 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
529 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
530 XtSetValues(engineOutputShell, args, j);
533 XtPopup(engineOutputShell, XtGrabNone);
534 XSync(xDisplay, False);
537 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
538 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
541 engineOutputDialogUp = True;
542 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
545 void EngineOutputPopDown()
550 if (!engineOutputDialogUp) return;
553 XtSetArg(args[j], XtNx, &engineOutputX); j++;
554 XtSetArg(args[j], XtNy, &engineOutputY); j++;
555 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
556 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
557 XtGetValues(engineOutputShell, args, j);
558 XtPopdown(engineOutputShell);
559 XSync(xDisplay, False);
561 XtSetArg(args[j], XtNleftBitmap, None); j++;
562 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
565 engineOutputDialogUp = False;
566 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
569 //------------------------ pure back-end routines -------------------------------
572 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
573 static SetEngineState( int which, int state, char * state_data )
575 int x_which = 1 - which;
577 if( engineState[ which ] != state ) {
578 engineState[ which ] = state;
582 SetIcon( which, nStateIcon, nThinking );
583 if( engineState[ x_which ] == STATE_THINKING ) {
584 SetEngineState( x_which, STATE_IDLE, "" );
587 case STATE_PONDERING:
588 SetIcon( which, nStateIcon, nPondering );
590 case STATE_ANALYZING:
591 SetIcon( which, nStateIcon, nAnalyzing );
594 SetIcon( which, nStateIcon, nClear );
599 if( state_data != 0 ) {
600 DoSetWindowText( which, nStateData, state_data );
604 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
605 void EngineOutputUpdate( FrontEndProgramStats * stats )
608 int clearMemo = FALSE;
613 SetEngineState( 0, STATE_IDLE, "" );
614 SetEngineState( 1, STATE_IDLE, "" );
618 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
619 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
621 which = stats->which;
622 depth = stats->depth;
624 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
628 if( engineOutputShell == NULL ) {
636 ed.nodes = stats->nodes;
637 ed.score = stats->score;
638 ed.time = stats->time;
640 ed.hint = stats->hint;
641 ed.an_move_index = stats->an_move_index;
642 ed.an_move_count = stats->an_move_count;
644 /* Get target control. [HGM] this is moved to front end, which get them from a table */
646 ed.name = first.tidy;
649 ed.name = second.tidy;
652 /* Clear memo if needed */
653 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
657 if( lastForwardMostMove[which] != forwardMostMove ) {
661 if( clearMemo ) DoClearMemo(which);
664 lastDepth[which] = depth;
665 lastForwardMostMove[which] = forwardMostMove;
667 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
668 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
673 UpdateControls( &ed );
676 #define ENGINE_COLOR_WHITE 'w'
677 #define ENGINE_COLOR_BLACK 'b'
678 #define ENGINE_COLOR_UNKNOWN ' '
681 char GetEngineColor( int which )
683 char result = ENGINE_COLOR_UNKNOWN;
685 if( which == 0 || which == 1 ) {
686 ChessProgramState * cps;
689 case MachinePlaysBlack:
690 case IcsPlayingBlack:
691 result = ENGINE_COLOR_BLACK;
693 case MachinePlaysWhite:
694 case IcsPlayingWhite:
695 result = ENGINE_COLOR_WHITE;
699 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
701 case TwoMachinesPlay:
702 cps = (which == 0) ? &first : &second;
703 result = cps->twoMachinesColor[0];
704 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
713 char GetActiveEngineColor()
715 char result = ENGINE_COLOR_UNKNOWN;
717 if( gameMode == TwoMachinesPlay ) {
718 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
725 static int IsEnginePondering( int which )
730 case MachinePlaysBlack:
731 case IcsPlayingBlack:
732 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
734 case MachinePlaysWhite:
735 case IcsPlayingWhite:
736 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
738 case TwoMachinesPlay:
739 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
740 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
749 static void SetDisplayMode( int mode )
751 if( windowMode != mode ) {
754 ResizeWindowControls( engineOutputShell, mode );
759 int VerifyDisplayMode()
763 /* Get proper mode for current game */
765 case IcsObserving: // [HGM] ICS analyze
766 if(!appData.icsEngineAnalyze) return;
769 case MachinePlaysWhite:
770 case MachinePlaysBlack:
773 case IcsPlayingWhite:
774 case IcsPlayingBlack:
775 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
777 case TwoMachinesPlay:
785 SetDisplayMode( mode );
788 // back end. Determine what icon to se in the color-icon field, and print it
789 static void SetEngineColorIcon( int which )
791 char color = GetEngineColor(which);
794 if( color == ENGINE_COLOR_BLACK )
796 else if( color == ENGINE_COLOR_WHITE )
799 nicon = nColorUnknown;
801 SetIcon( which, nColorIcon, nicon );
804 #define MAX_NAME_LENGTH 32
806 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
807 static void UpdateControls( EngineOutputData * ed )
809 int isPondering = FALSE;
811 char s_label[MAX_NAME_LENGTH + 32];
813 char * name = ed->name;
816 if( name == 0 || *name == '\0' ) {
820 strncpy( s_label, name, MAX_NAME_LENGTH );
821 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
823 #ifdef SHOW_PONDERING
824 if( IsEnginePondering( ed->which ) ) {
829 if( ed->hint != 0 && *ed->hint != '\0' ) {
830 strncpy( buf, ed->hint, sizeof(buf) );
831 buf[sizeof(buf)-1] = '\0';
833 else if( ed->pv != 0 && *ed->pv != '\0' ) {
834 char * sep = strchr( ed->pv, ' ' );
835 int buflen = sizeof(buf);
838 buflen = sep - ed->pv + 1;
839 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
842 strncpy( buf, ed->pv, buflen );
843 buf[ buflen-1 ] = '\0';
846 SetEngineState( ed->which, STATE_PONDERING, buf );
848 else if( gameMode == TwoMachinesPlay ) {
849 SetEngineState( ed->which, STATE_THINKING, "" );
851 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
852 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
854 int time_secs = ed->time / 100;
855 int time_mins = time_secs / 60;
859 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
862 strncpy( mov, ed->hint, sizeof(mov) );
863 mov[ sizeof(mov)-1 ] = '\0';
865 sprintf( buf, "%d/%d: %s [%02d:%02d:%02d]", ed->an_move_index, ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 );
868 SetEngineState( ed->which, STATE_ANALYZING, buf );
871 SetEngineState( ed->which, STATE_IDLE, "" );
875 DoSetWindowText( ed->which, nLabel, s_label );
879 if( ed->time > 0 && ed->nodes > 0 ) {
880 unsigned long nps_100 = ed->nodes / ed->time;
882 if( nps_100 < 100000 ) {
883 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
886 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
890 DoSetWindowText( ed->which, nLabelNPS, s_label );
893 if( ed->pv != 0 && *ed->pv != '\0' ) {
899 int time_secs = ed->time / 100;
900 int time_cent = ed->time % 100;
903 if( ed->nodes < 1000000 ) {
904 sprintf( s_nodes, u64Display, ed->nodes );
907 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
911 if( ed->score > 0 ) {
912 sprintf( s_score, "+%.2f", ed->score / 100.0 );
914 sprintf( s_score, "%.2f", ed->score / 100.0 );
917 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
919 /* Put all together... */
920 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
923 buflen = strlen(buf);
925 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
927 buf[ sizeof(buf) - 3 ] = '\0';
929 strcat( buf + buflen, "\n" );
932 InsertIntoMemo( ed->which, buf );
936 SetEngineColorIcon( ed->which );
940 int EngineOutputIsUp()
942 return engineOutputDialogUp;
946 EngineOutputProc(w, event, prms, nprms)
952 if (engineOutputDialogUp) {
953 EngineOutputPopDown();
955 EngineOutputPopUp(_("engine output"),_("This feature is experimental"));
957 // ToNrEvent(currentMove);
960 // [HGM] kibitz: write kibitz line; split window for it if necessary
961 void OutputKibitz(int window, char *text)
963 if(!EngineOutputIsUp()) return;
964 if(!opponentKibitzes) { // on first kibitz of game, clear memos
966 if(gameMode == IcsObserving) DoClearMemo(0);
968 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
970 if(gameMode == IcsObserving) {
971 DoSetWindowText(0, nLabel, gameInfo.white);
972 SetIcon( 0, nColorIcon, nColorWhite);
973 SetIcon( 0, nStateIcon, nClear);
975 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
976 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
977 SetIcon( 1, nStateIcon, nClear);
978 InsertIntoMemo(window-1, text);