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 */
148 //static void UpdateControls( EngineOutputData * ed );
150 void ReadIcon(char *pixData[], int iconNr)
154 if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
157 NULL, NULL /*&attr*/)) != 0) {
158 fprintf(stderr, _("Error %d loading icon image\n"), r);
163 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 )
186 Arg arg; XawTextBlock t; Widget edit;
188 /* the backend adds \r\n, which is needed for winboard,
189 * for xboard we delete them again over here */
190 if(t.ptr = strchr(text, '\r')) *t.ptr = ' ';
192 t.ptr = text; t.firstPos = 0; t.length = strlen(text); t.format = XawFmt8Bit;
193 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
194 XawTextReplace(edit, where, where, &t);
195 // XtSetArg(arg, XtNstring, (XtArgVal) text);
196 // XtSetValues(outputField[which][nMemo], &arg, 1);
199 void SetIcon( int which, int field, int nIcon )
204 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
205 XtSetValues(outputField[which][field], &arg, 1);
209 void DoClearMemo(int which)
215 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
216 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
217 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
220 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
222 extern char *selected_fen_position;
224 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
225 Atom *type_return, XtPointer *value_return,
226 unsigned long *length_return, int *format_return); // from xboard.c
227 void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
229 char memoTranslations[] =
230 ":Ctrl<Key>c: CopyMemoProc() \n";
233 MemoCB(Widget w, XtPointer client_data, Atom *selection,
234 Atom *type, XtPointer value, unsigned long *len, int *format)
236 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
237 selected_fen_position = value;
238 selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
239 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
241 SendPositionSelection,
242 NULL/* lose_ownership_proc */ ,
243 NULL/* transfer_done_proc */);
246 void CopyMemoProc(w, event, prms, nprms)
252 if(appData.pasteSelection) return;
253 if (selected_fen_position) free(selected_fen_position);
254 XtGetSelectionValue(menuBarWidget,
255 XA_PRIMARY, XA_STRING,
256 /* (XtSelectionCallbackProc) */ MemoCB,
257 NULL, /* client_data passed to PastePositionCB */
259 /* better to use the time field from the event that triggered the
260 * call to this function, but that isn't trivial to get
266 // The following routines are mutated clones of the commentPopUp routines
268 void PositionControlSet(which, shell, form, bw_width)
274 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
277 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
278 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
279 XtSetArg(args[j], XtNtop, XtChainTop); j++;
280 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
281 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
282 XtSetArg(args[j], XtNright, XtChainLeft); j++;
283 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
284 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
285 outputField[which][nColorIcon] = ColorWidget =
286 XtCreateManagedWidget("Color", labelWidgetClass,
290 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
291 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
292 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
293 XtSetArg(args[j], XtNtop, XtChainTop); j++;
294 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
295 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
296 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
297 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
298 outputField[which][nLabel] = NameWidget =
299 XtCreateManagedWidget("Engine", labelWidgetClass,
303 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
304 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
305 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
306 XtSetArg(args[j], XtNtop, XtChainTop); j++;
307 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
308 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
309 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
310 outputField[which][nStateIcon] = ModeWidget =
311 XtCreateManagedWidget("Mode", labelWidgetClass,
315 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
316 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
317 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
318 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
319 XtSetArg(args[j], XtNtop, XtChainTop); j++;
320 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
321 XtSetArg(args[j], XtNright, XtChainRight); j++;
322 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
323 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
324 outputField[which][nStateData] = MoveWidget =
325 XtCreateManagedWidget("Move", labelWidgetClass,
329 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
330 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
331 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
332 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
333 XtSetArg(args[j], XtNtop, XtChainTop); j++;
334 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
335 XtSetArg(args[j], XtNleft, XtChainRight); j++;
336 XtSetArg(args[j], XtNright, XtChainRight); j++;
337 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
338 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
339 outputField[which][nLabelNPS] = NodesWidget =
340 XtCreateManagedWidget("Nodes", labelWidgetClass,
343 // create "text" within "form"
346 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
347 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
349 XtSetArg(args[j], XtNstring, ""); j++;
350 XtSetArg(args[j], XtNdisplayCaret, False); j++;
351 XtSetArg(args[j], XtNtop, XtChainTop); j++;
352 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
353 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
354 XtSetArg(args[j], XtNright, XtChainRight); j++;
355 XtSetArg(args[j], XtNresizable, True); j++;
356 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
357 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
358 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
359 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
360 // XtSetArg(args[j], XtNautoFill, True); j++;
361 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
362 outputField[which][nMemo] = edit =
363 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
365 XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
366 XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
369 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
370 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
371 XtSetValues(edit, args, j);
374 Widget EngineOutputCreate(name, text)
378 Widget shell, layout, form, form2, edit;
379 Dimension bw_width, bw_height;
384 XtSetArg(args[j], XtNwidth, &bw_width); j++;
385 XtSetArg(args[j], XtNheight, &bw_height); j++;
386 XtGetValues(boardWidget, args, j);
388 // define form within layout within shell.
390 XtSetArg(args[j], XtNresizable, True); j++;
393 XtCreatePopupShell(name, topLevelShellWidgetClass,
395 XtCreatePopupShell(name, transientShellWidgetClass,
397 shellWidget, args, j);
399 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
400 layoutArgs, XtNumber(layoutArgs));
401 // divide window vertically into two equal parts, by creating two forms
403 XtCreateManagedWidget("form", formWidgetClass, layout,
404 formArgs, XtNumber(formArgs));
406 XtCreateManagedWidget("form2", formWidgetClass, layout,
407 formArgs, XtNumber(formArgs));
409 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
410 XtSetValues(form2, args, j);
411 // make sure width is known in advance, for better placement of child widgets
413 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
414 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
415 XtSetValues(shell, args, j);
417 // fill up both forms with control elements
418 PositionControlSet(0, shell, form, bw_width);
419 PositionControlSet(1, shell, form2, bw_width);
421 XtRealizeWidget(shell);
423 if(wpEngineOutput.width > 0) {
424 engineOutputW = wpEngineOutput.width;
425 engineOutputH = wpEngineOutput.height;
426 engineOutputX = wpEngineOutput.x;
427 engineOutputY = wpEngineOutput.y;
430 if (engineOutputX == -1) {
435 engineOutputH = bw_height/2;
436 engineOutputW = bw_width-16;
438 XSync(xDisplay, False);
440 /* This code seems to tickle an X bug if it is executed too soon
441 after xboard starts up. The coordinates get transformed as if
442 the main window was positioned at (0, 0).
444 XtTranslateCoords(shellWidget,
445 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
446 &engineOutputX, &engineOutputY);
448 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
449 RootWindowOfScreen(XtScreen(shellWidget)),
450 (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
455 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
458 XtSetArg(args[j], XtNheight, engineOutputH); j++;
459 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
460 XtSetArg(args[j], XtNx, engineOutputX); j++;
461 XtSetArg(args[j], XtNy, engineOutputY); j++;
462 XtSetValues(shell, args, j);
463 // XtSetKeyboardFocus(shell, edit);
468 void ResizeWindowControls(mode)
474 Dimension ew_height, tmp;
475 Widget shell = engineOutputShell;
477 form1 = XtNameToWidget(shell, "*form");
478 form2 = XtNameToWidget(shell, "*form2");
481 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
482 XtGetValues(form1, args, j);
484 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
485 XtGetValues(form2, args, j);
486 ew_height += tmp; // total height
490 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
491 XtSetValues(form2, args, j);
493 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
494 XtSetValues(form1, args, j);
497 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
498 XtSetValues(form1, args, j);
500 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
501 XtSetValues(form2, args, j);
511 static int needInit = TRUE;
512 static char *title = _("Engine output"), *text = _("This feature is experimental");
514 if (engineOutputShell == NULL) {
516 EngineOutputCreate(title, text);
517 XtRealizeWidget(engineOutputShell);
518 CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
520 InitializeEngineOutput();
523 SetEngineColorIcon( 0 );
524 SetEngineColorIcon( 1 );
525 SetEngineState( 0, STATE_IDLE, "" );
526 SetEngineState( 1, STATE_IDLE, "" );
528 edit = XtNameToWidget(engineOutputShell, "*form.text");
530 XtSetArg(args[j], XtNstring, text); j++;
531 XtSetValues(edit, args, j);
533 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
534 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
535 XtSetValues(engineOutputShell, args, j);
538 XtPopup(engineOutputShell, XtGrabNone);
539 XSync(xDisplay, False);
542 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
543 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
546 engineOutputDialogUp = True;
547 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
550 void EngineOutputPopDown()
555 if (!engineOutputDialogUp) return;
558 XtSetArg(args[j], XtNx, &engineOutputX); j++;
559 XtSetArg(args[j], XtNy, &engineOutputY); j++;
560 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
561 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
562 XtGetValues(engineOutputShell, args, j);
563 wpEngineOutput.x = engineOutputX - 4;
564 wpEngineOutput.y = engineOutputY - 23;
565 wpEngineOutput.width = engineOutputW;
566 wpEngineOutput.height = engineOutputH;
567 XtPopdown(engineOutputShell);
568 XSync(xDisplay, False);
570 XtSetArg(args[j], XtNleftBitmap, None); j++;
571 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
574 engineOutputDialogUp = False;
575 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
578 int EngineOutputIsUp()
580 return engineOutputDialogUp;
583 int EngineOutputDialogExists()
585 return engineOutputShell != NULL;
589 EngineOutputProc(w, event, prms, nprms)
595 if (engineOutputDialogUp) {
596 EngineOutputPopDown();