4 * Author: Alessandro Scotti (Dec 2005)
6 * Copyright 2005 Alessandro Scotti
8 * Enhancements Copyright 2009, 2010 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>
68 #include <X11/Xatom.h>
69 #include <X11/Xmu/Atoms.h>
75 #include "engineoutput.h"
79 # define _(s) gettext (s)
80 # define N_(s) gettext_noop (s)
88 // [HGM] pixmaps of some ICONS used in the engine-outut window
89 #include "pixmaps/WHITE_14.xpm"
90 #include "pixmaps/BLACK_14.xpm"
91 #include "pixmaps/CLEAR_14.xpm"
92 #include "pixmaps/UNKNOWN_14.xpm"
93 #include "pixmaps/THINKING_14.xpm"
94 #include "pixmaps/PONDER_14.xpm"
95 #include "pixmaps/ANALYZING_14.xpm"
103 // imports from xboard.c
104 extern Widget formWidget, shellWidget, boardWidget, menuBarWidget;
105 extern Display *xDisplay;
106 extern Window xBoardWindow;
107 extern int squareSize;
108 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
109 extern char *layoutName;
111 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
112 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
114 void EngineOutputPopDown();
115 void engineOutputPopUp();
116 int EngineOutputIsUp();
117 void SetEngineColorIcon( int which );
119 /* Imports from backend.c */
120 extern int opponentKibitzes;
122 /* Imports from xboard.c */
123 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
125 //extern WindowPlacement wpEngineOutput;
127 Position engineOutputX = -1, engineOutputY = -1;
128 Dimension engineOutputW, engineOutputH;
129 Widget engineOutputShell;
130 static int engineOutputDialogUp;
132 /* Module variables */
134 static int currentPV, highTextStart[2], highTextEnd[2];
149 //static void UpdateControls( EngineOutputData * ed );
151 void ReadIcon(char *pixData[], int iconNr)
155 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
158 NULL, NULL /*&attr*/)) != 0) {
159 fprintf(stderr, _("Error %d loading icon image\n"), r);
164 static void InitializeEngineOutput()
167 ReadIcon(WHITE_14, nColorWhite);
168 ReadIcon(BLACK_14, nColorBlack);
169 ReadIcon(UNKNOWN_14, nColorUnknown);
171 ReadIcon(CLEAR_14, nClear);
172 ReadIcon(PONDER_14, nPondering);
173 ReadIcon(THINK_14, nThinking);
174 ReadIcon(ANALYZE_14, nAnalyzing);
177 void DoSetWindowText(int which, int field, char *s_label)
181 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
182 XtSetValues(outputField[which][field], &arg, 1);
185 void InsertIntoMemo( int which, char * text, int where )
187 Arg arg; XawTextBlock t; Widget edit;
189 /* the backend adds \r\n, which is needed for winboard,
190 * for xboard we delete them again over here */
191 if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
193 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
194 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
195 XawTextReplace(edit, where, where, &t);
196 if(where < highTextStart[which]) { // [HGM] multiPVdisplay: move highlighting
197 int len = strlen(text);
198 highTextStart[which] += len; highTextEnd[which] += len;
199 XawTextSetSelection( outputField[which][nMemo], highTextStart[which], highTextEnd[which] );
203 void SetIcon( int which, int field, int nIcon )
208 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
209 XtSetValues(outputField[which][field], &arg, 1);
213 void DoClearMemo(int which)
219 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
220 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
221 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
224 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
226 extern char *selected_fen_position;
228 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
229 Atom *type_return, XtPointer *value_return,
230 unsigned long *length_return, int *format_return); // from xboard.c
231 void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
233 char memoTranslations[] =
234 ":Ctrl<Key>c: CopyMemoProc() \n \
235 <Btn3Motion>: HandlePV() \n \
236 <Btn3Down>: select-start() SelectPV() \n \
237 <Btn3Up>: extend-end() StopPV() \n";
240 SelectPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
241 { // [HGM] pv: translate click to PV line, and load it for display
243 int start, end, memo, j;
244 XawTextPosition index, dummy;
248 x = event->xmotion.x; y = event->xmotion.y;
249 currentPV = (w == outputField[1][nMemo]);
250 XawTextGetSelectionPos(w, &index, &dummy);
251 XtSetArg(arg, XtNstring, &val);
252 XtGetValues(w, &arg, 1);
253 if(LoadMultiPV(x, y, val, index, &start, &end)) {
254 XawTextSetSelection( outputField[currentPV][nMemo], start, end );
255 highTextStart[currentPV] = start; highTextEnd[currentPV] = end;
260 StopPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
261 { // [HGM] pv: on right-button release, stop displaying PV
262 XawTextUnsetSelection( w );
263 highTextStart[currentPV] = highTextEnd[currentPV] = 0;
268 MemoCB(Widget w, XtPointer client_data, Atom *selection,
269 Atom *type, XtPointer value, unsigned long *len, int *format)
271 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
272 selected_fen_position = value;
273 selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
274 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
276 SendPositionSelection,
277 NULL/* lose_ownership_proc */ ,
278 NULL/* transfer_done_proc */);
281 void CopyMemoProc(w, event, prms, nprms)
287 if(appData.pasteSelection) return;
288 if (selected_fen_position) free(selected_fen_position);
289 XtGetSelectionValue(menuBarWidget,
290 XA_PRIMARY, XA_STRING,
291 /* (XtSelectionCallbackProc) */ MemoCB,
292 NULL, /* client_data passed to PastePositionCB */
294 /* better to use the time field from the event that triggered the
295 * call to this function, but that isn't trivial to get
301 // The following routines are mutated clones of the commentPopUp routines
303 void PositionControlSet(which, shell, form, bw_width)
309 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
312 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
313 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
314 XtSetArg(args[j], XtNtop, XtChainTop); j++;
315 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
316 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
317 XtSetArg(args[j], XtNright, XtChainLeft); j++;
318 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
319 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
320 outputField[which][nColorIcon] = ColorWidget =
321 XtCreateManagedWidget("Color", labelWidgetClass,
325 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
326 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
327 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
328 XtSetArg(args[j], XtNtop, XtChainTop); j++;
329 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
330 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
331 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
332 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
333 outputField[which][nLabel] = NameWidget =
334 XtCreateManagedWidget("Engine", labelWidgetClass,
338 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
339 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
340 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
341 XtSetArg(args[j], XtNtop, XtChainTop); j++;
342 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
343 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
344 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
345 outputField[which][nStateIcon] = ModeWidget =
346 XtCreateManagedWidget("Mode", labelWidgetClass,
350 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
351 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
352 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
353 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
354 XtSetArg(args[j], XtNtop, XtChainTop); j++;
355 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
356 XtSetArg(args[j], XtNright, XtChainRight); j++;
357 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
358 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
359 outputField[which][nStateData] = MoveWidget =
360 XtCreateManagedWidget("Move", labelWidgetClass,
364 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
365 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
366 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
367 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
368 XtSetArg(args[j], XtNtop, XtChainTop); j++;
369 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
370 XtSetArg(args[j], XtNleft, XtChainRight); j++;
371 XtSetArg(args[j], XtNright, XtChainRight); j++;
372 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
373 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
374 outputField[which][nLabelNPS] = NodesWidget =
375 XtCreateManagedWidget("Nodes", labelWidgetClass,
378 // create "text" within "form"
381 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
382 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
384 XtSetArg(args[j], XtNstring, ""); j++;
385 XtSetArg(args[j], XtNdisplayCaret, False); j++;
386 XtSetArg(args[j], XtNtop, XtChainTop); j++;
387 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
388 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
389 XtSetArg(args[j], XtNright, XtChainRight); j++;
390 XtSetArg(args[j], XtNresizable, True); j++;
391 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
392 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
393 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
394 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
395 // XtSetArg(args[j], XtNautoFill, True); j++;
396 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
397 outputField[which][nMemo] = edit =
398 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
400 XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
401 XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
404 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
405 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
406 XtSetValues(edit, args, j);
409 Widget EngineOutputCreate(name, text)
413 Widget shell, layout, form, form2, edit;
414 Dimension bw_width, bw_height;
419 XtSetArg(args[j], XtNwidth, &bw_width); j++;
420 XtSetArg(args[j], XtNheight, &bw_height); j++;
421 XtGetValues(boardWidget, args, j);
423 // define form within layout within shell.
425 XtSetArg(args[j], XtNresizable, True); j++;
428 XtCreatePopupShell(name, topLevelShellWidgetClass,
430 XtCreatePopupShell(name, transientShellWidgetClass,
432 shellWidget, args, j);
434 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
435 layoutArgs, XtNumber(layoutArgs));
436 // divide window vertically into two equal parts, by creating two forms
438 XtCreateManagedWidget("form", formWidgetClass, layout,
439 formArgs, XtNumber(formArgs));
441 XtCreateManagedWidget("form2", formWidgetClass, layout,
442 formArgs, XtNumber(formArgs));
444 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
445 XtSetValues(form2, args, j);
446 // make sure width is known in advance, for better placement of child widgets
448 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
449 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
450 XtSetValues(shell, args, j);
452 // fill up both forms with control elements
453 PositionControlSet(0, shell, form, bw_width);
454 PositionControlSet(1, shell, form2, bw_width);
456 XtRealizeWidget(shell);
458 if(wpEngineOutput.width > 0) {
459 engineOutputW = wpEngineOutput.width;
460 engineOutputH = wpEngineOutput.height;
461 engineOutputX = wpEngineOutput.x;
462 engineOutputY = wpEngineOutput.y;
465 if (engineOutputX == -1) {
470 engineOutputH = bw_height/2;
471 engineOutputW = bw_width-16;
473 XSync(xDisplay, False);
475 /* This code seems to tickle an X bug if it is executed too soon
476 after xboard starts up. The coordinates get transformed as if
477 the main window was positioned at (0, 0).
479 XtTranslateCoords(shellWidget,
480 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
481 &engineOutputX, &engineOutputY);
483 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
484 RootWindowOfScreen(XtScreen(shellWidget)),
485 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
490 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
493 XtSetArg(args[j], XtNheight, engineOutputH); j++;
494 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
495 XtSetArg(args[j], XtNx, engineOutputX); j++;
496 XtSetArg(args[j], XtNy, engineOutputY); j++;
497 XtSetValues(shell, args, j);
498 // XtSetKeyboardFocus(shell, edit);
503 void ResizeWindowControls(mode)
509 Dimension ew_height, tmp;
510 Widget shell = engineOutputShell;
512 form1 = XtNameToWidget(shell, "*form");
513 form2 = XtNameToWidget(shell, "*form2");
516 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
517 XtGetValues(form1, args, j);
519 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
520 XtGetValues(form2, args, j);
521 ew_height += tmp; // total height
525 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
526 XtSetValues(form2, args, j);
528 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
529 XtSetValues(form1, args, j);
532 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
533 XtSetValues(form1, args, j);
535 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
536 XtSetValues(form2, args, j);
546 static int needInit = TRUE;
547 static char *title = _("Engine output"), *text = _("This feature is experimental");
549 if (engineOutputShell == NULL) {
551 EngineOutputCreate(title, text);
552 XtRealizeWidget(engineOutputShell);
553 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
555 InitializeEngineOutput();
558 SetEngineColorIcon( 0 );
559 SetEngineColorIcon( 1 );
560 SetEngineState( 0, STATE_IDLE, "" );
561 SetEngineState( 1, STATE_IDLE, "" );
563 edit = XtNameToWidget(engineOutputShell, "*form.text");
565 XtSetArg(args[j], XtNstring, text); j++;
566 XtSetValues(edit, args, j);
568 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
569 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
570 XtSetValues(engineOutputShell, args, j);
573 XtPopup(engineOutputShell, XtGrabNone);
574 XSync(xDisplay, False);
577 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
578 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
581 engineOutputDialogUp = True;
582 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
585 void EngineOutputPopDown()
590 if (!engineOutputDialogUp) return;
593 XtSetArg(args[j], XtNx, &engineOutputX); j++;
594 XtSetArg(args[j], XtNy, &engineOutputY); j++;
595 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
596 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
597 XtGetValues(engineOutputShell, args, j);
598 wpEngineOutput.x = engineOutputX - 4;
599 wpEngineOutput.y = engineOutputY - 23;
600 wpEngineOutput.width = engineOutputW;
601 wpEngineOutput.height = engineOutputH;
602 XtPopdown(engineOutputShell);
603 XSync(xDisplay, False);
605 XtSetArg(args[j], XtNleftBitmap, None); j++;
606 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
609 engineOutputDialogUp = False;
610 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
613 int EngineOutputIsUp()
615 return engineOutputDialogUp;
618 int EngineOutputDialogExists()
620 return engineOutputShell != NULL;
624 EngineOutputProc(w, event, prms, nprms)
630 if (engineOutputDialogUp) {
631 EngineOutputPopDown();