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();
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 void VerifyDisplayMode();
192 static void UpdateControls( EngineOutputData * ed );
193 static void 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*/
352 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
353 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
354 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
355 // XtSetArg(args[j], XtNautoFill, True); j++;
356 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
357 outputField[which][nMemo] = edit =
358 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
361 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
362 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
363 XtSetValues(edit, args, j);
366 Widget EngineOutputCreate(name, text)
370 Widget shell, layout, form, form2, edit;
371 Dimension bw_width, bw_height;
376 XtSetArg(args[j], XtNwidth, &bw_width); j++;
377 XtSetArg(args[j], XtNheight, &bw_height); j++;
378 XtGetValues(boardWidget, args, j);
380 // define form within layout within shell.
382 XtSetArg(args[j], XtNresizable, True); j++;
385 XtCreatePopupShell(name, topLevelShellWidgetClass,
387 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) {
420 engineOutputH = bw_height/2;
421 engineOutputW = bw_width-16;
423 XSync(xDisplay, False);
425 /* This code seems to tickle an X bug if it is executed too soon
426 after xboard starts up. The coordinates get transformed as if
427 the main window was positioned at (0, 0).
429 XtTranslateCoords(shellWidget,
430 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
431 &engineOutputX, &engineOutputY);
433 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
434 RootWindowOfScreen(XtScreen(shellWidget)),
435 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
440 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
443 XtSetArg(args[j], XtNheight, engineOutputH); j++;
444 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
445 XtSetArg(args[j], XtNx, engineOutputX); j++;
446 XtSetArg(args[j], XtNy, engineOutputY); j++;
447 XtSetValues(shell, args, j);
448 // XtSetKeyboardFocus(shell, edit);
453 void ResizeWindowControls(shell, mode)
460 Dimension ew_height, tmp;
462 form1 = XtNameToWidget(shell, "*form");
463 form2 = XtNameToWidget(shell, "*form2");
466 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
467 XtGetValues(form1, args, j);
469 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
470 XtGetValues(form2, args, j);
471 ew_height += tmp; // total height
475 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
476 XtSetValues(form2, args, j);
478 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
479 XtSetValues(form1, args, j);
482 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
483 XtSetValues(form1, args, j);
485 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
486 XtSetValues(form2, args, j);
496 static char *title = _("Engine output"), *text = _("This feature is experimental");
498 if (engineOutputShell == NULL) {
500 EngineOutputCreate(title, text);
501 XtRealizeWidget(engineOutputShell);
502 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
504 InitializeEngineOutput();
507 SetEngineColorIcon( 0 );
508 SetEngineColorIcon( 1 );
509 SetEngineState( 0, STATE_IDLE, "" );
510 SetEngineState( 1, STATE_IDLE, "" );
512 edit = XtNameToWidget(engineOutputShell, "*form.text");
514 XtSetArg(args[j], XtNstring, text); j++;
515 XtSetValues(edit, args, j);
517 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
518 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
519 XtSetValues(engineOutputShell, args, j);
522 XtPopup(engineOutputShell, XtGrabNone);
523 XSync(xDisplay, False);
526 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
527 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
530 engineOutputDialogUp = True;
531 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
534 void EngineOutputPopDown()
539 if (!engineOutputDialogUp) return;
542 XtSetArg(args[j], XtNx, &engineOutputX); j++;
543 XtSetArg(args[j], XtNy, &engineOutputY); j++;
544 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
545 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
546 XtGetValues(engineOutputShell, args, j);
547 XtPopdown(engineOutputShell);
548 XSync(xDisplay, False);
550 XtSetArg(args[j], XtNleftBitmap, None); j++;
551 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
554 engineOutputDialogUp = False;
555 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
558 //------------------------ pure back-end routines -------------------------------
561 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
562 static void SetEngineState( int which, int state, char * state_data )
564 int x_which = 1 - which;
566 if( engineState[ which ] != state ) {
567 engineState[ which ] = state;
571 SetIcon( which, nStateIcon, nThinking );
572 if( engineState[ x_which ] == STATE_THINKING ) {
573 SetEngineState( x_which, STATE_IDLE, "" );
576 case STATE_PONDERING:
577 SetIcon( which, nStateIcon, nPondering );
579 case STATE_ANALYZING:
580 SetIcon( which, nStateIcon, nAnalyzing );
583 SetIcon( which, nStateIcon, nClear );
588 if( state_data != 0 ) {
589 DoSetWindowText( which, nStateData, state_data );
593 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
594 void EngineOutputUpdate( FrontEndProgramStats * stats )
597 int clearMemo = FALSE;
602 SetEngineState( 0, STATE_IDLE, "" );
603 SetEngineState( 1, STATE_IDLE, "" );
607 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
608 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
610 which = stats->which;
611 depth = stats->depth;
613 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
617 if( engineOutputShell == NULL ) {
625 ed.nodes = stats->nodes;
626 ed.score = stats->score;
627 ed.time = stats->time;
629 ed.hint = stats->hint;
630 ed.an_move_index = stats->an_move_index;
631 ed.an_move_count = stats->an_move_count;
633 /* Get target control. [HGM] this is moved to front end, which get them from a table */
635 ed.name = first.tidy;
638 ed.name = second.tidy;
641 /* Clear memo if needed */
642 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
646 if( lastForwardMostMove[which] != forwardMostMove ) {
650 if( clearMemo ) DoClearMemo(which);
653 lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge
654 lastForwardMostMove[which] = forwardMostMove;
656 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
657 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
662 UpdateControls( &ed );
665 #define ENGINE_COLOR_WHITE 'w'
666 #define ENGINE_COLOR_BLACK 'b'
667 #define ENGINE_COLOR_UNKNOWN ' '
670 char GetEngineColor( int which )
672 char result = ENGINE_COLOR_UNKNOWN;
674 if( which == 0 || which == 1 ) {
675 ChessProgramState * cps;
678 case MachinePlaysBlack:
679 case IcsPlayingBlack:
680 result = ENGINE_COLOR_BLACK;
682 case MachinePlaysWhite:
683 case IcsPlayingWhite:
684 result = ENGINE_COLOR_WHITE;
688 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
690 case TwoMachinesPlay:
691 cps = (which == 0) ? &first : &second;
692 result = cps->twoMachinesColor[0];
693 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
702 char GetActiveEngineColor()
704 char result = ENGINE_COLOR_UNKNOWN;
706 if( gameMode == TwoMachinesPlay ) {
707 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
714 static int IsEnginePondering( int which )
719 case MachinePlaysBlack:
720 case IcsPlayingBlack:
721 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
723 case MachinePlaysWhite:
724 case IcsPlayingWhite:
725 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
727 case TwoMachinesPlay:
728 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
729 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
738 static void SetDisplayMode( int mode )
740 if( windowMode != mode ) {
743 ResizeWindowControls( engineOutputShell, mode );
748 void VerifyDisplayMode()
752 /* Get proper mode for current game */
754 case IcsObserving: // [HGM] ICS analyze
755 if(!appData.icsEngineAnalyze) return;
758 case MachinePlaysWhite:
759 case MachinePlaysBlack:
762 case IcsPlayingWhite:
763 case IcsPlayingBlack:
764 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
766 case TwoMachinesPlay:
774 SetDisplayMode( mode );
777 // back end. Determine what icon to se in the color-icon field, and print it
778 static void SetEngineColorIcon( int which )
780 char color = GetEngineColor(which);
783 if( color == ENGINE_COLOR_BLACK )
785 else if( color == ENGINE_COLOR_WHITE )
788 nicon = nColorUnknown;
790 SetIcon( which, nColorIcon, nicon );
793 #define MAX_NAME_LENGTH 32
795 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
796 static void UpdateControls( EngineOutputData * ed )
798 int isPondering = FALSE;
800 char s_label[MAX_NAME_LENGTH + 32];
802 char * name = ed->name;
805 if( name == 0 || *name == '\0' ) {
809 strncpy( s_label, name, MAX_NAME_LENGTH );
810 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
812 #ifdef SHOW_PONDERING
813 if( IsEnginePondering( ed->which ) ) {
818 if( ed->hint != 0 && *ed->hint != '\0' ) {
819 strncpy( buf, ed->hint, sizeof(buf) );
820 buf[sizeof(buf)-1] = '\0';
822 else if( ed->pv != 0 && *ed->pv != '\0' ) {
823 char * sep = strchr( ed->pv, ' ' );
824 int buflen = sizeof(buf);
827 buflen = sep - ed->pv + 1;
828 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
831 strncpy( buf, ed->pv, buflen );
832 buf[ buflen-1 ] = '\0';
835 SetEngineState( ed->which, STATE_PONDERING, buf );
837 else if( gameMode == TwoMachinesPlay ) {
838 SetEngineState( ed->which, STATE_THINKING, "" );
840 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
841 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
843 int time_secs = ed->time / 100;
844 int time_mins = time_secs / 60;
848 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
851 strncpy( mov, ed->hint, sizeof(mov) );
852 mov[ sizeof(mov)-1 ] = '\0';
854 sprintf( buf, "[%d] %d/%d: %s [%02d:%02d:%02d]", ed->depth, ed->an_move_index,
855 ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 );
858 SetEngineState( ed->which, STATE_ANALYZING, buf );
861 SetEngineState( ed->which, STATE_IDLE, "" );
865 DoSetWindowText( ed->which, nLabel, s_label );
869 if( ed->time > 0 && ed->nodes > 0 ) {
870 unsigned long nps_100 = ed->nodes / ed->time;
872 if( nps_100 < 100000 ) {
873 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
876 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
880 DoSetWindowText( ed->which, nLabelNPS, s_label );
883 if( ed->pv != 0 && *ed->pv != '\0' ) {
889 int time_secs = ed->time / 100;
890 int time_cent = ed->time % 100;
893 if( ed->nodes < 1000000 ) {
894 sprintf( s_nodes, u64Display, ed->nodes );
897 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
901 if( ed->score > 0 ) {
902 sprintf( s_score, "+%.2f", ed->score / 100.0 );
904 sprintf( s_score, "%.2f", ed->score / 100.0 );
907 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
909 /* Put all together... */
910 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else
911 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
914 buflen = strlen(buf);
916 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
918 buf[ sizeof(buf) - 3 ] = '\0';
920 strcat( buf + buflen, "\n" );
923 InsertIntoMemo( ed->which, buf );
927 SetEngineColorIcon( ed->which );
931 int EngineOutputIsUp()
933 return engineOutputDialogUp;
937 EngineOutputProc(w, event, prms, nprms)
943 if (engineOutputDialogUp) {
944 EngineOutputPopDown();
948 // ToNrEvent(currentMove);
951 // [HGM] kibitz: write kibitz line; split window for it if necessary
952 void OutputKibitz(int window, char *text)
954 if(!EngineOutputIsUp()) return;
955 if(!opponentKibitzes) { // on first kibitz of game, clear memos
957 if(gameMode == IcsObserving) DoClearMemo(0);
959 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
961 if(gameMode == IcsObserving) {
962 DoSetWindowText(0, nLabel, gameInfo.white);
963 SetIcon( 0, nColorIcon, nColorWhite);
964 SetIcon( 0, nStateIcon, nClear);
966 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
967 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
968 SetIcon( 1, nStateIcon, nClear);
969 InsertIntoMemo(window-1, text);