4 * Author: Alessandro Scotti (Dec 2005)
6 * Copyright 2005 Alessandro Scotti
8 * Enhancements Copyright 2009 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, boardWidget, menuBarWidget;
105 extern Window xBoardWindow;
106 extern int squareSize;
107 extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap;
108 extern char *layoutName;
110 Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
111 Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle
113 void EngineOutputPopDown();
114 void engineOutputPopUp();
115 int EngineOutputIsUp();
116 void SetEngineColorIcon( int which );
118 /* Imports from backend.c */
119 extern int opponentKibitzes;
121 /* Imports from xboard.c */
122 extern Arg layoutArgs[2], formArgs[2], messageArgs[4];
124 //extern WindowPlacement wpEngineOutput;
126 Position engineOutputX = -1, engineOutputY = -1;
127 Dimension engineOutputW, engineOutputH;
128 Widget engineOutputShell;
129 static int engineOutputDialogUp;
131 /* Module variables */
147 //static void UpdateControls( EngineOutputData * ed );
149 void ReadIcon(char *pixData[], int iconNr)
153 // if ((r=XpmCreatePixmapFromData(xDisplay, XtWindow(outputField[0][nColorIcon]),
156 // NULL, NULL /*&attr*/)) != 0) {
157 // fprintf(stderr, _("Error %d loading icon image\n"), r);
162 static void InitializeEngineOutput()
165 ReadIcon(WHITE_14, nColorWhite);
166 ReadIcon(BLACK_14, nColorBlack);
167 ReadIcon(UNKNOWN_14, nColorUnknown);
169 ReadIcon(CLEAR_14, nClear);
170 ReadIcon(PONDER_14, nPondering);
171 ReadIcon(THINK_14, nThinking);
172 ReadIcon(ANALYZE_14, nAnalyzing);
175 void DoSetWindowText(int which, int field, char *s_label)
179 XtSetArg(arg, XtNlabel, (XtArgVal) s_label);
180 XtSetValues(outputField[which][field], &arg, 1);
183 void InsertIntoMemo( int which, char * text, int where )
185 Arg arg; XawTextBlock t; Widget edit;
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 // XtSetArg(arg, XtNstring, (XtArgVal) text);
195 // XtSetValues(outputField[which][nMemo], &arg, 1);
198 void SetIcon( int which, int field, int nIcon )
203 XtSetArg(arg, XtNleftBitmap, (XtArgVal) icons[nIcon]);
204 XtSetValues(outputField[which][field], &arg, 1);
208 void DoClearMemo(int which)
214 edit = XtNameToWidget(engineOutputShell, which ? "*form2.text" : "*form.text");
215 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
216 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
219 // cloned from CopyPositionProc. Abuse selected_fen_position to hold selection
221 extern char *selected_fen_position;
223 Boolean SendPositionSelection(Widget w, Atom *selection, Atom *target,
224 Atom *type_return, XtPointer *value_return,
225 unsigned long *length_return, int *format_return); // from xboard.c
226 void SetFocus(Widget w, XtPointer data, XEvent *event, Boolean *b); // from xoptions.c
228 char memoTranslations[] =
229 ":Ctrl<Key>c: CopyMemoProc() \n";
232 MemoCB(Widget w, XtPointer client_data, Atom *selection,
233 Atom *type, XtPointer value, unsigned long *len, int *format)
235 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
236 selected_fen_position = value;
237 selected_fen_position[*len]='\0'; /* normally this string is terminated, but be safe */
238 // XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
240 // SendPositionSelection,
241 // NULL/* lose_ownership_proc */ ,
242 // NULL/* transfer_done_proc */);
245 void CopyMemoProc(w, event, prms, nprms)
251 if(appData.pasteSelection) return;
252 if (selected_fen_position) free(selected_fen_position);
253 XtGetSelectionValue(menuBarWidget,
254 XA_PRIMARY, XA_STRING,
255 /* (XtSelectionCallbackProc) */ MemoCB,
256 NULL, /* client_data passed to PastePositionCB */
258 /* better to use the time field from the event that triggered the
259 * call to this function, but that isn't trivial to get
265 // The following routines are mutated clones of the commentPopUp routines
267 void PositionControlSet(which, shell, form, bw_width)
273 Widget edit, NameWidget, ColorWidget, ModeWidget, MoveWidget, NodesWidget;
276 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
277 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
278 XtSetArg(args[j], XtNtop, XtChainTop); j++;
279 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
280 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
281 XtSetArg(args[j], XtNright, XtChainLeft); j++;
282 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
283 XtSetArg(args[j], XtNwidth, (XtArgVal) 17); j++;
284 outputField[which][nColorIcon] = ColorWidget =
285 XtCreateManagedWidget("Color", labelWidgetClass,
289 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
290 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
291 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ColorWidget); j++;
292 XtSetArg(args[j], XtNtop, XtChainTop); j++;
293 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
294 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
295 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
296 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 57); j++;
297 outputField[which][nLabel] = NameWidget =
298 XtCreateManagedWidget("Engine", labelWidgetClass,
302 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
303 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
304 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) NameWidget); j++;
305 XtSetArg(args[j], XtNtop, XtChainTop); j++;
306 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
307 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
308 XtSetArg(args[j], XtNwidth, (XtArgVal) 20); j++;
309 outputField[which][nStateIcon] = ModeWidget =
310 XtCreateManagedWidget("Mode", labelWidgetClass,
314 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
315 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyLeft); j++;
316 XtSetArg(args[j], XtNlabel, (XtArgVal) ""); j++;
317 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) ModeWidget); j++;
318 XtSetArg(args[j], XtNtop, XtChainTop); j++;
319 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
320 XtSetArg(args[j], XtNright, XtChainRight); j++;
321 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
322 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width/2 - 102); j++;
323 outputField[which][nStateData] = MoveWidget =
324 XtCreateManagedWidget("Move", labelWidgetClass,
328 XtSetArg(args[j], XtNborderWidth, (XtArgVal) 0); j++;
329 XtSetArg(args[j], XtNjustify, (XtArgVal) XtJustifyRight); j++;
330 XtSetArg(args[j], XtNlabel, (XtArgVal) _("NPS")); j++;
331 XtSetArg(args[j], XtNfromHoriz, (XtArgVal) MoveWidget); j++;
332 XtSetArg(args[j], XtNtop, XtChainTop); j++;
333 XtSetArg(args[j], XtNbottom, XtChainTop); j++;
334 XtSetArg(args[j], XtNleft, XtChainRight); j++;
335 XtSetArg(args[j], XtNright, XtChainRight); j++;
336 XtSetArg(args[j], XtNheight, (XtArgVal) 16); j++;
337 XtSetArg(args[j], XtNwidth, (XtArgVal) 100); j++;
338 outputField[which][nLabelNPS] = NodesWidget =
339 XtCreateManagedWidget("Nodes", labelWidgetClass,
342 // create "text" within "form"
345 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
346 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
348 XtSetArg(args[j], XtNstring, ""); j++;
349 XtSetArg(args[j], XtNdisplayCaret, False); j++;
350 XtSetArg(args[j], XtNtop, XtChainTop); j++;
351 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
352 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
353 XtSetArg(args[j], XtNright, XtChainRight); j++;
354 XtSetArg(args[j], XtNresizable, True); j++;
355 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
356 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
357 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
358 XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollWhenNeeded); j++;
359 // XtSetArg(args[j], XtNautoFill, True); j++;
360 // XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
361 outputField[which][nMemo] = edit =
362 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
364 XtOverrideTranslations(edit, XtParseTranslationTable(memoTranslations));
365 XtAddEventHandler(edit, ButtonPressMask, False, SetFocus, (XtPointer) shell);
368 XtSetArg(args[j], XtNfromVert, ColorWidget); j++;
369 // XtSetArg(args[j], XtNresizable, (XtArgVal) True); j++;
370 XtSetValues(edit, args, j);
373 Widget EngineOutputCreate(name, text)
377 Widget shell, layout, form, form2, edit;
378 Dimension bw_width, bw_height;
383 XtSetArg(args[j], XtNwidth, &bw_width); j++;
384 XtSetArg(args[j], XtNheight, &bw_height); j++;
385 XtGetValues(boardWidget, args, j);
387 // define form within layout within shell.
389 XtSetArg(args[j], XtNresizable, True); j++;
392 // XtCreatePopupShell(name, topLevelShellWidgetClass,
394 // XtCreatePopupShell(name, transientShellWidgetClass,
396 // shellWidget, args, j);
398 // XtCreateManagedWidget(layoutName, formWidgetClass, shell,
399 // layoutArgs, XtNumber(layoutArgs));
400 // divide window vertically into two equal parts, by creating two forms
402 XtCreateManagedWidget("form", formWidgetClass, layout,
403 formArgs, XtNumber(formArgs));
405 XtCreateManagedWidget("form2", formWidgetClass, layout,
406 formArgs, XtNumber(formArgs));
408 XtSetArg(args[j], XtNfromVert, (XtArgVal) form); j++;
409 XtSetValues(form2, args, j);
410 // make sure width is known in advance, for better placement of child widgets
412 XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++;
413 XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/2); j++;
414 XtSetValues(shell, args, j);
416 // fill up both forms with control elements
417 PositionControlSet(0, shell, form, bw_width);
418 PositionControlSet(1, shell, form2, bw_width);
420 XtRealizeWidget(shell);
422 if(wpEngineOutput.width > 0) {
423 engineOutputW = wpEngineOutput.width;
424 engineOutputH = wpEngineOutput.height;
425 engineOutputX = wpEngineOutput.x;
426 engineOutputY = wpEngineOutput.y;
429 if (engineOutputX == -1) {
434 engineOutputH = bw_height/2;
435 engineOutputW = bw_width-16;
437 // XSync(xDisplay, False);
439 /* This code seems to tickle an X bug if it is executed too soon
440 after xboard starts up. The coordinates get transformed as if
441 the main window was positioned at (0, 0).
443 // XtTranslateCoords(shellWidget,
444 // (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
445 // &engineOutputX, &engineOutputY);
447 // XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
448 // RootWindowOfScreen(XtScreen(shellWidget)),
449 // (bw_width - engineOutputW) / 2, 0 - engineOutputH / 2,
454 if (engineOutputY < 0) engineOutputY = 0; /*avoid positioning top offscreen*/
457 XtSetArg(args[j], XtNheight, engineOutputH); j++;
458 XtSetArg(args[j], XtNwidth, engineOutputW); j++;
459 XtSetArg(args[j], XtNx, engineOutputX); j++;
460 XtSetArg(args[j], XtNy, engineOutputY); j++;
461 XtSetValues(shell, args, j);
462 // XtSetKeyboardFocus(shell, edit);
467 void ResizeWindowControls(mode)
473 Dimension ew_height, tmp;
474 Widget shell = engineOutputShell;
476 form1 = XtNameToWidget(shell, "*form");
477 form2 = XtNameToWidget(shell, "*form2");
480 XtSetArg(args[j], XtNheight, (XtArgVal) &ew_height); j++;
481 XtGetValues(form1, args, j);
483 XtSetArg(args[j], XtNheight, (XtArgVal) &tmp); j++;
484 XtGetValues(form2, args, j);
485 ew_height += tmp; // total height
489 XtSetArg(args[j], XtNheight, (XtArgVal) 5); j++;
490 XtSetValues(form2, args, j);
492 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height-5)); j++;
493 XtSetValues(form1, args, j);
496 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
497 XtSetValues(form1, args, j);
499 XtSetArg(args[j], XtNheight, (XtArgVal) (ew_height/2)); j++;
500 XtSetValues(form2, args, j);
510 static int needInit = TRUE;
511 static char *title = _("Engine output"), *text = _("This feature is experimental");
513 if (engineOutputShell == NULL) {
515 EngineOutputCreate(title, text);
516 XtRealizeWidget(engineOutputShell);
517 // CatchDeleteWindow(engineOutputShell, "EngineOutputPopDown");
519 InitializeEngineOutput();
522 SetEngineColorIcon( 0 );
523 SetEngineColorIcon( 1 );
524 SetEngineState( 0, STATE_IDLE, "" );
525 SetEngineState( 1, STATE_IDLE, "" );
527 edit = XtNameToWidget(engineOutputShell, "*form.text");
529 XtSetArg(args[j], XtNstring, text); j++;
530 XtSetValues(edit, args, j);
532 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
533 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
534 XtSetValues(engineOutputShell, args, j);
537 XtPopup(engineOutputShell, XtGrabNone);
538 // XSync(xDisplay, False);
541 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
542 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
545 engineOutputDialogUp = True;
546 ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output
549 void EngineOutputPopDown()
554 if (!engineOutputDialogUp) return;
557 XtSetArg(args[j], XtNx, &engineOutputX); j++;
558 XtSetArg(args[j], XtNy, &engineOutputY); j++;
559 XtSetArg(args[j], XtNwidth, &engineOutputW); j++;
560 XtSetArg(args[j], XtNheight, &engineOutputH); j++;
561 XtGetValues(engineOutputShell, args, j);
562 wpEngineOutput.x = engineOutputX - 4;
563 wpEngineOutput.y = engineOutputY - 23;
564 wpEngineOutput.width = engineOutputW;
565 wpEngineOutput.height = engineOutputH;
566 XtPopdown(engineOutputShell);
567 // XSync(xDisplay, False);
569 XtSetArg(args[j], XtNleftBitmap, None); j++;
570 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Show Engine Output"),
573 engineOutputDialogUp = False;
574 ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
577 int EngineOutputIsUp()
579 return engineOutputDialogUp;
582 int EngineOutputDialogExists()
584 return engineOutputShell != NULL;
588 EngineOutputProc(w, event, prms, nprms)
594 if (engineOutputDialogUp) {
595 EngineOutputPopDown();