changes from H.G. Muller; version 4.3.16
[xboard.git] / xengineoutput.c
1 /*\r
2  * Engine output (PV)\r
3  *\r
4  * Author: Alessandro Scotti (Dec 2005)\r
5  *\r
6  * ------------------------------------------------------------------------\r
7  * This program is free software; you can redistribute it and/or modify\r
8  * it under the terms of the GNU General Public License as published by\r
9  * the Free Software Foundation; either version 2 of the License, or\r
10  * (at your option) any later version.\r
11  *\r
12  * This program is distributed in the hope that it will be useful,\r
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15  * GNU General Public License for more details.\r
16  *\r
17  * You should have received a copy of the GNU General Public License\r
18  * along with this program; if not, write to the Free Software\r
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
20  * ------------------------------------------------------------------------\r
21  */\r
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <sys/types.h>
28
29 #if STDC_HEADERS
30 # include <stdlib.h>
31 # include <string.h>
32 #else /* not STDC_HEADERS */
33 extern char *getenv();
34 # if HAVE_STRING_H
35 #  include <string.h>
36 # else /* not HAVE_STRING_H */
37 #  include <strings.h>
38 # endif /* not HAVE_STRING_H */
39 #endif /* not STDC_HEADERS */
40
41 #if HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44
45 #include <X11/Intrinsic.h>
46 #include <X11/StringDefs.h>
47 #include <X11/Shell.h>
48 #include <X11/Xaw/Dialog.h>
49 #include <X11/Xaw/Form.h>
50 #include <X11/Xaw/List.h>
51 #include <X11/Xaw/Label.h>
52 #include <X11/Xaw/SimpleMenu.h>
53 #include <X11/Xaw/SmeBSB.h>
54 #include <X11/Xaw/SmeLine.h>
55 #include <X11/Xaw/Box.h>
56 #include <X11/Xaw/Paned.h>
57 #include <X11/Xaw/MenuButton.h>
58 #include <X11/cursorfont.h>
59 #include <X11/Xaw/Text.h>
60 #include <X11/Xaw/AsciiText.h>
61 #include <X11/Xaw/Viewport.h>
62
63 #include "common.h"
64 #include "frontend.h"
65 #include "backend.h"
66 #include "xboard.h"
67 // Add xengineo.h later
68
69 #include <X11/xpm.h>\r
70
71 // [HGM] pixmaps of some ICONS used in the engine-outut window
72 #include "pixmaps/WHITE_14.xpm"
73 #include "pixmaps/BLACK_14.xpm"
74 #include "pixmaps/CLEAR_14.xpm"
75 #include "pixmaps/UNKNOWN_14.xpm"
76 #include "pixmaps/THINKING_14.xpm"
77 #include "pixmaps/PONDER_14.xpm"
78 #include "pixmaps/ANALYZING_14.xpm"
79
80 #ifdef SNAP\r
81 #include "wsnap.h"\r
82 #endif
83
84 #define _LL_ 100
85
86 // imports from xboard.c
87 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
88 extern Display *xDisplay;
89 extern Window xBoardWindow;
90 extern int squareSize;
91 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
92 extern char *layoutName;
93
94 // temporary kludge to avoid compile errors untill all Windows code has been replaced
95 #define HICON int *
96 #define HWND  int *
97 \r
98 // [HGM] define numbers to indicate icons, for referring to them in platform-independent way\r
99 #define nColorBlack   1\r
100 #define nColorWhite   2\r
101 #define nColorUnknown 3\r
102 #define nClear        4\r
103 #define nPondering    5\r
104 #define nThinking     6\r
105 #define nAnalyzing    7\r
106 \r
107 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle\r
108 \r
109 // [HGM] same for output fields (note that there are two of each type, one per color)\r
110 #define nColorIcon 1\r
111 #define nStateIcon 2\r
112 #define nLabel     3\r
113 #define nStateData 4\r
114 #define nLabelNPS  5\r
115 #define nMemo      6\r
116 \r
117 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle\r
118 \r
119 void EngineOutputPopDown();\r
120 void engineOutputPopUp(char *title, char *text);\r
121 int  EngineOutputIsUp();\r
122 static void SetEngineColorIcon( int which );\r
123 \r
124 #define SHOW_PONDERING\r
125 \r
126 /* Imports from backend.c */\r
127 char * SavePart(char *str);
128 extern int opponentKibitzes;\r
129 \r
130 /* Imports from winboard.c */\r
131 //extern HWND engineOutputDialog;\r
132 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];\r
133 \r
134 //extern WindowPlacement wpEngineOutput;\r
135
136 Position engineOutputX = -1, engineOutputY = -1;
137 Dimension engineOutputW, engineOutputH;
138 Widget engineOutputShell;
139 int engineOutputDialogUp;
140
141 /* Module variables */\r
142 #define H_MARGIN            2\r
143 #define V_MARGIN            2\r
144 #define LABEL_V_DISTANCE    1   /* Distance between label and memo */\r
145 #define SPLITTER_SIZE       4   /* Distance between first memo and second label */\r
146 \r
147 #define ICON_SIZE           14\r
148 \r
149 #define STATE_UNKNOWN   -1\r
150 #define STATE_THINKING   0\r
151 #define STATE_IDLE       1\r
152 #define STATE_PONDERING  2\r
153 #define STATE_ANALYZING  3\r
154 \r
155 static int  windowMode = 1;\r
156 \r
157 static int  needInit = TRUE;\r
158 \r
159 static int  lastDepth[2] = { -1, -1 };\r
160 static int  lastForwardMostMove[2] = { -1, -1 };\r
161 static int  engineState[2] = { -1, -1 };\r
162 \r
163 typedef struct {\r
164     char * name;\r
165     int which;\r
166     int depth;\r
167     unsigned long nodes;\r
168     int score;\r
169     int time;\r
170     char * pv;\r
171     char * hint;\r
172     int an_move_index;\r
173     int an_move_count;\r
174 } EngineOutputData;\r
175 \r
176 static int VerifyDisplayMode();\r
177 static void UpdateControls( EngineOutputData * ed );\r
178 static SetEngineState( int which, int state, char * state_data );\r
179
180 void ReadIcon(char *pixData[], int iconNr)
181 {
182     int r;
183
184         if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),\r
185                                        pixData,\r
186                                        &(icons[iconNr]),\r
187                                        NULL, NULL /*&attr*/)) != 0) {\r
188           fprintf(stderr, "Error %d loading icon image\n", r);\r
189           exit(1); \r
190         }       \r
191 }
192
193 static void InitializeEngineOutput()\r
194 { int i;
195
196         ReadIcon(WHITE_14,   nColorWhite);\r
197         ReadIcon(BLACK_14,   nColorBlack);\r
198         ReadIcon(UNKNOWN_14, nColorUnknown);\r
199
200         ReadIcon(CLEAR_14,   nClear);\r
201         ReadIcon(PONDER_14,  nPondering);\r
202         ReadIcon(THINK_14,   nThinking);\r
203         ReadIcon(ANALYZE_14, nAnalyzing);\r
204 //        icons[nClear]       = wIconPixmap;\r
205 //        icons[nPondering]   = bIconPixmap;\r//        icons[nThinking]    = wIconPixmap;\r
206 //        icons[nAnalyzing]   = bIconPixmap;\r}
207
208 #if 0
209 // Windows routines commented out
210 \r
211 // front end\r
212 static HICON LoadIconEx( int id )\r
213 {\r
214     return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );\r
215 }\r
216 \r
217 // [HGM] the platform-dependent way of indicating where output should go is now all\r
218 // concentrated here, where a table of platform-dependent handles are initialized.\r
219 // This cleanses most other routines of front-end stuff, so they can go into the back end.\r
220 static void InitializeEngineOutput()\r
221 {\r
222  //   if( needInit ) { // needInit was already tested before call\r
223         // [HGM] made this into a table, rather than separate global variables\r
224         icons[nColorBlack]   = LoadIconEx( IDI_BLACK_14 );\r
225         icons[nColorWhite]   = LoadIconEx( IDI_WHITE_14 );\r
226         icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );\r
227         icons[nClear]        = LoadIconEx( IDI_TRANS_14 );\r
228         icons[nPondering]    = LoadIconEx( IDI_PONDER_14 );\r
229         icons[nThinking]     = LoadIconEx( IDI_CLOCK_14 );\r
230         icons[nAnalyzing]    = LoadIconEx( IDI_ANALYZE2_14 );\r
231 \r
232         // [HGM] also make a table of handles to output controls\r
233         // Note that engineOutputDialog must be defined first!\r
234         outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );\r
235         outputField[0][nLabel]     = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );\r
236         outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );\r
237         outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );\r
238         outputField[0][nLabelNPS]  = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );\r
239         outputField[0][nMemo]      = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );\r
240 \r
241         outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );\r
242         outputField[1][nLabel]     = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );\r
243         outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );\r
244         outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );\r
245         outputField[1][nLabelNPS]  = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );\r
246         outputField[1][nMemo]      = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );\r
247 //        needInit = FALSE;\r
248 //    }\r
249 }\r
250 \r
251 // front end\r
252 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )\r
253 {\r
254     HWND hControl = GetDlgItem( hDlg, id );\r
255 \r
256     SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );\r
257 }\r
258 \r
259 #define HIDDEN_X    20000\r
260 #define HIDDEN_Y    20000\r
261 \r
262 // front end\r
263 static void HideControl( HWND hDlg, int id )\r
264 {\r
265     HWND hControl = GetDlgItem( hDlg, id );\r
266     RECT rc;\r
267 \r
268     GetWindowRect( hControl, &rc );\r
269 \r
270     /* \r
271         Avoid hiding an already hidden control, because that causes many\r
272         unnecessary WM_ERASEBKGND messages!\r
273     */\r
274     if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {\r
275         SetControlPos( hDlg, id, 20000, 20000, 100, 100 );\r
276     }\r
277 }\r
278 \r
279 // front end, although we might make GetWindowRect front end instead\r
280 static int GetControlWidth( HWND hDlg, int id )\r
281 {\r
282     RECT rc;\r
283 \r
284     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
285 \r
286     return rc.right - rc.left;\r
287 }\r
288 \r
289 // front end?\r
290 static int GetControlHeight( HWND hDlg, int id )\r
291 {\r
292     RECT rc;\r
293 \r
294     GetWindowRect( GetDlgItem( hDlg, id ), &rc );\r
295 \r
296     return rc.bottom - rc.top;\r
297 }\r
298 \r
299 static int GetHeaderHeight()\r
300 {\r
301     int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );\r
302 \r
303     if( result < ICON_SIZE ) result = ICON_SIZE;\r
304 \r
305     return result;\r
306 }\r
307 \r
308 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,\r
309 // a platform-independent wrapper for it should be supplied.\r
310 static void PositionControlSet( HWND hDlg, int x, int y, int clientWidth, int memoHeight, int idColor, int idEngineLabel, int idNPS, int idMemo, int idStateIcon, int idStateData )\r
311 {\r
312     int label_x = x + ICON_SIZE + H_MARGIN;\r
313     int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );\r
314     int label_y = y + ICON_SIZE - label_h;\r
315     int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );\r
316     int nps_x = clientWidth - H_MARGIN - nps_w;\r
317     int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );\r
318     int state_data_x = nps_x - H_MARGIN - state_data_w;\r
319     int state_icon_x = state_data_x - ICON_SIZE - 2;\r
320     int max_w = clientWidth - 2*H_MARGIN;\r
321     int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;\r
322 \r
323     SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );\r
324     SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );\r
325     SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );\r
326     SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );\r
327     SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );\r
328     SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );\r
329 }\r
330 \r
331 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine\r
332 static void ResizeWindowControls( HWND hDlg, int mode )\r
333 {\r
334     RECT rc;\r
335     int headerHeight = GetHeaderHeight();\r
336     int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );\r
337     int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;\r
338     int labelDeltaY = ICON_SIZE - labelHeight;\r
339     int clientWidth;\r
340     int clientHeight;\r
341     int maxControlWidth;\r
342     int npsWidth;\r
343 \r
344     /* Initialize variables */\r
345     GetClientRect( hDlg, &rc );\r
346 \r
347     clientWidth = rc.right - rc.left;\r
348     clientHeight = rc.bottom - rc.top;\r
349 \r
350     maxControlWidth = clientWidth - 2*H_MARGIN;\r
351 \r
352     npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );\r
353 \r
354     /* Resize controls */\r
355     if( mode == 0 ) {\r
356         /* One engine */\r
357         PositionControlSet( hDlg, H_MARGIN, V_MARGIN, \r
358             clientWidth, \r
359             clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,\r
360             IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );\r
361 \r
362         /* Hide controls for the second engine */\r
363         HideControl( hDlg, IDC_Color2 );\r
364         HideControl( hDlg, IDC_EngineLabel2 );\r
365         HideControl( hDlg, IDC_StateIcon2 );\r
366         HideControl( hDlg, IDC_StateData2 );\r
367         HideControl( hDlg, IDC_Engine2_NPS );\r
368         HideControl( hDlg, IDC_EngineMemo2 );\r
369         SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );\r
370         /* TODO: we should also hide/disable them!!! what about tab stops?!?! */\r
371     }\r
372     else {\r
373         /* Two engines */\r
374         int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;\r
375         int header1_y = V_MARGIN;\r
376         int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;\r
377 \r
378         PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,\r
379             IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );\r
380 \r
381         PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,\r
382             IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );\r
383     }\r
384 \r
385     InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );\r
386     InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );\r
387 }\r
388 \r
389 // front end. Actual printing of PV lines into the output field\r
390 static void InsertIntoMemo( int which, char * text )\r
391 {\r
392     SendMessage( outputField[which][nMemo], EM_SETSEL, 0, 0 );\r
393 \r
394     SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );\r
395 }\r
396 \r
397 // front end. Associates an icon with an output field ("control" in Windows jargon).\r
398 // [HGM] let it find out the output field from the 'which' number by itself\r
399 static void SetIcon( int which, int field, int nIcon )\r
400 {\r
401 \r
402     if( nIcon != 0 ) {\r
403         SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );\r
404     }\r
405 }\r
406 \r
407 // front end wrapper for SetWindowText, taking control number in stead of handle\r
408 void DoSetWindowText(int which, int field, char *s_label)\r
409 {\r
410     SetWindowText( outputField[which][field], s_label );\r
411 }\r
412 #endif
413
414 void DoSetWindowText(int which, int field, char *s_label)\r
415\r
416         Arg arg;\r
417 \r
418         XtSetArg(arg, XtNlabel, (XtArgVal) s_label);\r
419         XtSetValues(outputField[which][field], &arg, 1);\r
420 }\r
421
422 static void InsertIntoMemo( int which, char * text )\r
423 {
424         Arg arg; XawTextBlock t; Widget edit;
425
426         t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;\r
427         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");\r
428         XawTextReplace(edit, 0, 0, &t);
429 //      XtSetArg(arg, XtNstring, (XtArgVal) text);\r
430 //      XtSetValues(outputField[which][nMemo], &arg, 1);\r
431 }\r
432
433 static void SetIcon( int which, int field, int nIcon )
434 {
435     Arg arg;
436 \r
437     if( nIcon != 0 ) {\r
438         XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);\r
439         XtSetValues(outputField[which][field], &arg, 1);\r
440     }\r
441 }
442
443 void DoClearMemo(int which)\r\r    Arg args[16];\r
444     int j;\r
445     Widget edit;\r
446
447         edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");\r
448         XtCallActionProc(edit, "select-all", NULL, NULL, 0);\r
449         XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);\r
450 }
451 \r
452 // The following routines are mutated clones of the commentPopUp routines\r
453 \r
454 void PositionControlSet(which, form, bw_width)\r
455      int which;\r
456      Widget form;\r
457      Dimension bw_width;\r{\r
458     Arg args[16];\r
459     Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;\r
460     int j, mutable=1;\r
461     j = 0;\r
462     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
463     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;\r
464     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
465     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
466     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;\r    XtSetArg(args[j], XtNright,     XtChainLeft); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
467     XtSetArg(args[j], XtNwidth,     (XtArgVal) 17); j++;\r
468     outputField[which][nColorIcon] = ColorWidget =
469       XtCreateManagedWidget("Color", labelWidgetClass,\r
470                      form, args, j);\r
471
472     j = 0;\r
473     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
474     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
475     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;\r
476     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
477     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
478     XtSetArg(args[j], XtNleft,      XtChainLeft); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
479     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 57); j++;\r
480     outputField[which][nLabel] = NameWidget =
481       XtCreateManagedWidget("Engine", labelWidgetClass,\r
482                      form, args, j);\r
483
484     j = 0;\r
485     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
486     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;\r
487     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;\r
488     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
489     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
490     XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
491     XtSetArg(args[j], XtNwidth,     (XtArgVal) 20); j++;\r
492     outputField[which][nStateIcon] = ModeWidget =
493       XtCreateManagedWidget("Mode", labelWidgetClass,\r
494                      form, args, j);\r
495
496     j = 0;\r
497     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
498     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyLeft); j++;
499     XtSetArg(args[j], XtNlabel,     (XtArgVal) ""); j++;\r
500     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;\r
501     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
502     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
503     XtSetArg(args[j], XtNright,     XtChainRight); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
504     XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width/2 - 102); j++;\r
505     outputField[which][nStateData] = MoveWidget =
506       XtCreateManagedWidget("Move", labelWidgetClass,\r
507                      form, args, j);\r
508
509     j = 0;\r
510     XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
511     XtSetArg(args[j], XtNjustify,   (XtArgVal) XtJustifyRight); j++;\r
512     XtSetArg(args[j], XtNlabel,     (XtArgVal) "NPS"); j++;\r
513     XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;\r
514     XtSetArg(args[j], XtNtop,       XtChainTop); j++;\r
515     XtSetArg(args[j], XtNbottom,    XtChainTop); j++;\r
516     XtSetArg(args[j], XtNleft,      XtChainRight); j++;\r    XtSetArg(args[j], XtNright,     XtChainRight); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) 16); j++;\r
517     XtSetArg(args[j], XtNwidth,     (XtArgVal) 100); j++;\r
518     outputField[which][nLabelNPS] = NodesWidget =
519       XtCreateManagedWidget("Nodes", labelWidgetClass,\r
520                      form, args, j);\r
521
522     // create "text" within "form"
523     j = 0;\r
524     if (mutable) {\r
525         XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;\r
526         XtSetArg(args[j], XtNuseStringInPlace, False);  j++;\r
527     }\r
528     XtSetArg(args[j], XtNstring, "");  j++;\r
529     XtSetArg(args[j], XtNdisplayCaret, False);  j++;\r
530     XtSetArg(args[j], XtNtop, XtChainTop);  j++;\r
531     XtSetArg(args[j], XtNbottom, XtChainBottom);  j++;\r
532     XtSetArg(args[j], XtNleft, XtChainLeft);  j++;\r
533     XtSetArg(args[j], XtNright, XtChainRight);  j++;\r
534     XtSetArg(args[j], XtNresizable, True);  j++;\r
535     XtSetArg(args[j], XtNwidth, bw_width);  j++; /*force wider than buttons*/\r
536 #if 0\r
537     XtSetArg(args[j], XtNscrollVertical, XawtextScrollWhenNeeded);  j++;\r
538 #else\r
539     /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */\r
540     XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++;\r
541     XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded);  j++;\r#endif\r
542 //    XtSetArg(args[j], XtNautoFill, True);  j++;\r
543 //    XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;\r
544     outputField[which][nMemo] = edit =\r
545       XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);\r
546 \r
547     j = 0;\r
548     XtSetArg(args[j], XtNfromVert, ColorWidget); j++;\r
549 //    XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;\r
550     XtSetValues(edit, args, j);\r
551 }\r
552 \r
553 Widget EngineOutputCreate(name, text)\r
554      char *name, *text;\r
555 {\r
556     Arg args[16];\r
557     Widget shell, layout, form, form2, edit;
558     Dimension bw_width, bw_height;\r
559     int j;\r
560 \r
561     // get board width
562     j = 0;\r
563     XtSetArg(args[j], XtNwidth,  &bw_width);  j++;\r    XtSetArg(args[j], XtNheight, &bw_height);  j++;\r    XtGetValues(boardWidget, args, j);\r
564 \r
565     // define form within layout within shell.
566     j = 0;\r
567     XtSetArg(args[j], XtNresizable, True);  j++;\r
568     shell =\r
569       XtCreatePopupShell(name, transientShellWidgetClass,\r
570                          shellWidget, args, j);\r
571     layout =\r
572       XtCreateManagedWidget(layoutName, formWidgetClass, shell,\r
573                             layoutArgs, XtNumber(layoutArgs));\r
574     // divide window vertically into two equal parts, by creating two forms
575     form =\r
576       XtCreateManagedWidget("form", formWidgetClass, layout,\r
577                             formArgs, XtNumber(formArgs));\r
578     form2 =\r
579       XtCreateManagedWidget("form2", formWidgetClass, layout,\r
580                             formArgs, XtNumber(formArgs));\r
581     j = 0;\r    XtSetArg(args[j], XtNfromVert,  (XtArgVal) form); j++;\r    XtSetValues(form2, args, j);\r
582     // make sure width is known in advance, for better placement of child widgets
583     j = 0;\r    XtSetArg(args[j], XtNwidth,     (XtArgVal) bw_width-16); j++;\r    XtSetArg(args[j], XtNheight,    (XtArgVal) bw_height/2); j++;\r    XtSetValues(shell, args, j);\r
584
585     // fill up both forms with control elements
586     PositionControlSet(0, form,  bw_width);
587     PositionControlSet(1, form2, bw_width);
588 \r
589     XtRealizeWidget(shell);\r
590
591     if (engineOutputX == -1) {\r
592         int xx, yy;\r
593         Window junk;\r
594         Dimension pw_height;\r
595         Dimension ew_height;\r
596 #if 0\r
597         j = 0;\r
598         XtSetArg(args[j], XtNheight, &ew_height);  j++;\r
599         XtGetValues(edit, args, j);\r
600 \r
601         j = 0;\r
602         XtSetArg(args[j], XtNheight, &pw_height);  j++;\r
603         XtGetValues(shell, args, j);\r
604         engineOutputH = pw_height + (lines - 1) * ew_height;\r
605         engineOutputW = bw_width - 16;
606 #else
607         engineOutputH = bw_height/2;\r   engineOutputW = bw_width-16;\r#endif
608 \r
609         XSync(xDisplay, False);\r
610 #ifdef NOTDEF\r
611         /* This code seems to tickle an X bug if it is executed too soon\r
612            after xboard starts up.  The coordinates get transformed as if\r
613            the main window was positioned at (0, 0).\r
614            */\r
615         XtTranslateCoords(shellWidget,\r
616                           (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,\r
617                           &engineOutputX, &engineOutputY);\r
618 #else  /*!NOTDEF*/\r
619         XTranslateCoordinates(xDisplay, XtWindow(shellWidget),\r
620                               RootWindowOfScreen(XtScreen(shellWidget)),\r
621                               (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,\r
622                               &xx, &yy, &junk);\r
623         engineOutputX = xx;\r
624         engineOutputY = yy;\r
625 #endif /*!NOTDEF*/\r
626         if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/\r
627     }\r
628     j = 0;\r
629     XtSetArg(args[j], XtNheight, engineOutputH);  j++;\r    XtSetArg(args[j], XtNwidth, engineOutputW);  j++;\r
630     XtSetArg(args[j], XtNx, engineOutputX);  j++;\r
631     XtSetArg(args[j], XtNy, engineOutputY);  j++;\r
632     XtSetValues(shell, args, j);\r
633 //    XtSetKeyboardFocus(shell, edit);\r
634 \r
635     return shell;\r
636 }\r
637 \r
638 void ResizeWindowControls(shell, mode)
639         Widget shell;
640         int mode;
641 {
642     Widget form1, form2;
643     Arg args[16];
644     int j;
645     Dimension ew_height, tmp;
646
647     form1 = XtNameToWidget(shell, "*form");\r
648     form2 = XtNameToWidget(shell, "*form2");
649
650     j = 0;
651     XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;\r    XtGetValues(form1, args, j);
652     j = 0;
653     XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;\r    XtGetValues(form2, args, j);
654     ew_height += tmp; // total height
655 \r
656     if(mode==0) {\r
657         j = 0;
658         XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;\r
659         XtSetValues(form2, args, j);
660         j = 0;
661         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;\r
662         XtSetValues(form1, args, j);
663     } else {
664         j = 0;
665         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;\r
666         XtSetValues(form1, args, j);
667         j = 0;
668         XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;\r
669         XtSetValues(form2, args, j);
670     }\r
671 }
672
673 #if 0\r
674 void EngineOutputCallback(w, client_data, call_data)\r
675      Widget w;\r
676      XtPointer client_data, call_data;\r
677 {\r
678     String name;\r
679     Arg args[16];\r
680     int j;\r
681 \r
682     j = 0;\r
683     XtSetArg(args[j], XtNlabel, &name);  j++;\r
684     XtGetValues(w, args, j);\r
685 \r
686     if (strcmp(name, "close") == 0) {\r
687         EngineOutputPopDown();\r
688     } else if (strcmp(name, "edit") == 0) {\r
689         EngineOutputPopDown();\r
690         EditCommentEvent();\r
691     }\r
692 }\r
693 #endif
694 \r
695 #if 0\r
696 // This seems pure front end\r
697 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
698 {\r
699     static SnapData sd;\r
700 \r
701     switch (message) {\r
702     case WM_INITDIALOG:\r
703         if( engineOutputDialog == NULL ) {\r
704             engineOutputDialog = hDlg;\r
705 \r
706             RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */\r
707 \r
708             ResizeWindowControls( hDlg, windowMode );\r
709 \r
710             SetEngineState( 0, STATE_IDLE, "" );\r
711             SetEngineState( 1, STATE_IDLE, "" );\r
712         }\r
713 \r
714         return FALSE;\r
715 \r
716     case WM_COMMAND:\r
717         switch (LOWORD(wParam)) {\r
718         case IDOK:\r
719           EndDialog(hDlg, TRUE);\r
720           return TRUE;\r
721 \r
722         case IDCANCEL:\r
723           EndDialog(hDlg, FALSE);\r
724           return TRUE;\r
725 \r
726         default:\r
727           break;\r
728         }\r
729 \r
730         break;\r
731 \r
732     case WM_GETMINMAXINFO:\r
733         {\r
734             MINMAXINFO * mmi = (MINMAXINFO *) lParam;\r
735         \r
736             mmi->ptMinTrackSize.x = 100;\r
737             mmi->ptMinTrackSize.y = 160;\r
738         }\r
739         break;\r
740 \r
741     case WM_CLOSE:\r
742         EngineOutputPopDown();\r
743         break;\r
744 \r
745     case WM_SIZE:\r
746         ResizeWindowControls( hDlg, windowMode );\r
747         break;\r
748 \r
749     case WM_ENTERSIZEMOVE:\r
750         return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
751 \r
752     case WM_SIZING:\r
753         return OnSizing( &sd, hDlg, wParam, lParam );\r
754 \r
755     case WM_MOVING:\r
756         return OnMoving( &sd, hDlg, wParam, lParam );\r
757 \r
758     case WM_EXITSIZEMOVE:\r
759         return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
760     }\r
761 \r
762     return FALSE;\r
763 }\r
764 #endif
765 \r
766 void EngineOutputPopUp(title, text)\r
767      char *title, *text;\r
768 {\r
769     Arg args[16];\r
770     int j;\r
771     Widget edit;\r
772 \r
773     if (engineOutputShell == NULL) {\r
774         engineOutputShell =\r
775           EngineOutputCreate(title, text);\r
776         XtRealizeWidget(engineOutputShell);\r
777         CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");\r
778         if( needInit ) {\r
779             InitializeEngineOutput();\r
780             needInit = FALSE;\r  }\r
781         SetEngineColorIcon( 0 );\r
782         SetEngineColorIcon( 1 );\r
783         SetEngineState( 0, STATE_IDLE, "" );\r
784         SetEngineState( 1, STATE_IDLE, "" );\r
785     } else {
786         edit = XtNameToWidget(engineOutputShell, "*form.text");\r
787         j = 0;\r
788         XtSetArg(args[j], XtNstring, text); j++;\r
789         XtSetValues(edit, args, j);\r
790         j = 0;\r
791         XtSetArg(args[j], XtNiconName, (XtArgVal) title);   j++;\r
792         XtSetArg(args[j], XtNtitle, (XtArgVal) title);      j++;\r
793         XtSetValues(engineOutputShell, args, j);\r
794     }\r
795 \r
796     XtPopup(engineOutputShell, XtGrabNone);\r
797     XSync(xDisplay, False);\r
798 \r
799     j=0;
800     XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
801     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
802                 args, j);
803
804     engineOutputDialogUp = True;\r
805     ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
806 }\r
807
808 #if 0\r
809 // front end\r
810 void EngineOutputPopUp()\r
811 {\r
812   FARPROC lpProc;\r
813   \r
814   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);\r
815 \r
816   if( engineOutputDialog ) {\r
817     SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );\r
818 \r
819     if( ! engineOutputDialogUp ) {\r
820         ShowWindow(engineOutputDialog, SW_SHOW);\r
821     }\r
822   }\r
823   else {\r
824     lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );\r
825 \r
826     /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */\r
827     CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );\r
828 \r
829     FreeProcInstance(lpProc);\r
830   }\r
831 \r
832   // [HGM] displaced to after creation of dialog, to allow initialization of output fields\r
833   if( needInit ) {\r
834       InitializeEngineOutput();\r
835       needInit = FALSE;\r
836   }\r
837 \r
838   engineOutputDialogUp = TRUE;\r
839 }\r
840 #endif
841 \r
842 void EngineOutputPopDown()\r
843 {\r
844     Arg args[16];\r
845     int j;\r
846 \r
847     if (!engineOutputDialogUp) return;\r
848     DoClearMemo(1);
849     j = 0;\r
850     XtSetArg(args[j], XtNx, &engineOutputX); j++;\r
851     XtSetArg(args[j], XtNy, &engineOutputY); j++;\r
852     XtSetArg(args[j], XtNwidth, &engineOutputW); j++;\r
853     XtSetArg(args[j], XtNheight, &engineOutputH); j++;\r
854     XtGetValues(engineOutputShell, args, j);\r
855     XtPopdown(engineOutputShell);\r
856     XSync(xDisplay, False);
857     j=0;
858     XtSetArg(args[j], XtNleftBitmap, None); j++;
859     XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
860                 args, j);
861 \r
862     engineOutputDialogUp = False;\r
863     ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
864 }\r
865 \r
866 #if 0
867 // front end\r
868 void EngineOutputPopDown()\r
869 {\r
870   CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);\r
871 \r
872   if( engineOutputDialog ) {\r
873       ShowWindow(engineOutputDialog, SW_HIDE);\r
874   }\r
875 \r
876   engineOutputDialogUp = FALSE;\r
877 }\r
878 \r
879 // front end. [HGM] Takes handle of output control from table, so only number is passed\r
880 void DoClearMemo(int which)\r
881 {\r
882         SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );\r
883 }\r
884 #endif
885
886 //------------------------ pure back-end routines -------------------------------\r
887 \r
888 \r
889 // back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments\r
890 static SetEngineState( int which, int state, char * state_data )\r
891 {\r
892     int x_which = 1 - which;\r
893 \r
894     if( engineState[ which ] != state ) {\r
895         engineState[ which ] = state;\r
896 \r
897         switch( state ) {\r
898         case STATE_THINKING:\r
899             SetIcon( which, nStateIcon, nThinking );\r
900             if( engineState[ x_which ] == STATE_THINKING ) {\r
901                 SetEngineState( x_which, STATE_IDLE, "" );\r
902             }\r
903             break;\r
904         case STATE_PONDERING:\r
905             SetIcon( which, nStateIcon, nPondering );\r
906             break;\r
907         case STATE_ANALYZING:\r
908             SetIcon( which, nStateIcon, nAnalyzing );\r
909             break;\r
910         default:\r
911             SetIcon( which, nStateIcon, nClear );\r
912             break;\r
913         }\r
914     }\r
915 \r
916     if( state_data != 0 ) {\r
917         DoSetWindowText( which, nStateData, state_data );\r
918     }\r
919 }\r
920 \r
921 // back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles.\r
922 void EngineOutputUpdate( FrontEndProgramStats * stats )\r
923 {\r
924     EngineOutputData ed;\r
925     int clearMemo = FALSE;\r
926     int which;\r
927     int depth;\r
928 \r
929     if( stats == 0 ) {\r
930         SetEngineState( 0, STATE_IDLE, "" );\r
931         SetEngineState( 1, STATE_IDLE, "" );\r
932         return;\r
933     }\r
934 \r
935     if(gameMode == IcsObserving) return; // [HGM] kibitz: shut up engine if we are observing an ICS game
936
937     which = stats->which;\r
938     depth = stats->depth;\r
939 \r
940     if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) {\r
941         return;\r
942     }\r
943 \r
944     if( engineOutputShell == NULL ) {\r
945         return;\r
946     }\r
947 \r
948     VerifyDisplayMode();\r
949 \r
950     ed.which = which;\r
951     ed.depth = depth;\r
952     ed.nodes = stats->nodes;\r
953     ed.score = stats->score;\r
954     ed.time = stats->time;\r
955     ed.pv = stats->pv;\r
956     ed.hint = stats->hint;\r
957     ed.an_move_index = stats->an_move_index;\r
958     ed.an_move_count = stats->an_move_count;\r
959 \r
960     /* Get target control. [HGM] this is moved to front end, which get them from a table */\r
961     if( which == 0 ) {\r
962         ed.name = first.tidy;\r
963     }\r
964     else {\r
965         ed.name = second.tidy;\r
966     }\r
967 \r
968     /* Clear memo if needed */\r
969     if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) {\r
970         clearMemo = TRUE;\r
971     }\r
972 \r
973     if( lastForwardMostMove[which] != forwardMostMove ) {\r
974         clearMemo = TRUE;\r
975     }\r
976 \r
977     if( clearMemo ) DoClearMemo(which);\r
978 \r
979     /* Update */\r
980     lastDepth[which] = depth;\r
981     lastForwardMostMove[which] = forwardMostMove;\r
982 \r
983     if( ed.pv != 0 && ed.pv[0] == ' ' ) {\r
984         if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */\r
985             ed.pv = "";\r
986         }\r
987     }\r
988 \r
989     UpdateControls( &ed );\r
990 }\r
991 \r
992 #define ENGINE_COLOR_WHITE      'w'\r
993 #define ENGINE_COLOR_BLACK      'b'\r
994 #define ENGINE_COLOR_UNKNOWN    ' '\r
995 \r
996 // pure back end\r
997 char GetEngineColor( int which )\r
998 {\r
999     char result = ENGINE_COLOR_UNKNOWN;\r
1000 \r
1001     if( which == 0 || which == 1 ) {\r
1002         ChessProgramState * cps;\r
1003 \r
1004         switch (gameMode) {\r
1005         case MachinePlaysBlack:\r
1006         case IcsPlayingBlack:\r
1007             result = ENGINE_COLOR_BLACK;\r
1008             break;\r
1009         case MachinePlaysWhite:\r
1010         case IcsPlayingWhite:\r
1011             result = ENGINE_COLOR_WHITE;\r
1012             break;\r
1013         case AnalyzeMode:\r
1014         case AnalyzeFile:\r
1015             result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
1016             break;\r
1017         case TwoMachinesPlay:\r
1018             cps = (which == 0) ? &first : &second;\r
1019             result = cps->twoMachinesColor[0];\r
1020             result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
1021             break;\r
1022         }\r
1023     }\r
1024 \r
1025     return result;\r
1026 }\r
1027 \r
1028 // pure back end\r
1029 char GetActiveEngineColor()\r
1030 {\r
1031     char result = ENGINE_COLOR_UNKNOWN;\r
1032 \r
1033     if( gameMode == TwoMachinesPlay ) {\r
1034         result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK;\r
1035     }\r
1036 \r
1037     return result;\r
1038 }\r
1039 \r
1040 // pure back end\r
1041 static int IsEnginePondering( int which )\r
1042 {\r
1043     int result = FALSE;\r
1044 \r
1045     switch (gameMode) {\r
1046     case MachinePlaysBlack:\r
1047     case IcsPlayingBlack:\r
1048         if( WhiteOnMove(forwardMostMove) ) result = TRUE;\r
1049         break;\r
1050     case MachinePlaysWhite:\r
1051     case IcsPlayingWhite:\r
1052         if( ! WhiteOnMove(forwardMostMove) ) result = TRUE;\r
1053         break;\r
1054     case TwoMachinesPlay:\r
1055         if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) {\r
1056             if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE;\r
1057         }\r
1058         break;\r
1059     }\r
1060 \r
1061     return result;\r
1062 }\r
1063 \r
1064 // back end\r
1065 static void SetDisplayMode( int mode )\r
1066 {\r
1067     if( windowMode != mode ) {\r
1068         windowMode = mode;\r
1069 \r
1070         ResizeWindowControls( engineOutputShell, mode );\r
1071     }\r
1072 }\r
1073 \r
1074 // pure back end\r
1075 int VerifyDisplayMode()\r
1076 {\r
1077     int mode;\r
1078 \r
1079     /* Get proper mode for current game */\r
1080     switch( gameMode ) {\r
1081     case AnalyzeMode:\r
1082     case AnalyzeFile:\r
1083     case MachinePlaysWhite:\r
1084     case MachinePlaysBlack:\r
1085         mode = 0;\r
1086         break;\r
1087     case IcsPlayingWhite:\r
1088     case IcsPlayingBlack:\r
1089         mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz\r
1090         break;\r
1091     case TwoMachinesPlay:\r
1092         mode = 1;\r
1093         break;\r
1094     default:\r
1095         /* Do not change */\r
1096         return;\r
1097     }\r
1098 \r
1099     SetDisplayMode( mode );\r
1100 }\r
1101 \r
1102 // back end. Determine what icon to se in the color-icon field, and print it\r
1103 static void SetEngineColorIcon( int which )\r
1104 {\r
1105     char color = GetEngineColor(which);\r
1106     int nicon = 0;\r
1107 \r
1108     if( color == ENGINE_COLOR_BLACK )\r
1109         nicon = nColorBlack;\r
1110     else if( color == ENGINE_COLOR_WHITE )\r
1111         nicon = nColorWhite;\r
1112     else\r
1113         nicon = nColorUnknown;\r
1114 \r
1115     SetIcon( which, nColorIcon, nicon );\r
1116 }\r
1117 \r
1118 #define MAX_NAME_LENGTH 32\r
1119 \r
1120 // pure back end, now SetWindowText is called via wrapper DoSetWindowText\r
1121 static void UpdateControls( EngineOutputData * ed )\r
1122 {\r
1123     int isPondering = FALSE;\r
1124 \r
1125     char s_label[MAX_NAME_LENGTH + 32];\r
1126     \r
1127     char * name = ed->name;\r
1128 \r
1129     /* Label */\r
1130     if( name == 0 || *name == '\0' ) {\r
1131         name = "?";\r
1132     }\r
1133 \r
1134     strncpy( s_label, name, MAX_NAME_LENGTH );\r
1135     s_label[ MAX_NAME_LENGTH-1 ] = '\0';\r
1136 \r
1137 #ifdef SHOW_PONDERING\r
1138     if( IsEnginePondering( ed->which ) ) {\r
1139         char buf[8];\r
1140 \r
1141         buf[0] = '\0';\r
1142 \r
1143         if( ed->hint != 0 && *ed->hint != '\0' ) {\r
1144             strncpy( buf, ed->hint, sizeof(buf) );\r
1145             buf[sizeof(buf)-1] = '\0';\r
1146         }\r
1147         else if( ed->pv != 0 && *ed->pv != '\0' ) {\r
1148             char * sep = strchr( ed->pv, ' ' );\r
1149             int buflen = sizeof(buf);\r
1150 \r
1151             if( sep != NULL ) {\r
1152                 buflen = sep - ed->pv + 1;\r
1153                 if( buflen > sizeof(buf) ) buflen = sizeof(buf);\r
1154             }\r
1155 \r
1156             strncpy( buf, ed->pv, buflen );\r
1157             buf[ buflen-1 ] = '\0';\r
1158         }\r
1159 \r
1160         SetEngineState( ed->which, STATE_PONDERING, buf );\r
1161     }\r
1162     else if( gameMode == TwoMachinesPlay ) {\r
1163         SetEngineState( ed->which, STATE_THINKING, "" );\r
1164     }\r
1165     else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile ) {\r
1166         char buf[64];\r
1167         int time_secs = ed->time / 100;\r
1168         int time_mins = time_secs / 60;\r
1169 \r
1170         buf[0] = '\0';\r
1171 \r
1172         if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) {\r
1173             char mov[16];\r
1174 \r
1175             strncpy( mov, ed->hint, sizeof(mov) );\r
1176             mov[ sizeof(mov)-1 ] = '\0';\r
1177 \r
1178             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 );\r
1179         }\r
1180 \r
1181         SetEngineState( ed->which, STATE_ANALYZING, buf );\r
1182     }\r
1183     else {\r
1184         SetEngineState( ed->which, STATE_IDLE, "" );\r
1185     }\r
1186 #endif\r
1187 \r
1188     DoSetWindowText( ed->which, nLabel, s_label );\r
1189 \r
1190     s_label[0] = '\0';\r
1191 \r
1192     if( ed->time > 0 && ed->nodes > 0 ) {\r
1193         unsigned long nps_100 = ed->nodes / ed->time;\r
1194 \r
1195         if( nps_100 < 100000 ) {\r
1196             sprintf( s_label, "NPS: %lu", nps_100 * 100 );\r
1197         }\r
1198         else {\r
1199             sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 );\r
1200         }\r
1201     }\r
1202 \r
1203     DoSetWindowText( ed->which, nLabelNPS, s_label );\r
1204 \r
1205     /* Memo */\r
1206     if( ed->pv != 0 && *ed->pv != '\0' ) {\r
1207         char s_nodes[24];\r
1208         char s_score[16];\r
1209         char s_time[24];\r
1210         char buf[256];\r
1211         int buflen;\r
1212         int time_secs = ed->time / 100;\r
1213         int time_cent = ed->time % 100;\r
1214 \r
1215         /* Nodes */\r
1216         if( ed->nodes < 1000000 ) {\r
1217             sprintf( s_nodes, "%lu", ed->nodes );\r
1218         }\r
1219         else {\r
1220             sprintf( s_nodes, "%.1fM", ed->nodes / 1000000.0 );\r
1221         }\r
1222 \r
1223         /* Score */\r
1224         if( ed->score > 0 ) {\r
1225             sprintf( s_score, "+%.2f", ed->score / 100.0 );\r
1226         } else\r
1227             sprintf( s_score, "%.2f", ed->score / 100.0 );\r
1228 \r
1229         /* Time */\r
1230         sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent );\r
1231 \r
1232         /* Put all together... */\r
1233         sprintf( buf, "%3d  %s  %s\t%s\t", ed->depth, s_score, s_nodes, s_time );\r
1234 \r
1235         /* Add PV */\r
1236         buflen = strlen(buf);\r
1237 \r
1238         strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen );\r
1239 \r
1240         buf[ sizeof(buf) - 3 ] = '\0';\r
1241 \r
1242         strcat( buf + buflen, "\n" );\r
1243 \r
1244         /* Update memo */\r
1245         InsertIntoMemo( ed->which, buf );\r
1246     }\r
1247 \r
1248     /* Colors */\r
1249     SetEngineColorIcon( ed->which );\r
1250 }\r
1251 \r
1252 // back end\r
1253 int EngineOutputIsUp()\r
1254 {\r
1255     return engineOutputDialogUp;\r
1256 }\r
1257
1258 void
1259 EngineOutputProc(w, event, prms, nprms)
1260      Widget w;
1261      XEvent *event;
1262      String *prms;
1263      Cardinal *nprms;
1264 {
1265   if (engineOutputDialogUp) {
1266     EngineOutputPopDown();
1267   } else {
1268     EngineOutputPopUp("engine output","This feature is experimental");
1269   }
1270 //  ToNrEvent(currentMove);
1271 }
1272
1273 // [HGM] kibitz: write kibitz line; split window for it if necessary
1274 void OutputKibitz(int window, char *text)
1275 {
1276         if(!EngineOutputIsUp()) return;
1277         if(!opponentKibitzes) { // on first kibitz of game, clear memos
1278             DoClearMemo(1);
1279             if(gameMode == IcsObserving) DoClearMemo(0);
1280         }
1281         opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes.
1282         VerifyDisplayMode();
1283         if(gameMode == IcsObserving) {
1284             DoSetWindowText(0, nLabel, gameInfo.white);
1285             SetIcon( 0, nColorIcon,  nColorWhite);
1286             SetIcon( 0, nStateIcon,  nClear);
1287         }
1288         DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name
1289         SetIcon( 1, nColorIcon,  gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack);
1290         SetIcon( 1, nStateIcon,  nClear);
1291         InsertIntoMemo(window-1, text);
1292 }
1293