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()
166 ReadIcon(WHITE_14, nColorWhite);
167 ReadIcon(BLACK_14, nColorBlack);
168 ReadIcon(UNKNOWN_14, nColorUnknown);
170 ReadIcon(CLEAR_14, nClear);
171 ReadIcon(PONDER_14, nPondering);
172 ReadIcon(THINK_14, nThinking);
173 ReadIcon(ANALYZE_14, nAnalyzing);
176 void DoSetWindowText(int which, int field, char *s_label)
180 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
181 XtSetValues(outputField[which][field], &arg, 1);
184 void InsertIntoMemo( int which, char * text, int where )
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)
217 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
218 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
219 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
222 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
224 extern char *selected_fen_position;
226 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
227 Atom *type_return, XtPointer *value_return,
228 unsigned long *length_return, int *format_return); // from xboard.c
229 void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
231 char memoTranslations[] =
232 ":Ctrl<Key>c: CopyMemoProc() \n \
233 <Btn3Motion>: HandlePV() \n \
234 <Btn3Down>: select-start() SelectPV() \n \
235 <Btn3Up>: extend-end() StopPV() \n";
238 SelectPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
239 { // [HGM] pv: translate click to PV line, and load it for display
242 XawTextPosition index, dummy;
246 x = event->xmotion.x; y = event->xmotion.y;
247 currentPV = (w == outputField[1][nMemo]);
248 XawTextGetSelectionPos(w, &index, &dummy);
249 XtSetArg(arg, XtNstring, &val);
250 XtGetValues(w, &arg, 1);
251 if(LoadMultiPV(x, y, val, index, &start, &end)) {
252 XawTextSetSelection( outputField[currentPV][nMemo], start, end );
253 highTextStart[currentPV] = start; highTextEnd[currentPV] = end;
258 StopPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
259 { // [HGM] pv: on right-button release, stop displaying PV
260 XawTextUnsetSelection( w );
261 highTextStart[currentPV] = highTextEnd[currentPV] = 0;
266 MemoCB(Widget w, XtPointer client_data, Atom *selection,
267 Atom *type, XtPointer value, unsigned long *len, int *format)
269 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
270 selected_fen_position = value;
271 selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
272 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
274 SendPositionSelection,
275 NULL/* lose_ownership_proc */ ,
276 NULL/* transfer_done_proc */);
279 void CopyMemoProc(w, event, prms, nprms)
285 if(appData.pasteSelection) return;
286 if (selected_fen_position) free(selected_fen_position);
287 XtGetSelectionValue(menuBarWidget,
288 XA_PRIMARY, XA_STRING,
289 /* (XtSelectionCallbackProc) */ MemoCB,
290 NULL, /* client_data passed to PastePositionCB */
292 /* better to use the time field from the event that triggered the
293 * call to this function, but that isn't trivial to get
299 // The following routines are mutated clones of the commentPopUp routines
301 void PositionControlSet(which, shell, form, bw_width)
307 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
310 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
311 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
312 XtSetArg(args[j], XtNtop, XtChainTop); j++;
313 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
314 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
315 XtSetArg(args[j], XtNright, XtChainLeft); j++;
316 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
317 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
318 outputField[which][nColorIcon] = ColorWidget =
319 XtCreateManagedWidget("Color", labelWidgetClass,
323 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
324 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
325 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
326 XtSetArg(args[j], XtNtop, XtChainTop); j++;
327 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
328 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
329 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
330 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
331 outputField[which][nLabel] = NameWidget =
332 XtCreateManagedWidget("Engine", labelWidgetClass,
336 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
337 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
338 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
339 XtSetArg(args[j], XtNtop, XtChainTop); j++;
340 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
341 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
342 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
343 outputField[which][nStateIcon] = ModeWidget =
344 XtCreateManagedWidget("Mode", labelWidgetClass,
348 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
349 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
350 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
351 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
352 XtSetArg(args[j], XtNtop, XtChainTop); j++;
353 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
354 XtSetArg(args[j], XtNright, XtChainRight); j++;
355 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
356 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
357 outputField[which][nStateData] = MoveWidget =
358 XtCreateManagedWidget("Move", labelWidgetClass,
362 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
363 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
364 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
365 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
366 XtSetArg(args[j], XtNtop, XtChainTop); j++;
367 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
368 XtSetArg(args[j], XtNleft, XtChainRight); j++;
369 XtSetArg(args[j], XtNright, XtChainRight); j++;
370 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
371 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
372 outputField[which][nLabelNPS] = NodesWidget =
373 XtCreateManagedWidget("Nodes", labelWidgetClass,
376 // create "text" within "form"
379 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
380 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
382 XtSetArg(args[j], XtNstring, ""); j++;
383 XtSetArg(args[j], XtNdisplayCaret, False); j++;
384 XtSetArg(args[j], XtNtop, XtChainTop); j++;
385 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
386 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
387 XtSetArg(args[j], XtNright, XtChainRight); j++;
388 XtSetArg(args[j], XtNresizable, True); j++;
389 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
390 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
391 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
392 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
393 // XtSetArg(args[j], XtNautoFill, True); j++;
394 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
395 outputField[which][nMemo] = edit =
396 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
398 XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
399 XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
402 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
403 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
404 XtSetValues(edit, args, j);
407 Widget EngineOutputCreate(name, text)
411 Widget shell, layout, form, form2;
412 Dimension bw_width, bw_height;
417 XtSetArg(args[j], XtNwidth, &bw_width); j++;
418 XtSetArg(args[j], XtNheight, &bw_height); j++;
419 XtGetValues(boardWidget, args, j);
421 // define form within layout within shell.
423 XtSetArg(args[j], XtNresizable, True); j++;
426 XtCreatePopupShell(name, topLevelShellWidgetClass,
428 XtCreatePopupShell(name, transientShellWidgetClass,
430 shellWidget, args, j);
432 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
433 layoutArgs, XtNumber(layoutArgs));
434 // divide window vertically into two equal parts, by creating two forms
436 XtCreateManagedWidget("form", formWidgetClass, layout,
437 formArgs, XtNumber(formArgs));
439 XtCreateManagedWidget("form2", formWidgetClass, layout,
440 formArgs, XtNumber(formArgs));
442 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
443 XtSetValues(form2, args, j);
444 // make sure width is known in advance, for better placement of child widgets
446 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
447 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
448 XtSetValues(shell, args, j);
450 // fill up both forms with control elements
451 PositionControlSet(0, shell, form, bw_width);
452 PositionControlSet(1, shell, form2, bw_width);
454 XtRealizeWidget(shell);
456 if(wpEngineOutput.width > 0) {
457 engineOutputW = wpEngineOutput.width;
458 engineOutputH = wpEngineOutput.height;
459 engineOutputX = wpEngineOutput.x;
460 engineOutputY = wpEngineOutput.y;
463 if (engineOutputX == -1) {
467 engineOutputH = bw_height/2;
468 engineOutputW = bw_width-16;
470 XSync(xDisplay, False);
472 /* This code seems to tickle an X bug if it is executed too soon
473 after xboard starts up. The coordinates get transformed as if
474 the main window was positioned at (0, 0).
476 XtTranslateCoords(shellWidget,
477 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
478 &engineOutputX, &engineOutputY);
480 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
481 RootWindowOfScreen(XtScreen(shellWidget)),
482 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
487 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
490 XtSetArg(args[j], XtNheight, engineOutputH); j++;
491 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
492 XtSetArg(args[j], XtNx, engineOutputX); j++;
493 XtSetArg(args[j], XtNy, engineOutputY); j++;
494 XtSetValues(shell, args, j);
499 void ResizeWindowControls(mode)
505 Dimension ew_height, tmp;
506 Widget shell = engineOutputShell;
508 form1 = XtNameToWidget(shell, "*form");
509 form2 = XtNameToWidget(shell, "*form2");
512 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
513 XtGetValues(form1, args, j);
515 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
516 XtGetValues(form2, args, j);
517 ew_height += tmp; // total height
521 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
522 XtSetValues(form2, args, j);
524 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
525 XtSetValues(form1, args, j);
528 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
529 XtSetValues(form1, args, j);
531 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
532 XtSetValues(form2, args, j);
542 static int needInit = TRUE;
543 static char *title = _("Engine output"), *text = _("This feature is experimental");
545 if (engineOutputShell == NULL) {
547 EngineOutputCreate(title, text);
548 XtRealizeWidget(engineOutputShell);
549 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
551 InitializeEngineOutput();
554 SetEngineColorIcon( 0 );
555 SetEngineColorIcon( 1 );
556 SetEngineState( 0, STATE_IDLE, "" );
557 SetEngineState( 1, STATE_IDLE, "" );
559 edit = XtNameToWidget(engineOutputShell, "*form.text");
561 XtSetArg(args[j], XtNstring, text); j++;
562 XtSetValues(edit, args, j);
564 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
565 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
566 XtSetValues(engineOutputShell, args, j);
569 XtPopup(engineOutputShell, XtGrabNone);
570 XSync(xDisplay, False);
573 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
574 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
577 engineOutputDialogUp = True;
578 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
581 void EngineOutputPopDown()
586 if (!engineOutputDialogUp) return;
589 XtSetArg(args[j], XtNx, &engineOutputX); j++;
590 XtSetArg(args[j], XtNy, &engineOutputY); j++;
591 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
592 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
593 XtGetValues(engineOutputShell, args, j);
594 wpEngineOutput.x = engineOutputX - 4;
595 wpEngineOutput.y = engineOutputY - 23;
596 wpEngineOutput.width = engineOutputW;
597 wpEngineOutput.height = engineOutputH;
598 XtPopdown(engineOutputShell);
599 XSync(xDisplay, False);
601 XtSetArg(args[j], XtNleftBitmap, None); j++;
602 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
605 engineOutputDialogUp = False;
606 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
609 int EngineOutputIsUp()
611 return engineOutputDialogUp;
614 int EngineOutputDialogExists()
616 return engineOutputShell != NULL;
620 EngineOutputProc(w, event, prms, nprms)
626 if (engineOutputDialogUp) {
627 EngineOutputPopDown();