4 * Author: Alessandro Scotti (Dec 2005)
6 * Copyright 2005 Alessandro Scotti
8 * Enhancements Copyright 2009, 2010, 2011, 2012 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;
116 static int engineOutputDialogUp;
118 /* Module variables */
120 static int currentPV, highTextStart[2], highTextEnd[2];
135 //static void UpdateControls( EngineOutputData * ed );
138 ReadIcon (char *pixData[], int iconNr)
142 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
145 NULL, NULL /*&attr*/)) != 0) {
146 fprintf(stderr, _("Error %d loading icon image\n"), r);
152 InitializeEngineOutput ()
154 ReadIcon(WHITE_14, nColorWhite);
155 ReadIcon(BLACK_14, nColorBlack);
156 ReadIcon(UNKNOWN_14, nColorUnknown);
158 ReadIcon(CLEAR_14, nClear);
159 ReadIcon(PONDER_14, nPondering);
160 ReadIcon(THINK_14, nThinking);
161 ReadIcon(ANALYZE_14, nAnalyzing);
165 DoSetWindowText (int which, int field, char *s_label)
169 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
170 XtSetValues(outputField[which][field], &arg, 1);
174 SetEngineOutputTitle (char *title)
177 XtSetArg(arg, XtNtitle, (XtArgVal) title);
178 XtSetValues(engineOutputShell, &arg, 1);
182 InsertIntoMemo (int which, char * text, int where)
187 /* the backend adds \r\n, which is needed for winboard,
188 * for xboard we delete them again over here */
189 if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
191 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
192 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
193 XawTextReplace(edit, where, where, &t);
194 if(where < highTextStart[which]) { // [HGM] multiPVdisplay: move highlighting
195 int len = strlen(text);
196 highTextStart[which] += len; highTextEnd[which] += len;
197 XawTextSetSelection( outputField[which][nMemo], highTextStart[which], highTextEnd[which] );
202 SetIcon (int which, int field, int nIcon)
207 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
208 XtSetValues(outputField[which][field], &arg, 1);
213 DoClearMemo (int which)
215 Widget edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
217 // XtCallActionProc(edit, "select-all", NULL, NULL, 0);
218 // XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
219 XtSetArg(arg, XtNstring, ""); // clear without disturbing selection!
220 XtSetValues(edit, &arg, 1);
223 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
225 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
226 Atom *type_return, XtPointer *value_return,
227 unsigned long *length_return, int *format_return); // from xboard.c
228 void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
230 char memoTranslations[] =
231 ":Ctrl<Key>c: CopyMemoProc() \n \
232 <Btn3Motion>: HandlePV() \n \
233 Shift<Btn3Down>: select-start() SelectPV(1) \n \
234 Any<Btn3Down>: select-start() SelectPV(0) \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 shiftKey = strcmp(params[0], "0");
252 if(LoadMultiPV(x, y, val, index, &start, &end)) {
253 XawTextSetSelection( outputField[currentPV][nMemo], start, end );
254 highTextStart[currentPV] = start; highTextEnd[currentPV] = end;
259 StopPV (Widget w, XEvent * event, String * params, Cardinal * nParams)
260 { // [HGM] pv: on right-button release, stop displaying PV
261 XawTextUnsetSelection( w );
262 highTextStart[currentPV] = highTextEnd[currentPV] = 0;
267 MemoCB (Widget w, XtPointer client_data, Atom *selection,
268 Atom *type, XtPointer value, unsigned long *len, int *format)
270 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
271 selected_fen_position = value;
272 selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
273 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
275 SendPositionSelection,
276 NULL/* lose_ownership_proc */ ,
277 NULL/* transfer_done_proc */);
281 CopyMemoProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
283 if(appData.pasteSelection) return;
284 if (selected_fen_position) free(selected_fen_position);
285 XtGetSelectionValue(menuBarWidget,
286 XA_PRIMARY, XA_STRING,
287 /* (XtSelectionCallbackProc) */ MemoCB,
288 NULL, /* client_data passed to PastePositionCB */
290 /* better to use the time field from the event that triggered the
291 * call to this function, but that isn't trivial to get
297 // The following routines are mutated clones of the commentPopUp routines
300 PositionControlSet (int which, Widget shell, Widget form, Dimension bw_width)
303 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
306 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
307 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
308 XtSetArg(args[j], XtNtop, XtChainTop); j++;
309 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
310 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
311 XtSetArg(args[j], XtNright, XtChainLeft); 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], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
325 outputField[which][nLabel] = NameWidget =
326 XtCreateManagedWidget("Engine", labelWidgetClass,
330 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
331 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
332 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
333 XtSetArg(args[j], XtNtop, XtChainTop); j++;
334 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
335 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
336 outputField[which][nStateIcon] = ModeWidget =
337 XtCreateManagedWidget("Mode", labelWidgetClass,
341 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
342 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
343 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
344 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
345 XtSetArg(args[j], XtNtop, XtChainTop); j++;
346 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
347 XtSetArg(args[j], XtNright, XtChainRight); j++;
348 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
349 outputField[which][nStateData] = MoveWidget =
350 XtCreateManagedWidget("Move", labelWidgetClass,
354 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
355 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
356 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
357 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
358 XtSetArg(args[j], XtNtop, XtChainTop); j++;
359 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
360 XtSetArg(args[j], XtNleft, XtChainRight); j++;
361 XtSetArg(args[j], XtNright, XtChainRight); j++;
362 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
363 outputField[which][nLabelNPS] = NodesWidget =
364 XtCreateManagedWidget("Nodes", labelWidgetClass,
367 // create "text" within "form"
370 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
371 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
373 XtSetArg(args[j], XtNstring, ""); j++;
374 XtSetArg(args[j], XtNdisplayCaret, False); j++;
375 XtSetArg(args[j], XtNtop, XtChainTop); j++;
376 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
377 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
378 XtSetArg(args[j], XtNright, XtChainRight); j++;
379 XtSetArg(args[j], XtNresizable, True); j++;
380 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
381 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
382 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
383 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
384 // XtSetArg(args[j], XtNautoFill, True); j++;
385 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
386 outputField[which][nMemo] = edit =
387 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
389 XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
390 XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
393 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
394 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
395 XtSetValues(edit, args, j);
399 EngineOutputCreate (char *name, char *text)
402 Widget shell, layout, form, form2;
403 Dimension bw_width, bw_height;
408 XtSetArg(args[j], XtNwidth, &bw_width); j++;
409 XtSetArg(args[j], XtNheight, &bw_height); j++;
410 XtGetValues(boardWidget, args, j);
412 // define form within layout within shell.
414 XtSetArg(args[j], XtNresizable, True); j++;
417 XtCreatePopupShell(name, topLevelShellWidgetClass,
419 XtCreatePopupShell(name, transientShellWidgetClass,
421 shellWidget, args, j);
423 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
424 layoutArgs, XtNumber(layoutArgs));
425 // divide window vertically into two equal parts, by creating two forms
427 XtCreateManagedWidget("form", formWidgetClass, layout,
428 formArgs, XtNumber(formArgs));
430 XtCreateManagedWidget("form2", formWidgetClass, layout,
431 formArgs, XtNumber(formArgs));
433 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
434 XtSetValues(form2, args, j);
435 // make sure width is known in advance, for better placement of child widgets
437 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
438 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
439 XtSetValues(shell, args, j);
441 // fill up both forms with control elements
442 PositionControlSet(0, shell, form, bw_width);
443 PositionControlSet(1, shell, form2, bw_width);
445 XtRealizeWidget(shell);
447 if(wpEngineOutput.width > 0) {
448 engineOutputW = wpEngineOutput.width;
449 engineOutputH = wpEngineOutput.height;
450 engineOutputX = wpEngineOutput.x;
451 engineOutputY = wpEngineOutput.y;
454 if (engineOutputX == -1) {
458 engineOutputH = bw_height/2;
459 engineOutputW = bw_width-16;
461 XSync(xDisplay, False);
463 /* This code seems to tickle an X bug if it is executed too soon
464 after xboard starts up. The coordinates get transformed as if
465 the main window was positioned at (0, 0).
467 XtTranslateCoords(shellWidget,
468 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
469 &engineOutputX, &engineOutputY);
471 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
472 RootWindowOfScreen(XtScreen(shellWidget)),
473 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
478 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
481 XtSetArg(args[j], XtNheight, engineOutputH); j++;
482 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
483 XtSetArg(args[j], XtNx, engineOutputX); j++;
484 XtSetArg(args[j], XtNy, engineOutputY); j++;
485 XtSetValues(shell, args, j);
491 ResizeWindowControls (int mode)
496 Dimension ew_height, tmp;
497 Widget shell = engineOutputShell;
499 form1 = XtNameToWidget(shell, "*form");
500 form2 = XtNameToWidget(shell, "*form2");
503 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
504 XtGetValues(form1, args, j);
506 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
507 XtGetValues(form2, args, j);
508 ew_height += tmp; // total height
512 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
513 XtSetValues(form2, args, j);
515 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
516 XtSetValues(form1, args, j);
519 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
520 XtSetValues(form1, args, j);
522 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
523 XtSetValues(form2, args, j);
533 static int needInit = TRUE;
534 static char *title = N_("Engine output"), *text = N_("This feature is experimental");
536 if (engineOutputShell == NULL) {
538 EngineOutputCreate(_(title), _(text));
539 XtRealizeWidget(engineOutputShell);
540 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
542 InitializeEngineOutput();
545 SetEngineColorIcon( 0 );
546 SetEngineColorIcon( 1 );
547 SetEngineState( 0, STATE_IDLE, "" );
548 SetEngineState( 1, STATE_IDLE, "" );
550 edit = XtNameToWidget(engineOutputShell, "*form.text");
552 XtSetArg(args[j], XtNstring, text); j++;
553 XtSetValues(edit, args, j);
555 XtSetArg(args[j], XtNiconName, (XtArgVal) _(title)); j++;
556 XtSetArg(args[j], XtNtitle, (XtArgVal) _(title)); j++;
557 XtSetValues(engineOutputShell, args, j);
560 XtPopup(engineOutputShell, XtGrabNone);
561 XSync(xDisplay, False);
564 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
565 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Engine Output"),
568 engineOutputDialogUp = True;
569 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
573 EngineOutputPopDown ()
578 if (!engineOutputDialogUp) return;
581 XtSetArg(args[j], XtNx, &engineOutputX); j++;
582 XtSetArg(args[j], XtNy, &engineOutputY); j++;
583 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
584 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
585 XtGetValues(engineOutputShell, args, j);
586 wpEngineOutput.x = engineOutputX - 4;
587 wpEngineOutput.y = engineOutputY - 23;
588 wpEngineOutput.width = engineOutputW;
589 wpEngineOutput.height = engineOutputH;
590 XtPopdown(engineOutputShell);
591 XSync(xDisplay, False);
593 XtSetArg(args[j], XtNleftBitmap, None); j++;
594 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Engine Output"),
597 engineOutputDialogUp = False;
598 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
604 return engineOutputDialogUp;
608 EngineOutputDialogExists ()
610 return engineOutputShell != NULL;
614 EngineOutputProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
616 if (engineOutputDialogUp) {
617 EngineOutputPopDown();