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++;
384 XtCreatePopupShell(name, transientShellWidgetClass,
385 shellWidget, args, j);
387 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
388 layoutArgs, XtNumber(layoutArgs));
389 // divide window vertically into two equal parts, by creating two forms
391 XtCreateManagedWidget("form", formWidgetClass, layout,
392 formArgs, XtNumber(formArgs));
394 XtCreateManagedWidget("form2", formWidgetClass, layout,
395 formArgs, XtNumber(formArgs));
397 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
398 XtSetValues(form2, args, j);
399 // make sure width is known in advance, for better placement of child widgets
401 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
402 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
403 XtSetValues(shell, args, j);
405 // fill up both forms with control elements
406 PositionControlSet(0, form, bw_width);
407 PositionControlSet(1, form2, bw_width);
409 XtRealizeWidget(shell);
411 if (engineOutputX == -1) {
416 engineOutputH = bw_height/2;
417 engineOutputW = bw_width-16;
419 XSync(xDisplay, False);
421 /* This code seems to tickle an X bug if it is executed too soon
422 after xboard starts up. The coordinates get transformed as if
423 the main window was positioned at (0, 0).
425 XtTranslateCoords(shellWidget,
426 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
427 &engineOutputX, &engineOutputY);
429 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
430 RootWindowOfScreen(XtScreen(shellWidget)),
431 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
436 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
439 XtSetArg(args[j], XtNheight, engineOutputH); j++;
440 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
441 XtSetArg(args[j], XtNx, engineOutputX); j++;
442 XtSetArg(args[j], XtNy, engineOutputY); j++;
443 XtSetValues(shell, args, j);
444 // XtSetKeyboardFocus(shell, edit);
449 void ResizeWindowControls(shell, mode)
456 Dimension ew_height, tmp;
458 form1 = XtNameToWidget(shell, "*form");
459 form2 = XtNameToWidget(shell, "*form2");
462 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
463 XtGetValues(form1, args, j);
465 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
466 XtGetValues(form2, args, j);
467 ew_height += tmp; // total height
471 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
472 XtSetValues(form2, args, j);
474 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
475 XtSetValues(form1, args, j);
478 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
479 XtSetValues(form1, args, j);
481 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
482 XtSetValues(form2, args, j);
492 static char *title = _("Engine output"), *text = _("This feature is experimental");
494 if (engineOutputShell == NULL) {
496 EngineOutputCreate(title, text);
497 XtRealizeWidget(engineOutputShell);
498 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
500 InitializeEngineOutput();
503 SetEngineColorIcon( 0 );
504 SetEngineColorIcon( 1 );
505 SetEngineState( 0, STATE_IDLE, "" );
506 SetEngineState( 1, STATE_IDLE, "" );
508 edit = XtNameToWidget(engineOutputShell, "*form.text");
510 XtSetArg(args[j], XtNstring, text); j++;
511 XtSetValues(edit, args, j);
513 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
514 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
515 XtSetValues(engineOutputShell, args, j);
518 XtPopup(engineOutputShell, XtGrabNone);
519 XSync(xDisplay, False);
522 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
523 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
526 engineOutputDialogUp = True;
527 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
530 void EngineOutputPopDown()
535 if (!engineOutputDialogUp) return;
538 XtSetArg(args[j], XtNx, &engineOutputX); j++;
539 XtSetArg(args[j], XtNy, &engineOutputY); j++;
540 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
541 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
542 XtGetValues(engineOutputShell, args, j);
543 XtPopdown(engineOutputShell);
544 XSync(xDisplay, False);
546 XtSetArg(args[j], XtNleftBitmap, None); j++;
547 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
550 engineOutputDialogUp = False;
551 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
554 //------------------------ pure back-end routines -------------------------------
557 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
558 static void SetEngineState( int which, int state, char * state_data )
560 int x_which = 1 - which;
562 if( engineState[ which ] != state ) {
563 engineState[ which ] = state;
567 SetIcon( which, nStateIcon, nThinking );
568 if( engineState[ x_which ] == STATE_THINKING ) {
569 SetEngineState( x_which, STATE_IDLE, "" );
572 case STATE_PONDERING:
573 SetIcon( which, nStateIcon, nPondering );
575 case STATE_ANALYZING:
576 SetIcon( which, nStateIcon, nAnalyzing );
579 SetIcon( which, nStateIcon, nClear );
584 if( state_data != 0 ) {
585 DoSetWindowText( which, nStateData, state_data );
589 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
590 void EngineOutputUpdate( FrontEndProgramStats * stats )
593 int clearMemo = FALSE;
598 SetEngineState( 0, STATE_IDLE, "" );
599 SetEngineState( 1, STATE_IDLE, "" );
603 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
604 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
606 which = stats->which;
607 depth = stats->depth;
609 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
613 if( engineOutputShell == NULL ) {
621 ed.nodes = stats->nodes;
622 ed.score = stats->score;
623 ed.time = stats->time;
625 ed.hint = stats->hint;
626 ed.an_move_index = stats->an_move_index;
627 ed.an_move_count = stats->an_move_count;
629 /* Get target control. [HGM] this is moved to front end, which get them from a table */
631 ed.name = first.tidy;
634 ed.name = second.tidy;
637 /* Clear memo if needed */
638 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
642 if( lastForwardMostMove[which] != forwardMostMove ) {
646 if( clearMemo ) DoClearMemo(which);
649 lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge
650 lastForwardMostMove[which] = forwardMostMove;
652 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
653 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
658 UpdateControls( &ed );
661 #define ENGINE_COLOR_WHITE 'w'
662 #define ENGINE_COLOR_BLACK 'b'
663 #define ENGINE_COLOR_UNKNOWN ' '
666 char GetEngineColor( int which )
668 char result = ENGINE_COLOR_UNKNOWN;
670 if( which == 0 || which == 1 ) {
671 ChessProgramState * cps;
674 case MachinePlaysBlack:
675 case IcsPlayingBlack:
676 result = ENGINE_COLOR_BLACK;
678 case MachinePlaysWhite:
679 case IcsPlayingWhite:
680 result = ENGINE_COLOR_WHITE;
684 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
686 case TwoMachinesPlay:
687 cps = (which == 0) ? &first : &second;
688 result = cps->twoMachinesColor[0];
689 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
698 char GetActiveEngineColor()
700 char result = ENGINE_COLOR_UNKNOWN;
702 if( gameMode == TwoMachinesPlay ) {
703 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
710 static int IsEnginePondering( int which )
715 case MachinePlaysBlack:
716 case IcsPlayingBlack:
717 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
719 case MachinePlaysWhite:
720 case IcsPlayingWhite:
721 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
723 case TwoMachinesPlay:
724 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
725 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
734 static void SetDisplayMode( int mode )
736 if( windowMode != mode ) {
739 ResizeWindowControls( engineOutputShell, mode );
744 void VerifyDisplayMode()
748 /* Get proper mode for current game */
750 case IcsObserving: // [HGM] ICS analyze
751 if(!appData.icsEngineAnalyze) return;
754 case MachinePlaysWhite:
755 case MachinePlaysBlack:
758 case IcsPlayingWhite:
759 case IcsPlayingBlack:
760 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
762 case TwoMachinesPlay:
770 SetDisplayMode( mode );
773 // back end. Determine what icon to se in the color-icon field, and print it
774 static void SetEngineColorIcon( int which )
776 char color = GetEngineColor(which);
779 if( color == ENGINE_COLOR_BLACK )
781 else if( color == ENGINE_COLOR_WHITE )
784 nicon = nColorUnknown;
786 SetIcon( which, nColorIcon, nicon );
789 #define MAX_NAME_LENGTH 32
791 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
792 static void UpdateControls( EngineOutputData * ed )
794 int isPondering = FALSE;
796 char s_label[MAX_NAME_LENGTH + 32];
798 char * name = ed->name;
801 if( name == 0 || *name == '\0' ) {
805 strncpy( s_label, name, MAX_NAME_LENGTH );
806 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
808 #ifdef SHOW_PONDERING
809 if( IsEnginePondering( ed->which ) ) {
814 if( ed->hint != 0 && *ed->hint != '\0' ) {
815 strncpy( buf, ed->hint, sizeof(buf) );
816 buf[sizeof(buf)-1] = '\0';
818 else if( ed->pv != 0 && *ed->pv != '\0' ) {
819 char * sep = strchr( ed->pv, ' ' );
820 int buflen = sizeof(buf);
823 buflen = sep - ed->pv + 1;
824 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
827 strncpy( buf, ed->pv, buflen );
828 buf[ buflen-1 ] = '\0';
831 SetEngineState( ed->which, STATE_PONDERING, buf );
833 else if( gameMode == TwoMachinesPlay ) {
834 SetEngineState( ed->which, STATE_THINKING, "" );
836 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
837 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
839 int time_secs = ed->time / 100;
840 int time_mins = time_secs / 60;
844 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
847 strncpy( mov, ed->hint, sizeof(mov) );
848 mov[ sizeof(mov)-1 ] = '\0';
850 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 );
853 SetEngineState( ed->which, STATE_ANALYZING, buf );
856 SetEngineState( ed->which, STATE_IDLE, "" );
860 DoSetWindowText( ed->which, nLabel, s_label );
864 if( ed->time > 0 && ed->nodes > 0 ) {
865 unsigned long nps_100 = ed->nodes / ed->time;
867 if( nps_100 < 100000 ) {
868 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
871 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
875 DoSetWindowText( ed->which, nLabelNPS, s_label );
878 if( ed->pv != 0 && *ed->pv != '\0' ) {
884 int time_secs = ed->time / 100;
885 int time_cent = ed->time % 100;
888 if( ed->nodes < 1000000 ) {
889 sprintf( s_nodes, u64Display, ed->nodes );
892 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
896 if( ed->score > 0 ) {
897 sprintf( s_score, "+%.2f", ed->score / 100.0 );
899 sprintf( s_score, "%.2f", ed->score / 100.0 );
902 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
904 /* Put all together... */
905 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else
906 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
909 buflen = strlen(buf);
911 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
913 buf[ sizeof(buf) - 3 ] = '\0';
915 strcat( buf + buflen, "\n" );
918 InsertIntoMemo( ed->which, buf );
922 SetEngineColorIcon( ed->which );
926 int EngineOutputIsUp()
928 return engineOutputDialogUp;
932 EngineOutputProc(w, event, prms, nprms)
938 if (engineOutputDialogUp) {
939 EngineOutputPopDown();
943 // ToNrEvent(currentMove);
946 // [HGM] kibitz: write kibitz line; split window for it if necessary
947 void OutputKibitz(int window, char *text)
949 if(!EngineOutputIsUp()) return;
950 if(!opponentKibitzes) { // on first kibitz of game, clear memos
952 if(gameMode == IcsObserving) DoClearMemo(0);
954 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
956 if(gameMode == IcsObserving) {
957 DoSetWindowText(0, nLabel, gameInfo.white);
958 SetIcon( 0, nColorIcon, nColorWhite);
959 SetIcon( 0, nStateIcon, nClear);
961 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
962 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
963 SetIcon( 1, nStateIcon, nClear);
964 InsertIntoMemo(window-1, text);