4 * Author: Alessandro Scotti (Dec 2005)
6 * Copyright 2005 Alessandro Scotti
8 * Enhancements Copyright 2009, 2010, 2011 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 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
104 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
106 void EngineOutputPopDown();
107 void engineOutputPopUp();
108 int EngineOutputIsUp();
109 void SetEngineColorIcon( int which );
111 //extern WindowPlacement wpEngineOutput;
113 Position engineOutputX = -1, engineOutputY = -1;
114 Dimension engineOutputW, engineOutputH;
115 Widget engineOutputShell = NULL;
116 static int engineOutputDialogUp;
118 /* Module variables */
120 static int currentPV, highTextStart[2], highTextEnd[2];
135 //static void UpdateControls( EngineOutputData * ed );
137 void ReadIcon(char *pixData[], int iconNr)
141 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
144 NULL, NULL /*&attr*/)) != 0) {
145 fprintf(stderr, _("Error %d loading icon image\n"), r);
150 static void InitializeEngineOutput()
152 ReadIcon(WHITE_14, nColorWhite);
153 ReadIcon(BLACK_14, nColorBlack);
154 ReadIcon(UNKNOWN_14, nColorUnknown);
156 ReadIcon(CLEAR_14, nClear);
157 ReadIcon(PONDER_14, nPondering);
158 ReadIcon(THINK_14, nThinking);
159 ReadIcon(ANALYZE_14, nAnalyzing);
162 void DoSetWindowText(int which, int field, char *s_label)
166 XtSetArg(args[0], XtNlabel, (XtArgVal) s_label);
167 XtSetValues(outputField[which][field], args, 1);
170 void SetEngineOutputTitle(char *title)
173 if(engineOutputShell==NULL) return;
174 XtSetArg(args[0], XtNtitle, (XtArgVal) title);
175 XtSetValues(engineOutputShell, args, 1);
178 void InsertIntoMemo( int which, char * text, int where )
183 /* the backend adds \r\n, which is needed for winboard,
184 * for xboard we delete them again over here */
185 if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
187 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
188 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
189 XawTextReplace(edit, where, where, &t);
190 if(where < highTextStart[which]) { // [HGM] multiPVdisplay: move highlighting
191 int len = strlen(text);
192 highTextStart[which] += len; highTextEnd[which] += len;
193 XawTextSetSelection( outputField[which][nMemo], highTextStart[which], highTextEnd[which] );
197 void SetIcon( int which, int field, int nIcon )
202 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
203 XtSetValues(outputField[which][field], &arg, 1);
207 void DoClearMemo(int which)
209 Widget edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
211 // XtCallActionProc(edit, "select-all", NULL, NULL, 0);
212 // XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
213 XtSetArg(arg, XtNstring, ""); // clear without disturbing selection!
214 XtSetValues(edit, &arg, 1);
217 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
219 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
220 Atom *type_return, XtPointer *value_return,
221 unsigned long *length_return, int *format_return); // from xboard.c
222 void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
224 char memoTranslations[] =
225 ":Ctrl<Key>c: CopyMemoProc() \n \
226 <Btn3Motion>: HandlePV() \n \
227 Shift<Btn3Down>: select-start() SelectPV(1) \n \
228 Any<Btn3Down>: select-start() SelectPV(0) \n \
229 <Btn3Up>: extend-end() StopPV() \n";
232 SelectPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
233 { // [HGM] pv: translate click to PV line, and load it for display
236 XawTextPosition index, dummy;
240 x = event->xmotion.x; y = event->xmotion.y;
241 currentPV = (w == outputField[1][nMemo]);
242 XawTextGetSelectionPos(w, &index, &dummy);
243 XtSetArg(arg, XtNstring, &val);
244 XtGetValues(w, &arg, 1);
245 shiftKey = strcmp(params[0], "0");
246 if(LoadMultiPV(x, y, val, index, &start, &end)) {
247 XawTextSetSelection( outputField[currentPV][nMemo], start, end );
248 highTextStart[currentPV] = start; highTextEnd[currentPV] = end;
253 StopPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
254 { // [HGM] pv: on right-button release, stop displaying PV
255 XawTextUnsetSelection( w );
256 highTextStart[currentPV] = highTextEnd[currentPV] = 0;
261 MemoCB(Widget w, XtPointer client_data, Atom *selection,
262 Atom *type, XtPointer value, unsigned long *len, int *format)
264 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
265 selected_fen_position = value;
266 selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
267 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
269 SendPositionSelection,
270 NULL/* lose_ownership_proc */ ,
271 NULL/* transfer_done_proc */);
274 void CopyMemoProc(w, event, prms, nprms)
280 if(appData.pasteSelection) return;
281 if (selected_fen_position) free(selected_fen_position);
282 XtGetSelectionValue(menuBarWidget,
283 XA_PRIMARY, XA_STRING,
284 /* (XtSelectionCallbackProc) */ MemoCB,
285 NULL, /* client_data passed to PastePositionCB */
287 /* better to use the time field from the event that triggered the
288 * call to this function, but that isn't trivial to get
294 // The following routines are mutated clones of the commentPopUp routines
296 void PositionControlSet(which, shell, form, bw_width)
302 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
305 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
306 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
307 XtSetArg(args[j], XtNtop, XtChainTop); j++;
308 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
309 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
310 XtSetArg(args[j], XtNright, XtChainLeft); j++;
311 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
312 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
313 outputField[which][nColorIcon] = ColorWidget =
314 XtCreateManagedWidget("Color", labelWidgetClass,
318 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
319 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
320 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
321 XtSetArg(args[j], XtNtop, XtChainTop); j++;
322 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
323 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
324 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
325 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
326 outputField[which][nLabel] = NameWidget =
327 XtCreateManagedWidget("Engine", labelWidgetClass,
331 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
332 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
333 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
334 XtSetArg(args[j], XtNtop, XtChainTop); j++;
335 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
336 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
337 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
338 outputField[which][nStateIcon] = ModeWidget =
339 XtCreateManagedWidget("Mode", labelWidgetClass,
343 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
344 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
345 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
346 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
347 XtSetArg(args[j], XtNtop, XtChainTop); j++;
348 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
349 XtSetArg(args[j], XtNright, XtChainRight); j++;
350 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
351 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
352 outputField[which][nStateData] = MoveWidget =
353 XtCreateManagedWidget("Move", labelWidgetClass,
357 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
358 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
359 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
360 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
361 XtSetArg(args[j], XtNtop, XtChainTop); j++;
362 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
363 XtSetArg(args[j], XtNleft, XtChainRight); j++;
364 XtSetArg(args[j], XtNright, XtChainRight); j++;
365 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
366 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
367 outputField[which][nLabelNPS] = NodesWidget =
368 XtCreateManagedWidget("Nodes", labelWidgetClass,
371 // create "text" within "form"
374 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
375 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
377 XtSetArg(args[j], XtNstring, ""); j++;
378 XtSetArg(args[j], XtNdisplayCaret, False); j++;
379 XtSetArg(args[j], XtNtop, XtChainTop); j++;
380 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
381 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
382 XtSetArg(args[j], XtNright, XtChainRight); j++;
383 XtSetArg(args[j], XtNresizable, True); j++;
384 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
385 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
386 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
387 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
388 // XtSetArg(args[j], XtNautoFill, True); j++;
389 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
390 outputField[which][nMemo] = edit =
391 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
393 XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
394 XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
397 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
398 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
399 XtSetValues(edit, args, j);
402 Widget EngineOutputCreate(name, text)
406 Widget shell, layout, form, form2;
407 Dimension bw_width, bw_height;
412 XtSetArg(args[j], XtNwidth, &bw_width); j++;
413 XtSetArg(args[j], XtNheight, &bw_height); j++;
414 XtGetValues(boardWidget, args, j);
416 // define form within layout within shell.
418 XtSetArg(args[j], XtNresizable, True); j++;
421 XtCreatePopupShell(name, topLevelShellWidgetClass,
423 XtCreatePopupShell(name, transientShellWidgetClass,
425 shellWidget, args, j);
427 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
428 layoutArgs, XtNumber(layoutArgs));
429 // divide window vertically into two equal parts, by creating two forms
431 XtCreateManagedWidget("form", formWidgetClass, layout,
432 formArgs, XtNumber(formArgs));
434 XtCreateManagedWidget("form2", formWidgetClass, layout,
435 formArgs, XtNumber(formArgs));
437 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
438 XtSetValues(form2, args, j);
439 // make sure width is known in advance, for better placement of child widgets
441 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
442 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
443 XtSetValues(shell, args, j);
445 // fill up both forms with control elements
446 PositionControlSet(0, shell, form, bw_width);
447 PositionControlSet(1, shell, form2, bw_width);
449 XtRealizeWidget(shell);
451 if(wpEngineOutput.width > 0) {
452 engineOutputW = wpEngineOutput.width;
453 engineOutputH = wpEngineOutput.height;
454 engineOutputX = wpEngineOutput.x;
455 engineOutputY = wpEngineOutput.y;
458 if (engineOutputX == -1) {
462 engineOutputH = bw_height/2;
463 engineOutputW = bw_width-16;
465 XSync(xDisplay, False);
467 /* This code seems to tickle an X bug if it is executed too soon
468 after xboard starts up. The coordinates get transformed as if
469 the main window was positioned at (0, 0).
471 XtTranslateCoords(shellWidget,
472 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
473 &engineOutputX, &engineOutputY);
475 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
476 RootWindowOfScreen(XtScreen(shellWidget)),
477 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
482 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
485 XtSetArg(args[j], XtNheight, engineOutputH); j++;
486 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
487 XtSetArg(args[j], XtNx, engineOutputX); j++;
488 XtSetArg(args[j], XtNy, engineOutputY); j++;
489 XtSetValues(shell, args, j);
494 void ResizeWindowControls(mode)
500 Dimension ew_height, tmp;
501 Widget shell = engineOutputShell;
503 form1 = XtNameToWidget(shell, "*form");
504 form2 = XtNameToWidget(shell, "*form2");
507 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
508 XtGetValues(form1, args, j);
510 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
511 XtGetValues(form2, args, j);
512 ew_height += tmp; // total height
516 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
517 XtSetValues(form2, args, j);
519 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
520 XtSetValues(form1, args, j);
523 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
524 XtSetValues(form1, args, j);
526 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
527 XtSetValues(form2, args, j);
537 static int needInit = TRUE;
538 static char *title = N_("Engine output"), *text = N_("This feature is experimental");
540 if (engineOutputShell == NULL) {
542 EngineOutputCreate(_(title), _(text));
543 XtRealizeWidget(engineOutputShell);
544 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
546 InitializeEngineOutput();
549 SetEngineColorIcon( 0 );
550 SetEngineColorIcon( 1 );
551 SetEngineState( 0, STATE_IDLE, "" );
552 SetEngineState( 1, STATE_IDLE, "" );
554 edit = XtNameToWidget(engineOutputShell, "*form.text");
556 XtSetArg(args[j], XtNstring, text); j++;
557 XtSetValues(edit, args, j);
559 XtSetArg(args[j], XtNiconName, (XtArgVal) _(title)); j++;
560 XtSetArg(args[j], XtNtitle, (XtArgVal) _(title)); j++;
561 XtSetValues(engineOutputShell, args, j);
564 XtPopup(engineOutputShell, XtGrabNone);
565 XSync(xDisplay, False);
568 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
569 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Engine Output"),
572 engineOutputDialogUp = True;
573 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
576 void EngineOutputPopDown()
581 if (!engineOutputDialogUp) return;
584 XtSetArg(args[j], XtNx, &engineOutputX); j++;
585 XtSetArg(args[j], XtNy, &engineOutputY); j++;
586 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
587 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
588 XtGetValues(engineOutputShell, args, j);
589 wpEngineOutput.x = engineOutputX - 4;
590 wpEngineOutput.y = engineOutputY - 23;
591 wpEngineOutput.width = engineOutputW;
592 wpEngineOutput.height = engineOutputH;
593 XtPopdown(engineOutputShell);
594 XSync(xDisplay, False);
596 XtSetArg(args[j], XtNleftBitmap, None); j++;
597 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Engine Output"),
600 engineOutputDialogUp = False;
601 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
604 int EngineOutputIsUp()
606 return engineOutputDialogUp;
609 int EngineOutputDialogExists()
611 return engineOutputShell != NULL;
615 EngineOutputProc(w, event, prms, nprms)
621 if (engineOutputDialogUp) {
622 EngineOutputPopDown();