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 /* the backend adds \r\n, which is needed for winboard,
234 * for xboard we delete them again over here */
235 if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
237 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
238 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
239 XawTextReplace(edit, 0, 0, &t);
240 // XtSetArg(arg, XtNstring, (XtArgVal) text);
241 // XtSetValues(outputField[which][nMemo], &arg, 1);
244 static void SetIcon( int which, int field, int nIcon )
249 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
250 XtSetValues(outputField[which][field], &arg, 1);
254 void DoClearMemo(int which)
260 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
261 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
262 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
265 // The following routines are mutated clones of the commentPopUp routines
267 void PositionControlSet(which, form, bw_width)
273 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
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,
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,
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,
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,
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,
342 // create "text" within "form"
345 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
346 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
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);
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++;
389 XtCreatePopupShell(name, topLevelShellWidgetClass,
391 XtCreatePopupShell(name, transientShellWidgetClass,
393 shellWidget, args, j);
395 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
396 layoutArgs, XtNumber(layoutArgs));
397 // divide window vertically into two equal parts, by creating two forms
399 XtCreateManagedWidget("form", formWidgetClass, layout,
400 formArgs, XtNumber(formArgs));
402 XtCreateManagedWidget("form2", formWidgetClass, layout,
403 formArgs, XtNumber(formArgs));
405 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
406 XtSetValues(form2, args, j);
407 // make sure width is known in advance, for better placement of child widgets
409 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
410 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
411 XtSetValues(shell, args, j);
413 // fill up both forms with control elements
414 PositionControlSet(0, form, bw_width);
415 PositionControlSet(1, form2, bw_width);
417 XtRealizeWidget(shell);
419 if (engineOutputX == -1) {
424 engineOutputH = bw_height/2;
425 engineOutputW = bw_width-16;
427 XSync(xDisplay, False);
429 /* This code seems to tickle an X bug if it is executed too soon
430 after xboard starts up. The coordinates get transformed as if
431 the main window was positioned at (0, 0).
433 XtTranslateCoords(shellWidget,
434 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
435 &engineOutputX, &engineOutputY);
437 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
438 RootWindowOfScreen(XtScreen(shellWidget)),
439 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
444 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
447 XtSetArg(args[j], XtNheight, engineOutputH); j++;
448 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
449 XtSetArg(args[j], XtNx, engineOutputX); j++;
450 XtSetArg(args[j], XtNy, engineOutputY); j++;
451 XtSetValues(shell, args, j);
452 // XtSetKeyboardFocus(shell, edit);
457 void ResizeWindowControls(shell, mode)
464 Dimension ew_height, tmp;
466 form1 = XtNameToWidget(shell, "*form");
467 form2 = XtNameToWidget(shell, "*form2");
470 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
471 XtGetValues(form1, args, j);
473 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
474 XtGetValues(form2, args, j);
475 ew_height += tmp; // total height
479 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
480 XtSetValues(form2, args, j);
482 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
483 XtSetValues(form1, args, j);
486 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
487 XtSetValues(form1, args, j);
489 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
490 XtSetValues(form2, args, j);
500 static char *title = _("Engine output"), *text = _("This feature is experimental");
502 if (engineOutputShell == NULL) {
504 EngineOutputCreate(title, text);
505 XtRealizeWidget(engineOutputShell);
506 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
508 InitializeEngineOutput();
511 SetEngineColorIcon( 0 );
512 SetEngineColorIcon( 1 );
513 SetEngineState( 0, STATE_IDLE, "" );
514 SetEngineState( 1, STATE_IDLE, "" );
516 edit = XtNameToWidget(engineOutputShell, "*form.text");
518 XtSetArg(args[j], XtNstring, text); j++;
519 XtSetValues(edit, args, j);
521 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
522 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
523 XtSetValues(engineOutputShell, args, j);
526 XtPopup(engineOutputShell, XtGrabNone);
527 XSync(xDisplay, False);
530 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
531 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
534 engineOutputDialogUp = True;
535 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
538 void EngineOutputPopDown()
543 if (!engineOutputDialogUp) return;
546 XtSetArg(args[j], XtNx, &engineOutputX); j++;
547 XtSetArg(args[j], XtNy, &engineOutputY); j++;
548 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
549 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
550 XtGetValues(engineOutputShell, args, j);
551 XtPopdown(engineOutputShell);
552 XSync(xDisplay, False);
554 XtSetArg(args[j], XtNleftBitmap, None); j++;
555 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
558 engineOutputDialogUp = False;
559 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
562 //------------------------ pure back-end routines -------------------------------
565 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
566 static void SetEngineState( int which, int state, char * state_data )
568 int x_which = 1 - which;
570 if( engineState[ which ] != state ) {
571 engineState[ which ] = state;
575 SetIcon( which, nStateIcon, nThinking );
576 if( engineState[ x_which ] == STATE_THINKING ) {
577 SetEngineState( x_which, STATE_IDLE, "" );
580 case STATE_PONDERING:
581 SetIcon( which, nStateIcon, nPondering );
583 case STATE_ANALYZING:
584 SetIcon( which, nStateIcon, nAnalyzing );
587 SetIcon( which, nStateIcon, nClear );
592 if( state_data != 0 ) {
593 DoSetWindowText( which, nStateData, state_data );
597 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
598 void EngineOutputUpdate( FrontEndProgramStats * stats )
601 int clearMemo = FALSE;
606 SetEngineState( 0, STATE_IDLE, "" );
607 SetEngineState( 1, STATE_IDLE, "" );
611 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
612 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
614 which = stats->which;
615 depth = stats->depth;
617 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
621 if( engineOutputShell == NULL ) {
629 ed.nodes = stats->nodes;
630 ed.score = stats->score;
631 ed.time = stats->time;
633 ed.hint = stats->hint;
634 ed.an_move_index = stats->an_move_index;
635 ed.an_move_count = stats->an_move_count;
637 /* Get target control. [HGM] this is moved to front end, which get them from a table */
639 ed.name = first.tidy;
642 ed.name = second.tidy;
645 /* Clear memo if needed */
646 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
650 if( lastForwardMostMove[which] != forwardMostMove ) {
654 if( clearMemo ) DoClearMemo(which);
657 lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge
658 lastForwardMostMove[which] = forwardMostMove;
660 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
661 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
666 UpdateControls( &ed );
669 #define ENGINE_COLOR_WHITE 'w'
670 #define ENGINE_COLOR_BLACK 'b'
671 #define ENGINE_COLOR_UNKNOWN ' '
674 char GetEngineColor( int which )
676 char result = ENGINE_COLOR_UNKNOWN;
678 if( which == 0 || which == 1 ) {
679 ChessProgramState * cps;
682 case MachinePlaysBlack:
683 case IcsPlayingBlack:
684 result = ENGINE_COLOR_BLACK;
686 case MachinePlaysWhite:
687 case IcsPlayingWhite:
688 result = ENGINE_COLOR_WHITE;
692 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
694 case TwoMachinesPlay:
695 cps = (which == 0) ? &first : &second;
696 result = cps->twoMachinesColor[0];
697 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
706 char GetActiveEngineColor()
708 char result = ENGINE_COLOR_UNKNOWN;
710 if( gameMode == TwoMachinesPlay ) {
711 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
718 static int IsEnginePondering( int which )
723 case MachinePlaysBlack:
724 case IcsPlayingBlack:
725 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
727 case MachinePlaysWhite:
728 case IcsPlayingWhite:
729 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
731 case TwoMachinesPlay:
732 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
733 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
742 static void SetDisplayMode( int mode )
744 if( windowMode != mode ) {
747 ResizeWindowControls( engineOutputShell, mode );
752 void VerifyDisplayMode()
756 /* Get proper mode for current game */
758 case IcsObserving: // [HGM] ICS analyze
759 if(!appData.icsEngineAnalyze) return;
762 case MachinePlaysWhite:
763 case MachinePlaysBlack:
766 case IcsPlayingWhite:
767 case IcsPlayingBlack:
768 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
770 case TwoMachinesPlay:
778 SetDisplayMode( mode );
781 // back end. Determine what icon to se in the color-icon field, and print it
782 static void SetEngineColorIcon( int which )
784 char color = GetEngineColor(which);
787 if( color == ENGINE_COLOR_BLACK )
789 else if( color == ENGINE_COLOR_WHITE )
792 nicon = nColorUnknown;
794 SetIcon( which, nColorIcon, nicon );
797 #define MAX_NAME_LENGTH 32
799 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
800 static void UpdateControls( EngineOutputData * ed )
802 int isPondering = FALSE;
804 char s_label[MAX_NAME_LENGTH + 32];
806 char * name = ed->name;
809 if( name == 0 || *name == '\0' ) {
813 strncpy( s_label, name, MAX_NAME_LENGTH );
814 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
816 #ifdef SHOW_PONDERING
817 if( IsEnginePondering( ed->which ) ) {
822 if( ed->hint != 0 && *ed->hint != '\0' ) {
823 strncpy( buf, ed->hint, sizeof(buf) );
824 buf[sizeof(buf)-1] = '\0';
826 else if( ed->pv != 0 && *ed->pv != '\0' ) {
827 char * sep = strchr( ed->pv, ' ' );
828 int buflen = sizeof(buf);
831 buflen = sep - ed->pv + 1;
832 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
835 strncpy( buf, ed->pv, buflen );
836 buf[ buflen-1 ] = '\0';
839 SetEngineState( ed->which, STATE_PONDERING, buf );
841 else if( gameMode == TwoMachinesPlay ) {
842 SetEngineState( ed->which, STATE_THINKING, "" );
844 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
845 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
847 int time_secs = ed->time / 100;
848 int time_mins = time_secs / 60;
852 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
855 strncpy( mov, ed->hint, sizeof(mov) );
856 mov[ sizeof(mov)-1 ] = '\0';
858 sprintf( buf, "[%d] %d/%d: %s [%02d:%02d:%02d]", ed->depth, ed->an_move_index,
859 ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 );
862 SetEngineState( ed->which, STATE_ANALYZING, buf );
865 SetEngineState( ed->which, STATE_IDLE, "" );
869 DoSetWindowText( ed->which, nLabel, s_label );
873 if( ed->time > 0 && ed->nodes > 0 ) {
874 unsigned long nps_100 = ed->nodes / ed->time;
876 if( nps_100 < 100000 ) {
877 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
880 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
884 DoSetWindowText( ed->which, nLabelNPS, s_label );
887 if( ed->pv != 0 && *ed->pv != '\0' ) {
893 int time_secs = ed->time / 100;
894 int time_cent = ed->time % 100;
897 if( ed->nodes < 1000000 ) {
898 sprintf( s_nodes, u64Display, ed->nodes );
901 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
905 if( ed->score > 0 ) {
906 sprintf( s_score, "+%.2f", ed->score / 100.0 );
908 sprintf( s_score, "%.2f", ed->score / 100.0 );
911 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
913 /* Put all together... */
914 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else
915 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
918 buflen = strlen(buf);
920 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
922 buf[ sizeof(buf) - 3 ] = '\0';
924 strcat( buf + buflen, "\n" );
927 InsertIntoMemo( ed->which, buf );
931 SetEngineColorIcon( ed->which );
935 int EngineOutputIsUp()
937 return engineOutputDialogUp;
941 EngineOutputProc(w, event, prms, nprms)
947 if (engineOutputDialogUp) {
948 EngineOutputPopDown();
952 // ToNrEvent(currentMove);
955 // [HGM] kibitz: write kibitz line; split window for it if necessary
956 void OutputKibitz(int window, char *text)
958 if(!EngineOutputIsUp()) return;
959 if(!opponentKibitzes) { // on first kibitz of game, clear memos
961 if(gameMode == IcsObserving) DoClearMemo(0);
963 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
965 if(gameMode == IcsObserving) {
966 DoSetWindowText(0, nLabel, gameInfo.white);
967 SetIcon( 0, nColorIcon, nColorWhite);
968 SetIcon( 0, nStateIcon, nClear);
970 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
971 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
972 SetIcon( 1, nStateIcon, nClear);
973 InsertIntoMemo(window-1, text);