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 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);
486 void EngineOutputPopUp(title, text)
493 if (engineOutputShell == NULL) {
495 EngineOutputCreate(title, text);
496 XtRealizeWidget(engineOutputShell);
497 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
499 InitializeEngineOutput();
502 SetEngineColorIcon( 0 );
503 SetEngineColorIcon( 1 );
504 SetEngineState( 0, STATE_IDLE, "" );
505 SetEngineState( 1, STATE_IDLE, "" );
507 edit = XtNameToWidget(engineOutputShell, "*form.text");
509 XtSetArg(args[j], XtNstring, text); j++;
510 XtSetValues(edit, args, j);
512 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
513 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
514 XtSetValues(engineOutputShell, args, j);
517 XtPopup(engineOutputShell, XtGrabNone);
518 XSync(xDisplay, False);
521 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
522 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
525 engineOutputDialogUp = True;
526 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
529 void EngineOutputPopDown()
534 if (!engineOutputDialogUp) return;
537 XtSetArg(args[j], XtNx, &engineOutputX); j++;
538 XtSetArg(args[j], XtNy, &engineOutputY); j++;
539 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
540 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
541 XtGetValues(engineOutputShell, args, j);
542 XtPopdown(engineOutputShell);
543 XSync(xDisplay, False);
545 XtSetArg(args[j], XtNleftBitmap, None); j++;
546 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
549 engineOutputDialogUp = False;
550 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
553 //------------------------ pure back-end routines -------------------------------
556 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments
557 static void SetEngineState( int which, int state, char * state_data )
559 int x_which = 1 - which;
561 if( engineState[ which ] != state ) {
562 engineState[ which ] = state;
566 SetIcon( which, nStateIcon, nThinking );
567 if( engineState[ x_which ] == STATE_THINKING ) {
568 SetEngineState( x_which, STATE_IDLE, "" );
571 case STATE_PONDERING:
572 SetIcon( which, nStateIcon, nPondering );
574 case STATE_ANALYZING:
575 SetIcon( which, nStateIcon, nAnalyzing );
578 SetIcon( which, nStateIcon, nClear );
583 if( state_data != 0 ) {
584 DoSetWindowText( which, nStateData, state_data );
588 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.
589 void EngineOutputUpdate( FrontEndProgramStats * stats )
592 int clearMemo = FALSE;
597 SetEngineState( 0, STATE_IDLE, "" );
598 SetEngineState( 1, STATE_IDLE, "" );
602 if(gameMode == IcsObserving && !appData.icsEngineAnalyze)
603 return; // [HGM] kibitz: shut up engine if we are observing an ICS game
605 which = stats->which;
606 depth = stats->depth;
608 if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {
612 if( engineOutputShell == NULL ) {
620 ed.nodes = stats->nodes;
621 ed.score = stats->score;
622 ed.time = stats->time;
624 ed.hint = stats->hint;
625 ed.an_move_index = stats->an_move_index;
626 ed.an_move_count = stats->an_move_count;
628 /* Get target control. [HGM] this is moved to front end, which get them from a table */
630 ed.name = first.tidy;
633 ed.name = second.tidy;
636 /* Clear memo if needed */
637 if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {
641 if( lastForwardMostMove[which] != forwardMostMove ) {
645 if( clearMemo ) DoClearMemo(which);
648 lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge
649 lastForwardMostMove[which] = forwardMostMove;
651 if( ed.pv != 0 && ed.pv[0] == ' ' ) {
652 if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */
657 UpdateControls( &ed );
660 #define ENGINE_COLOR_WHITE 'w'
661 #define ENGINE_COLOR_BLACK 'b'
662 #define ENGINE_COLOR_UNKNOWN ' '
665 char GetEngineColor( int which )
667 char result = ENGINE_COLOR_UNKNOWN;
669 if( which == 0 || which == 1 ) {
670 ChessProgramState * cps;
673 case MachinePlaysBlack:
674 case IcsPlayingBlack:
675 result = ENGINE_COLOR_BLACK;
677 case MachinePlaysWhite:
678 case IcsPlayingWhite:
679 result = ENGINE_COLOR_WHITE;
683 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
685 case TwoMachinesPlay:
686 cps = (which == 0) ? &first : &second;
687 result = cps->twoMachinesColor[0];
688 result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
697 char GetActiveEngineColor()
699 char result = ENGINE_COLOR_UNKNOWN;
701 if( gameMode == TwoMachinesPlay ) {
702 result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;
709 static int IsEnginePondering( int which )
714 case MachinePlaysBlack:
715 case IcsPlayingBlack:
716 if( WhiteOnMove(forwardMostMove) ) result = TRUE;
718 case MachinePlaysWhite:
719 case IcsPlayingWhite:
720 if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;
722 case TwoMachinesPlay:
723 if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {
724 if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;
733 static void SetDisplayMode( int mode )
735 if( windowMode != mode ) {
738 ResizeWindowControls( engineOutputShell, mode );
743 void VerifyDisplayMode()
747 /* Get proper mode for current game */
749 case IcsObserving: // [HGM] ICS analyze
750 if(!appData.icsEngineAnalyze) return;
753 case MachinePlaysWhite:
754 case MachinePlaysBlack:
757 case IcsPlayingWhite:
758 case IcsPlayingBlack:
759 mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz
761 case TwoMachinesPlay:
769 SetDisplayMode( mode );
772 // back end. Determine what icon to se in the color-icon field, and print it
773 static void SetEngineColorIcon( int which )
775 char color = GetEngineColor(which);
778 if( color == ENGINE_COLOR_BLACK )
780 else if( color == ENGINE_COLOR_WHITE )
783 nicon = nColorUnknown;
785 SetIcon( which, nColorIcon, nicon );
788 #define MAX_NAME_LENGTH 32
790 // pure back end, now SetWindowText is called via wrapper DoSetWindowText
791 static void UpdateControls( EngineOutputData * ed )
793 int isPondering = FALSE;
795 char s_label[MAX_NAME_LENGTH + 32];
797 char * name = ed->name;
800 if( name == 0 || *name == '\0' ) {
804 strncpy( s_label, name, MAX_NAME_LENGTH );
805 s_label[ MAX_NAME_LENGTH-1 ] = '\0';
807 #ifdef SHOW_PONDERING
808 if( IsEnginePondering( ed->which ) ) {
813 if( ed->hint != 0 && *ed->hint != '\0' ) {
814 strncpy( buf, ed->hint, sizeof(buf) );
815 buf[sizeof(buf)-1] = '\0';
817 else if( ed->pv != 0 && *ed->pv != '\0' ) {
818 char * sep = strchr( ed->pv, ' ' );
819 int buflen = sizeof(buf);
822 buflen = sep - ed->pv + 1;
823 if( buflen > sizeof(buf) ) buflen = sizeof(buf);
826 strncpy( buf, ed->pv, buflen );
827 buf[ buflen-1 ] = '\0';
830 SetEngineState( ed->which, STATE_PONDERING, buf );
832 else if( gameMode == TwoMachinesPlay ) {
833 SetEngineState( ed->which, STATE_THINKING, "" );
835 else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile
836 || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze
838 int time_secs = ed->time / 100;
839 int time_mins = time_secs / 60;
843 if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {
846 strncpy( mov, ed->hint, sizeof(mov) );
847 mov[ sizeof(mov)-1 ] = '\0';
849 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 );
852 SetEngineState( ed->which, STATE_ANALYZING, buf );
855 SetEngineState( ed->which, STATE_IDLE, "" );
859 DoSetWindowText( ed->which, nLabel, s_label );
863 if( ed->time > 0 && ed->nodes > 0 ) {
864 unsigned long nps_100 = ed->nodes / ed->time;
866 if( nps_100 < 100000 ) {
867 sprintf( s_label, _("NPS: %lu"), nps_100 * 100 );
870 sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 );
874 DoSetWindowText( ed->which, nLabelNPS, s_label );
877 if( ed->pv != 0 && *ed->pv != '\0' ) {
883 int time_secs = ed->time / 100;
884 int time_cent = ed->time % 100;
887 if( ed->nodes < 1000000 ) {
888 sprintf( s_nodes, u64Display, ed->nodes );
891 sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 );
895 if( ed->score > 0 ) {
896 sprintf( s_score, "+%.2f", ed->score / 100.0 );
898 sprintf( s_score, "%.2f", ed->score / 100.0 );
901 sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );
903 /* Put all together... */
904 if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else
905 sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time );
908 buflen = strlen(buf);
910 strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );
912 buf[ sizeof(buf) - 3 ] = '\0';
914 strcat( buf + buflen, "\n" );
917 InsertIntoMemo( ed->which, buf );
921 SetEngineColorIcon( ed->which );
925 int EngineOutputIsUp()
927 return engineOutputDialogUp;
931 EngineOutputProc(w, event, prms, nprms)
937 if (engineOutputDialogUp) {
938 EngineOutputPopDown();
940 EngineOutputPopUp(_("engine output"),_("This feature is experimental"));
942 // ToNrEvent(currentMove);
945 // [HGM] kibitz: write kibitz line; split window for it if necessary
946 void OutputKibitz(int window, char *text)
948 if(!EngineOutputIsUp()) return;
949 if(!opponentKibitzes) { // on first kibitz of game, clear memos
951 if(gameMode == IcsObserving) DoClearMemo(0);
953 opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
955 if(gameMode == IcsObserving) {
956 DoSetWindowText(0, nLabel, gameInfo.white);
957 SetIcon( 0, nColorIcon, nColorWhite);
958 SetIcon( 0, nStateIcon, nClear);
960 DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
961 SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
962 SetIcon( 1, nStateIcon, nClear);
963 InsertIntoMemo(window-1, text);