2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
64 #include <cairo/cairo.h>
65 #include <cairo/cairo-xlib.h>
68 # if HAVE_SYS_SOCKET_H
69 # include <sys/socket.h>
70 # include <netinet/in.h>
72 # else /* not HAVE_SYS_SOCKET_H */
73 # if HAVE_LAN_SOCKET_H
74 # include <lan/socket.h>
76 # include <lan/netdb.h>
77 # else /* not HAVE_LAN_SOCKET_H */
78 # define OMIT_SOCKETS 1
79 # endif /* not HAVE_LAN_SOCKET_H */
80 # endif /* not HAVE_SYS_SOCKET_H */
81 #endif /* !OMIT_SOCKETS */
86 #else /* not STDC_HEADERS */
87 extern char *getenv();
90 # else /* not HAVE_STRING_H */
92 # endif /* not HAVE_STRING_H */
93 #endif /* not STDC_HEADERS */
96 # include <sys/fcntl.h>
97 #else /* not HAVE_SYS_FCNTL_H */
100 # endif /* HAVE_FCNTL_H */
101 #endif /* not HAVE_SYS_FCNTL_H */
103 #if HAVE_SYS_SYSTEMINFO_H
104 # include <sys/systeminfo.h>
105 #endif /* HAVE_SYS_SYSTEMINFO_H */
107 #if TIME_WITH_SYS_TIME
108 # include <sys/time.h>
112 # include <sys/time.h>
123 # include <sys/wait.h>
128 # define NAMLEN(dirent) strlen((dirent)->d_name)
129 # define HAVE_DIR_STRUCT
131 # define dirent direct
132 # define NAMLEN(dirent) (dirent)->d_namlen
134 # include <sys/ndir.h>
135 # define HAVE_DIR_STRUCT
138 # include <sys/dir.h>
139 # define HAVE_DIR_STRUCT
143 # define HAVE_DIR_STRUCT
151 #include <X11/Intrinsic.h>
152 #include <X11/StringDefs.h>
153 #include <X11/Shell.h>
154 #include <X11/cursorfont.h>
155 #include <X11/Xatom.h>
156 #include <X11/Xmu/Atoms.h>
158 #include <X11/Xaw3d/Dialog.h>
159 #include <X11/Xaw3d/Form.h>
160 #include <X11/Xaw3d/List.h>
161 #include <X11/Xaw3d/Label.h>
162 #include <X11/Xaw3d/SimpleMenu.h>
163 #include <X11/Xaw3d/SmeBSB.h>
164 #include <X11/Xaw3d/SmeLine.h>
165 #include <X11/Xaw3d/Box.h>
166 #include <X11/Xaw3d/MenuButton.h>
167 #include <X11/Xaw3d/Text.h>
168 #include <X11/Xaw3d/AsciiText.h>
170 #include <X11/Xaw/Dialog.h>
171 #include <X11/Xaw/Form.h>
172 #include <X11/Xaw/List.h>
173 #include <X11/Xaw/Label.h>
174 #include <X11/Xaw/SimpleMenu.h>
175 #include <X11/Xaw/SmeBSB.h>
176 #include <X11/Xaw/SmeLine.h>
177 #include <X11/Xaw/Box.h>
178 #include <X11/Xaw/MenuButton.h>
179 #include <X11/Xaw/Text.h>
180 #include <X11/Xaw/AsciiText.h>
183 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
192 #include "backendz.h"
196 #include "xgamelist.h"
197 #include "xhistory.h"
201 #include "engineoutput.h"
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
223 int main P((int argc, char **argv));
224 RETSIGTYPE CmailSigHandler P((int sig));
225 RETSIGTYPE IntSigHandler P((int sig));
226 RETSIGTYPE TermSizeSigHandler P((int sig));
227 Widget CreateMenuBar P((Menu *mb, int boardWidth));
229 char *InsertPxlSize P((char *pattern, int targetPxlSize));
230 XFontSet CreateFontSet P((char *base_fnt_lst));
232 char *FindFont P((char *pattern, int targetPxlSize));
234 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
235 u_int wreq, u_int hreq));
236 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
237 void DelayedDrag P((void));
238 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
239 void HandlePV P((Widget w, XEvent * event,
240 String * params, Cardinal * nParams));
241 void DrawPositionProc P((Widget w, XEvent *event,
242 String *prms, Cardinal *nprms));
243 void CommentClick P((Widget w, XEvent * event,
244 String * params, Cardinal * nParams));
245 void ICSInputBoxPopUp P((void));
246 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
247 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
248 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
249 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
250 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
251 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
252 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
253 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
254 Boolean TempBackwardActive = False;
255 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 void DisplayMove P((int moveNumber));
257 void update_ics_width P(());
258 int CopyMemoProc P(());
261 * XBoard depends on Xt R4 or higher
263 int xtVersion = XtSpecificationRelease;
268 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
269 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
270 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
271 Option *optList; // contains all widgets of main window
273 XFontSet fontSet, clockFontSet;
276 XFontStruct *clockFontStruct;
278 Font coordFontID, countFontID;
279 XFontStruct *coordFontStruct, *countFontStruct;
280 XtAppContext appContext;
283 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
285 Position commentX = -1, commentY = -1;
286 Dimension commentW, commentH;
287 typedef unsigned int BoardSize;
289 Boolean chessProgram;
291 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
292 int smallLayout = 0, tinyLayout = 0,
293 marginW, marginH, // [HGM] for run-time resizing
294 fromX = -1, fromY = -1, toX, toY, commentUp = False,
295 errorExitStatus = -1, defaultLineGap;
296 Dimension textHeight;
297 Pixel timerForegroundPixel, timerBackgroundPixel;
298 Pixel buttonForegroundPixel, buttonBackgroundPixel;
299 char *chessDir, *programName, *programVersion;
300 Boolean alwaysOnTop = False;
301 char *icsTextMenuString;
303 char *firstChessProgramNames;
304 char *secondChessProgramNames;
306 WindowPlacement wpMain;
307 WindowPlacement wpConsole;
308 WindowPlacement wpComment;
309 WindowPlacement wpMoveHistory;
310 WindowPlacement wpEvalGraph;
311 WindowPlacement wpEngineOutput;
312 WindowPlacement wpGameList;
313 WindowPlacement wpTags;
314 WindowPlacement wpDualBoard;
317 /* This magic number is the number of intermediate frames used
318 in each half of the animation. For short moves it's reduced
319 by 1. The total number of frames will be factor * 2 + 1. */
322 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
329 DropMenuEnables dmEnables[] = {
346 XtResource clientResources[] = {
347 { "flashCount", "flashCount", XtRInt, sizeof(int),
348 XtOffset(AppDataPtr, flashCount), XtRImmediate,
349 (XtPointer) FLASH_COUNT },
352 XrmOptionDescRec shellOptions[] = {
353 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
354 { "-flash", "flashCount", XrmoptionNoArg, "3" },
355 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
358 XtActionsRec boardActions[] = {
359 { "DrawPosition", DrawPositionProc },
360 { "HandlePV", HandlePV },
361 { "SelectPV", SelectPV },
362 { "StopPV", StopPV },
363 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
364 { "QuitProc", QuitWrapper },
365 { "ManProc", ManInner },
366 { "TempBackwardProc", TempBackwardProc },
367 { "TempForwardProc", TempForwardProc },
368 { "CommentClick", (XtActionProc) CommentClick },
369 { "GenericPopDown", (XtActionProc) GenericPopDown },
370 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
371 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
372 { "SelectMove", (XtActionProc) SelectMoveX },
373 { "LoadSelectedProc", LoadSelectedProc },
374 { "SetFilterProc", SetFilterProc },
375 { "TypeInProc", TypeInProc },
376 { "EnterKeyProc", EnterKeyProc },
377 { "UpKeyProc", UpKeyProc },
378 { "DownKeyProc", DownKeyProc },
379 { "WheelProc", WheelProc },
380 { "TabProc", TabProc },
383 char globalTranslations[] =
384 ":Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
385 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
386 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
387 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
388 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
389 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
390 :<Key>Pause: MenuItem(Mode.Pause) \n \
391 :Ctrl<Key>d: MenuItem(DebugProc) \n \
392 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
393 :<Key>Left: MenuItem(Edit.Backward) \n \
394 :<Key>Right: MenuItem(Edit.Forward) \n \
395 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
396 #ifndef OPTIONSDIALOG
398 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
399 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
400 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
401 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
402 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
405 :<KeyDown>Return: TempBackwardProc() \n \
406 :<KeyUp>Return: TempForwardProc() \n";
408 char ICSInputTranslations[] =
409 "<Key>Up: UpKeyProc() \n "
410 "<Key>Down: DownKeyProc() \n "
411 "<Key>Return: EnterKeyProc() \n";
413 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
414 // as the widget is destroyed before the up-click can call extend-end
415 char commentTranslations[] = "<Btn3Down>: extend-end(PRIMARY) select-start() CommentClick() \n";
417 String xboardResources[] = {
418 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
423 /* Max possible square size */
424 #define MAXSQSIZE 256
426 /* Arrange to catch delete-window events */
427 Atom wm_delete_window;
429 CatchDeleteWindow (Widget w, String procname)
432 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
433 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
434 XtAugmentTranslations(w, XtParseTranslationTable(buf));
441 XtSetArg(args[0], XtNiconic, False);
442 XtSetValues(shellWidget, args, 1);
444 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
447 //---------------------------------------------------------------------------------------------------------
448 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
451 #define CW_USEDEFAULT (1<<31)
452 #define ICS_TEXT_MENU_SIZE 90
453 #define DEBUG_FILE "xboard.debug"
454 #define SetCurrentDirectory chdir
455 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
459 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
462 // front-end part of option handling
464 // [HGM] This platform-dependent table provides the location for storing the color info
465 extern char *crWhite, * crBlack;
469 &appData.whitePieceColor,
470 &appData.blackPieceColor,
471 &appData.lightSquareColor,
472 &appData.darkSquareColor,
473 &appData.highlightSquareColor,
474 &appData.premoveHighlightColor,
475 &appData.lowTimeWarningColor,
486 // [HGM] font: keep a font for each square size, even non-stndard ones
489 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
490 char *fontTable[NUM_FONTS][MAX_SIZE];
493 ParseFont (char *name, int number)
494 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
496 if(sscanf(name, "size%d:", &size)) {
497 // [HGM] font: font is meant for specific boardSize (likely from settings file);
498 // defer processing it until we know if it matches our board size
499 if(strstr(name, "-*-") && // only pay attention to things that look like X-fonts
500 size >= 0 && size<MAX_SIZE) { // for now, fixed limit
501 fontTable[number][size] = strdup(strchr(name, ':')+1);
502 fontValid[number][size] = True;
507 case 0: // CLOCK_FONT
508 appData.clockFont = strdup(name);
510 case 1: // MESSAGE_FONT
511 appData.font = strdup(name);
513 case 2: // COORD_FONT
514 appData.coordFont = strdup(name);
519 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
524 { // only 2 fonts currently
525 appData.clockFont = CLOCK_FONT_NAME;
526 appData.coordFont = COORD_FONT_NAME;
527 appData.font = DEFAULT_FONT_NAME;
532 { // no-op, until we identify the code for this already in XBoard and move it here
536 ParseColor (int n, char *name)
537 { // in XBoard, just copy the color-name string
538 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
544 return *(char**)colorVariable[n];
548 ParseTextAttribs (ColorClass cc, char *s)
550 (&appData.colorShout)[cc] = strdup(s);
554 ParseBoardSize (void *addr, char *name)
556 appData.boardSize = strdup(name);
561 { // In XBoard the sound-playing program takes care of obtaining the actual sound
565 SetCommPortDefaults ()
566 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
569 // [HGM] args: these three cases taken out to stay in front-end
571 SaveFontArg (FILE *f, ArgDescriptor *ad)
574 int i, n = (int)(intptr_t)ad->argLoc;
576 case 0: // CLOCK_FONT
577 name = appData.clockFont;
579 case 1: // MESSAGE_FONT
582 case 2: // COORD_FONT
583 name = appData.coordFont;
588 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
589 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
590 fontTable[n][squareSize] = strdup(name);
591 fontValid[n][squareSize] = True;
594 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
595 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
600 { // nothing to do, as the sounds are at all times represented by their text-string names already
604 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
605 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
606 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
610 SaveColor (FILE *f, ArgDescriptor *ad)
611 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
612 if(colorVariable[(int)(intptr_t)ad->argLoc])
613 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
617 SaveBoardSize (FILE *f, char *name, void *addr)
618 { // wrapper to shield back-end from BoardSize & sizeInfo
619 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
623 ParseCommPortSettings (char *s)
624 { // no such option in XBoard (yet)
630 GetActualPlacement (Widget wg, WindowPlacement *wp)
632 XWindowAttributes winAt;
639 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
640 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
641 wp->x = rx - winAt.x;
642 wp->y = ry - winAt.y;
643 wp->height = winAt.height;
644 wp->width = winAt.width;
645 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
649 GetPlacement (DialogClass dlg, WindowPlacement *wp)
650 { // wrapper to shield back-end from widget type
651 if(shellUp[dlg]) GetActualPlacement(shells[dlg], wp);
656 { // wrapper to shield use of window handles from back-end (make addressible by number?)
657 // In XBoard this will have to wait until awareness of window parameters is implemented
658 GetActualPlacement(shellWidget, &wpMain);
659 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
660 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
661 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
662 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
663 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
664 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
668 PrintCommPortSettings (FILE *f, char *name)
669 { // This option does not exist in XBoard
673 EnsureOnScreen (int *x, int *y, int minX, int minY)
680 { // [HGM] args: allows testing if main window is realized from back-end
681 return xBoardWindow != 0;
685 PopUpStartupDialog ()
686 { // start menu not implemented in XBoard
690 ConvertToLine (int argc, char **argv)
692 static char line[128*1024], buf[1024];
696 for(i=1; i<argc; i++)
698 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
699 && argv[i][0] != '{' )
700 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
702 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
703 strncat(line, buf, 128*1024 - strlen(line) - 1 );
706 line[strlen(line)-1] = NULLCHAR;
710 //--------------------------------------------------------------------------------------------
713 ResizeBoardWindow (int w, int h, int inhibit)
715 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
717 shellArgs[0].value = w;
718 shellArgs[1].value = h;
719 shellArgs[4].value = shellArgs[2].value = w;
720 shellArgs[5].value = shellArgs[3].value = h;
721 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
723 XSync(xDisplay, False);
727 MakeOneColor (char *name, Pixel *color)
730 if (!appData.monoMode) {
731 vFrom.addr = (caddr_t) name;
732 vFrom.size = strlen(name);
733 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
734 if (vTo.addr == NULL) {
735 appData.monoMode = True;
738 *color = *(Pixel *) vTo.addr;
746 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
747 int forceMono = False;
749 if (appData.lowTimeWarning)
750 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
751 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
752 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
758 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
759 { // detervtomine what fonts to use, and create them
763 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
764 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
765 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
766 appData.font = fontTable[MESSAGE_FONT][squareSize];
767 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
768 appData.coordFont = fontTable[COORD_FONT][squareSize];
771 appData.font = InsertPxlSize(appData.font, fontPxlSize);
772 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
773 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
774 fontSet = CreateFontSet(appData.font);
775 clockFontSet = CreateFontSet(appData.clockFont);
777 /* For the coordFont, use the 0th font of the fontset. */
778 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
779 XFontStruct **font_struct_list;
780 XFontSetExtents *fontSize;
781 char **font_name_list;
782 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
783 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
784 coordFontStruct = XQueryFont(xDisplay, coordFontID);
785 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
786 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
789 appData.font = FindFont(appData.font, fontPxlSize);
790 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
791 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
792 clockFontID = XLoadFont(xDisplay, appData.clockFont);
793 clockFontStruct = XQueryFont(xDisplay, clockFontID);
794 coordFontID = XLoadFont(xDisplay, appData.coordFont);
795 coordFontStruct = XQueryFont(xDisplay, coordFontID);
796 // textHeight in !NLS mode!
798 countFontID = coordFontID; // [HGM] holdings
799 countFontStruct = coordFontStruct;
801 xdb = XtDatabase(xDisplay);
803 XrmPutLineResource(&xdb, "*international: True");
804 vTo.size = sizeof(XFontSet);
805 vTo.addr = (XtPointer) &fontSet;
806 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
808 XrmPutStringResource(&xdb, "*font", appData.font);
818 case ArgInt: p = " N"; break;
819 case ArgString: p = " STR"; break;
820 case ArgBoolean: p = " TF"; break;
821 case ArgSettingsFilename:
822 case ArgBackupSettingsFile:
823 case ArgFilename: p = " FILE"; break;
824 case ArgX: p = " Nx"; break;
825 case ArgY: p = " Ny"; break;
826 case ArgAttribs: p = " TEXTCOL"; break;
827 case ArgColor: p = " COL"; break;
828 case ArgFont: p = " FONT"; break;
829 case ArgBoardSize: p = " SIZE"; break;
830 case ArgFloat: p = " FLOAT"; break;
835 case ArgCommSettings:
844 GenerateGlobalTranslationTable (void)
846 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
852 output[0] = strdup(""); // build keystrokes with and wo mod keys separately
853 output[1] = strdup(""); // so the more specific can preceed the other
855 /* loop over all menu entries */
856 for( i=0; menuBar[i].mi ; i++)
859 for(j=0; mi[j].proc; j++)
867 char *key,*test, *mods;
869 /* check for Ctrl/Alt */
870 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
871 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
872 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
874 /* remove all <...> */
875 test = strrchr(mi[j].accel, '>');
877 key = strdup(mi[j].accel);
879 key = strdup(++test); // remove ">"
881 /* instead of shift X11 uses the uppercase letter directly*/
882 if (shift && strlen(key)==1 )
884 *key = toupper(*key);
888 /* handle some special cases which have different names in X11 */
889 if ( strncmp(key, "Page_Down", 9) == 0 )
894 else if ( strncmp(key, "Page_Up", 7) == 0 )
900 /* create string of mods */
902 mods = strdup("Ctrl ");
908 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
909 strncat(mods, "Meta ", 5);
914 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
915 strncat(mods, "Shift ", 6);
918 // remove trailing space
919 if( isspace(mods[strlen(mods)-1]) )
920 mods[strlen(mods)-1]='\0';
922 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
923 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
924 char *name = malloc(namesize+1);
925 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
927 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
928 char *buffer = malloc(buffersize+1);
929 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
931 /* add string to the output */
932 output[shift|alt|ctrl] = realloc(output[shift|alt|ctrl], strlen(output[shift|alt|ctrl]) + strlen(buffer)+1);
933 strncat(output[shift|alt|ctrl], buffer, strlen(buffer));
943 output[1] = realloc(output[1], strlen(output[1]) + strlen(output[0])+1);
944 strncat(output[1], output[0], strlen(output[0]));
955 ArgDescriptor *q, *p = argDescriptors+5;
956 printf("\nXBoard accepts the following options:\n"
957 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
958 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
959 " SIZE = board-size spec(s)\n"
960 " Within parentheses are short forms, or options to set to true or false.\n"
961 " Persistent options (saved in the settings file) are marked with *)\n\n");
963 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
964 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
965 if(p->save) strcat(buf+len, "*");
966 for(q=p+1; q->argLoc == p->argLoc; q++) {
967 if(q->argName[0] == '-') continue;
968 strcat(buf+len, q == p+1 ? " (" : " ");
969 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
971 if(q != p+1) strcat(buf+len, ")");
973 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
976 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
980 SlaveResize (Option *opt)
985 main (int argc, char **argv)
987 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
988 XSetWindowAttributes window_attributes;
990 Dimension boardWidth, boardHeight, w, h;
992 int forceMono = False;
994 srandom(time(0)); // [HGM] book: make random truly random
996 setbuf(stdout, NULL);
997 setbuf(stderr, NULL);
1000 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1001 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1005 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1010 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1011 typedef struct {char *name, *value; } Config;
1012 static Config configList[] = {
1013 { "Datadir", DATADIR },
1014 { "Sysconfdir", SYSCONFDIR },
1019 for(i=0; configList[i].name; i++) {
1020 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1021 if(argc > 2) printf("%s", configList[i].value);
1022 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1027 programName = strrchr(argv[0], '/');
1028 if (programName == NULL)
1029 programName = argv[0];
1034 XtSetLanguageProc(NULL, NULL, NULL);
1035 if (appData.debugMode) {
1036 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1039 bindtextdomain(PACKAGE, LOCALEDIR);
1040 textdomain(PACKAGE);
1043 appData.boardSize = "";
1044 InitAppData(ConvertToLine(argc, argv));
1046 if (p == NULL) p = "/tmp";
1047 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1048 gameCopyFilename = (char*) malloc(i);
1049 gamePasteFilename = (char*) malloc(i);
1050 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1051 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1053 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1054 static char buf[MSG_SIZ];
1055 EscapeExpand(buf, appData.firstInitString);
1056 appData.firstInitString = strdup(buf);
1057 EscapeExpand(buf, appData.secondInitString);
1058 appData.secondInitString = strdup(buf);
1059 EscapeExpand(buf, appData.firstComputerString);
1060 appData.firstComputerString = strdup(buf);
1061 EscapeExpand(buf, appData.secondComputerString);
1062 appData.secondComputerString = strdup(buf);
1065 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1068 if (chdir(chessDir) != 0) {
1069 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1075 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1076 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1077 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1078 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1081 setbuf(debugFP, NULL);
1084 /* [HGM,HR] make sure board size is acceptable */
1085 if(appData.NrFiles > BOARD_FILES ||
1086 appData.NrRanks > BOARD_RANKS )
1087 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1090 /* This feature does not work; animation needs a rewrite */
1091 appData.highlightDragging = FALSE;
1095 gameInfo.variant = StringToVariant(appData.variant);
1096 InitPosition(FALSE);
1099 XtAppInitialize(&appContext, "XBoard", shellOptions,
1100 XtNumber(shellOptions),
1101 &argc, argv, xboardResources, NULL, 0);
1103 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1104 clientResources, XtNumber(clientResources),
1107 xDisplay = XtDisplay(shellWidget);
1108 xScreen = DefaultScreen(xDisplay);
1109 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1112 * determine size, based on supplied or remembered -size, or screen size
1114 if (isdigit(appData.boardSize[0])) {
1115 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1116 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1117 &fontPxlSize, &smallLayout, &tinyLayout);
1119 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1120 programName, appData.boardSize);
1124 squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
1126 /* Find some defaults; use the nearest known size */
1127 SizeDefaults *szd, *nearest;
1128 int distance = 99999;
1129 nearest = szd = sizeDefaults;
1130 while (szd->name != NULL) {
1131 if (abs(szd->squareSize - squareSize) < distance) {
1133 distance = abs(szd->squareSize - squareSize);
1134 if (distance == 0) break;
1138 if (i < 2) lineGap = nearest->lineGap;
1139 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1140 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1141 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1142 if (i < 6) smallLayout = nearest->smallLayout;
1143 if (i < 7) tinyLayout = nearest->tinyLayout;
1146 SizeDefaults *szd = sizeDefaults;
1147 if (*appData.boardSize == NULLCHAR) {
1148 while (DisplayWidth(xDisplay, xScreen) < (szd->minScreenSize*BOARD_WIDTH + 4)/8 ||
1149 DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
1152 if (szd->name == NULL) szd--;
1153 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1155 while (szd->name != NULL &&
1156 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1157 if (szd->name == NULL) {
1158 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1159 programName, appData.boardSize);
1163 squareSize = szd->squareSize;
1164 lineGap = szd->lineGap;
1165 clockFontPxlSize = szd->clockFontPxlSize;
1166 coordFontPxlSize = szd->coordFontPxlSize;
1167 fontPxlSize = szd->fontPxlSize;
1168 smallLayout = szd->smallLayout;
1169 tinyLayout = szd->tinyLayout;
1170 // [HGM] font: use defaults from settings file if available and not overruled
1173 defaultLineGap = lineGap;
1174 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1176 /* [HR] height treated separately (hacked) */
1177 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1178 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1181 * Determine what fonts to use.
1183 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1186 * Detect if there are not enough colors available and adapt.
1188 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1189 appData.monoMode = True;
1192 forceMono = MakeColors();
1195 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1197 appData.monoMode = True;
1200 if (appData.monoMode && appData.debugMode) {
1201 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1202 (unsigned long) XWhitePixel(xDisplay, xScreen),
1203 (unsigned long) XBlackPixel(xDisplay, xScreen));
1206 ParseIcsTextColors();
1208 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1214 layoutName = "tinyLayout";
1215 } else if (smallLayout) {
1216 layoutName = "smallLayout";
1218 layoutName = "normalLayout";
1221 optList = BoardPopUp(squareSize, lineGap, (void*)
1227 InitDrawingHandle(optList + W_BOARD);
1228 currBoard = &optList[W_BOARD];
1229 boardWidget = optList[W_BOARD].handle;
1230 menuBarWidget = optList[W_MENU].handle;
1231 dropMenu = optList[W_DROP].handle;
1232 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1233 formWidget = XtParent(boardWidget);
1234 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1235 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1236 XtGetValues(optList[W_WHITE].handle, args, 2);
1237 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1238 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1239 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1240 XtGetValues(optList[W_PAUSE].handle, args, 2);
1243 xBoardWindow = XtWindow(boardWidget);
1245 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1246 // not need to go into InitDrawingSizes().
1249 * Create X checkmark bitmap and initialize option menu checks.
1251 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1252 checkmark_bits, checkmark_width, checkmark_height);
1258 ReadBitmap(&wIconPixmap, "icon_white.bm",
1259 icon_white_bits, icon_white_width, icon_white_height);
1260 ReadBitmap(&bIconPixmap, "icon_black.bm",
1261 icon_black_bits, icon_black_width, icon_black_height);
1262 iconPixmap = wIconPixmap;
1264 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1265 XtSetValues(shellWidget, args, i);
1268 * Create a cursor for the board widget.
1270 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1271 XChangeWindowAttributes(xDisplay, xBoardWindow,
1272 CWCursor, &window_attributes);
1275 * Inhibit shell resizing.
1277 shellArgs[0].value = (XtArgVal) &w;
1278 shellArgs[1].value = (XtArgVal) &h;
1279 XtGetValues(shellWidget, shellArgs, 2);
1280 shellArgs[4].value = shellArgs[2].value = w;
1281 shellArgs[5].value = shellArgs[3].value = h;
1282 // XtSetValues(shellWidget, &shellArgs[2], 4);
1283 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1284 marginH = h - boardHeight;
1286 CatchDeleteWindow(shellWidget, "QuitProc");
1291 if(appData.logoSize)
1292 { // locate and read user logo
1294 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1295 ASSIGN(userLogo, buf);
1298 if (appData.animate || appData.animateDragging)
1302 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1304 XtAugmentTranslations(formWidget,
1305 XtParseTranslationTable(globalTranslations));
1306 XtAugmentTranslations(formWidget,
1307 XtParseTranslationTable(TranslationsTableMenus));
1309 XtAddEventHandler(formWidget, KeyPressMask, False,
1310 (XtEventHandler) MoveTypeInProc, NULL);
1311 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1312 (XtEventHandler) EventProc, NULL);
1314 /* [AS] Restore layout */
1315 if( wpMoveHistory.visible ) {
1319 if( wpEvalGraph.visible )
1324 if( wpEngineOutput.visible ) {
1325 EngineOutputPopUp();
1328 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1333 if (errorExitStatus == -1) {
1334 if (appData.icsActive) {
1335 /* We now wait until we see "login:" from the ICS before
1336 sending the logon script (problems with timestamp otherwise) */
1337 /*ICSInitScript();*/
1338 if (appData.icsInputBox) ICSInputBoxPopUp();
1342 signal(SIGWINCH, TermSizeSigHandler);
1344 signal(SIGINT, IntSigHandler);
1345 signal(SIGTERM, IntSigHandler);
1346 if (*appData.cmailGameName != NULLCHAR) {
1347 signal(SIGUSR1, CmailSigHandler);
1352 // XtSetKeyboardFocus(shellWidget, formWidget);
1353 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1355 XtAppMainLoop(appContext);
1356 if (appData.debugMode) fclose(debugFP); // [DM] debug
1364 while((m = XtAppPending(appContext))) XtAppProcessEvent(appContext, m);
1368 TermSizeSigHandler (int sig)
1374 IntSigHandler (int sig)
1380 CmailSigHandler (int sig)
1385 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1387 /* Activate call-back function CmailSigHandlerCallBack() */
1388 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1390 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1394 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1397 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1399 /**** end signal code ****/
1402 #define Abs(n) ((n)<0 ? -(n) : (n))
1406 InsertPxlSize (char *pattern, int targetPxlSize)
1408 char *base_fnt_lst, strInt[12], *p, *q;
1409 int alternatives, i, len, strIntLen;
1412 * Replace the "*" (if present) in the pixel-size slot of each
1413 * alternative with the targetPxlSize.
1417 while ((p = strchr(p, ',')) != NULL) {
1421 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1422 strIntLen = strlen(strInt);
1423 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1427 while (alternatives--) {
1428 char *comma = strchr(p, ',');
1429 for (i=0; i<14; i++) {
1430 char *hyphen = strchr(p, '-');
1432 if (comma && hyphen > comma) break;
1433 len = hyphen + 1 - p;
1434 if (i == 7 && *p == '*' && len == 2) {
1436 memcpy(q, strInt, strIntLen);
1446 len = comma + 1 - p;
1453 return base_fnt_lst;
1457 CreateFontSet (char *base_fnt_lst)
1460 char **missing_list;
1464 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1465 &missing_list, &missing_count, &def_string);
1466 if (appData.debugMode) {
1468 XFontStruct **font_struct_list;
1469 char **font_name_list;
1470 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1472 fprintf(debugFP, " got list %s, locale %s\n",
1473 XBaseFontNameListOfFontSet(fntSet),
1474 XLocaleOfFontSet(fntSet));
1475 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1476 for (i = 0; i < count; i++) {
1477 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1480 for (i = 0; i < missing_count; i++) {
1481 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1484 if (fntSet == NULL) {
1485 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1490 #else // not ENABLE_NLS
1492 * Find a font that matches "pattern" that is as close as
1493 * possible to the targetPxlSize. Prefer fonts that are k
1494 * pixels smaller to fonts that are k pixels larger. The
1495 * pattern must be in the X Consortium standard format,
1496 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1497 * The return value should be freed with XtFree when no
1501 FindFont (char *pattern, int targetPxlSize)
1503 char **fonts, *p, *best, *scalable, *scalableTail;
1504 int i, j, nfonts, minerr, err, pxlSize;
1506 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1508 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1509 programName, pattern);
1516 for (i=0; i<nfonts; i++) {
1519 if (*p != '-') continue;
1521 if (*p == NULLCHAR) break;
1522 if (*p++ == '-') j++;
1524 if (j < 7) continue;
1527 scalable = fonts[i];
1530 err = pxlSize - targetPxlSize;
1531 if (Abs(err) < Abs(minerr) ||
1532 (minerr > 0 && err < 0 && -err == minerr)) {
1538 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1539 /* If the error is too big and there is a scalable font,
1540 use the scalable font. */
1541 int headlen = scalableTail - scalable;
1542 p = (char *) XtMalloc(strlen(scalable) + 10);
1543 while (isdigit(*scalableTail)) scalableTail++;
1544 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1546 p = (char *) XtMalloc(strlen(best) + 2);
1547 safeStrCpy(p, best, strlen(best)+1 );
1549 if (appData.debugMode) {
1550 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1551 pattern, targetPxlSize, p);
1553 XFreeFontNames(fonts);
1559 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1562 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1568 MarkMenuItem (char *menuRef, int state)
1570 MenuItem *item = MenuNameToItem(menuRef);
1574 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1575 XtSetValues(item->handle, args, 1);
1580 EnableNamedMenuItem (char *menuRef, int state)
1582 MenuItem *item = MenuNameToItem(menuRef);
1584 if(item) XtSetSensitive(item->handle, state);
1588 EnableButtonBar (int state)
1590 XtSetSensitive(optList[W_BUTTON].handle, state);
1595 SetMenuEnables (Enables *enab)
1597 while (enab->name != NULL) {
1598 EnableNamedMenuItem(enab->name, enab->value);
1604 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1605 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1607 if(*nprms == 0) return;
1608 item = MenuNameToItem(prms[0]);
1609 if(item) ((MenuProc *) item->proc) ();
1621 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1622 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1623 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1624 dmEnables[i].piece);
1625 XtSetSensitive(entry, p != NULL || !appData.testLegality
1626 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1627 && !appData.icsActive));
1629 while (p && *p++ == dmEnables[i].piece) count++;
1630 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1632 XtSetArg(args[j], XtNlabel, label); j++;
1633 XtSetValues(entry, args, j);
1638 do_flash_delay (unsigned long msec)
1644 FlashDelay (int flash_delay)
1646 XSync(xDisplay, False);
1647 if(flash_delay) do_flash_delay(flash_delay);
1651 Fraction (int x, int start, int stop)
1653 double f = ((double) x - start)/(stop - start);
1654 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1658 static WindowPlacement wpNew;
1661 CoDrag (Widget sh, WindowPlacement *wp)
1664 int j=0, touch=0, fudge = 2;
1665 GetActualPlacement(sh, wp);
1666 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1667 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1668 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1669 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1670 if(!touch ) return; // only windows that touch co-move
1671 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1672 int heightInc = wpNew.height - wpMain.height;
1673 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1674 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1675 wp->y += fracTop * heightInc;
1676 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1677 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1678 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1679 int widthInc = wpNew.width - wpMain.width;
1680 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1681 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1682 wp->y += fracLeft * widthInc;
1683 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1684 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1686 wp->x += wpNew.x - wpMain.x;
1687 wp->y += wpNew.y - wpMain.y;
1688 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1689 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1690 XtSetArg(args[j], XtNx, wp->x); j++;
1691 XtSetArg(args[j], XtNy, wp->y); j++;
1692 XtSetValues(sh, args, j);
1696 ReSize (WindowPlacement *wp)
1699 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1700 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1701 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1702 if(sqy < sqx) sqx = sqy;
1703 if(sqx != squareSize) {
1704 squareSize = sqx; // adopt new square size
1705 CreatePNGPieces(); // make newly scaled pieces
1706 InitDrawingSizes(0, 0); // creates grid etc.
1707 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1708 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1709 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1710 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1711 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1714 static XtIntervalId delayedDragID = 0;
1723 GetActualPlacement(shellWidget, &wpNew);
1724 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1725 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1726 busy = 0; return; // false alarm
1729 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1730 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1731 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1732 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1734 DrawPosition(True, NULL);
1735 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1743 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1745 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1749 EventProc (Widget widget, caddr_t unused, XEvent *event)
1751 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1752 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1756 * event handler for redrawing the board
1759 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1761 DrawPosition(True, NULL);
1766 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1767 { // [HGM] pv: walk PV
1768 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1771 extern int savedIndex; /* gross that this is global */
1774 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1777 XawTextPosition index, dummy;
1780 XawTextGetSelectionPos(w, &index, &dummy);
1781 XtSetArg(arg, XtNstring, &val);
1782 XtGetValues(w, &arg, 1);
1783 ReplaceComment(savedIndex, val);
1784 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1785 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1789 /* Disable all user input other than deleting the window */
1790 static int frozen = 0;
1796 /* Grab by a widget that doesn't accept input */
1797 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1801 /* Undo a FreezeUI */
1805 if (!frozen) return;
1806 XtRemoveGrab(optList[W_MESSG].handle);
1814 static int oldPausing = FALSE;
1815 static GameMode oldmode = (GameMode) -1;
1818 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1820 if (pausing != oldPausing) {
1821 oldPausing = pausing;
1822 MarkMenuItem("Mode.Pause", pausing);
1824 if (appData.showButtonBar) {
1825 /* Always toggle, don't set. Previous code messes up when
1826 invoked while the button is pressed, as releasing it
1827 toggles the state again. */
1830 XtSetArg(args[0], XtNbackground, &oldbg);
1831 XtSetArg(args[1], XtNforeground, &oldfg);
1832 XtGetValues(optList[W_PAUSE].handle,
1834 XtSetArg(args[0], XtNbackground, oldfg);
1835 XtSetArg(args[1], XtNforeground, oldbg);
1837 XtSetValues(optList[W_PAUSE].handle, args, 2);
1841 wname = ModeToWidgetName(oldmode);
1842 if (wname != NULL) {
1843 MarkMenuItem(wname, False);
1845 wname = ModeToWidgetName(gameMode);
1846 if (wname != NULL) {
1847 MarkMenuItem(wname, True);
1850 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1852 /* Maybe all the enables should be handled here, not just this one */
1853 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1855 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1860 * Button/menu procedures
1863 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1864 char *selected_fen_position=NULL;
1867 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1868 Atom *type_return, XtPointer *value_return,
1869 unsigned long *length_return, int *format_return)
1871 char *selection_tmp;
1873 // if (!selected_fen_position) return False; /* should never happen */
1874 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1875 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1876 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1879 if (f == NULL) return False;
1883 selection_tmp = XtMalloc(len + 1);
1884 count = fread(selection_tmp, 1, len, f);
1887 XtFree(selection_tmp);
1890 selection_tmp[len] = NULLCHAR;
1892 /* note: since no XtSelectionDoneProc was registered, Xt will
1893 * automatically call XtFree on the value returned. So have to
1894 * make a copy of it allocated with XtMalloc */
1895 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1896 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1899 *value_return=selection_tmp;
1900 *length_return=strlen(selection_tmp);
1901 *type_return=*target;
1902 *format_return = 8; /* bits per byte */
1904 } else if (*target == XA_TARGETS(xDisplay)) {
1905 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1906 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1907 targets_tmp[1] = XA_STRING;
1908 *value_return = targets_tmp;
1909 *type_return = XA_ATOM;
1912 // This code leads to a read of value_return out of bounds on 64-bit systems.
1913 // Other code which I have seen always sets *format_return to 32 independent of
1914 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1915 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1916 *format_return = 8 * sizeof(Atom);
1917 if (*format_return > 32) {
1918 *length_return *= *format_return / 32;
1919 *format_return = 32;
1922 *format_return = 32;
1930 /* note: when called from menu all parameters are NULL, so no clue what the
1931 * Widget which was clicked on was, or what the click event was
1934 CopySomething (char *src)
1936 selected_fen_position = src;
1938 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1939 * have a notion of a position that is selected but not copied.
1940 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1942 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1944 SendPositionSelection,
1945 NULL/* lose_ownership_proc */ ,
1946 NULL/* transfer_done_proc */);
1947 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1949 SendPositionSelection,
1950 NULL/* lose_ownership_proc */ ,
1951 NULL/* transfer_done_proc */);
1954 /* function called when the data to Paste is ready */
1956 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1957 Atom *type, XtPointer value, unsigned long *len, int *format)
1960 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1961 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1962 EditPositionPasteFEN(fenstr);
1966 /* called when Paste Position button is pressed,
1967 * all parameters will be NULL */
1969 PastePositionProc ()
1971 XtGetSelectionValue(menuBarWidget,
1972 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1973 /* (XtSelectionCallbackProc) */ PastePositionCB,
1974 NULL, /* client_data passed to PastePositionCB */
1976 /* better to use the time field from the event that triggered the
1977 * call to this function, but that isn't trivial to get
1984 /* note: when called from menu all parameters are NULL, so no clue what the
1985 * Widget which was clicked on was, or what the click event was
1987 /* function called when the data to Paste is ready */
1989 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1990 Atom *type, XtPointer value, unsigned long *len, int *format)
1993 if (value == NULL || *len == 0) {
1994 return; /* nothing had been selected to copy */
1996 f = fopen(gamePasteFilename, "w");
1998 DisplayError(_("Can't open temp file"), errno);
2001 fwrite(value, 1, *len, f);
2004 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2007 /* called when Paste Game button is pressed,
2008 * all parameters will be NULL */
2012 XtGetSelectionValue(menuBarWidget,
2013 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2014 /* (XtSelectionCallbackProc) */ PasteGameCB,
2015 NULL, /* client_data passed to PasteGameCB */
2017 /* better to use the time field from the event that triggered the
2018 * call to this function, but that isn't trivial to get
2027 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2034 { // bassic primitive for determining if modifier keys are pressed
2035 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2038 XQueryKeymap(xDisplay,keys);
2039 for(i=0; i<6; i++) {
2041 j = XKeysymToKeycode(xDisplay, codes[i]);
2042 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2048 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2052 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2053 if ( n == 1 && *buf >= 32 // printable
2054 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2055 ) BoxAutoPopUp (buf);
2059 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2060 { // [HGM] input: let up-arrow recall previous line from history
2065 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2066 { // [HGM] input: let down-arrow recall next line from history
2071 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2077 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2079 if (!TempBackwardActive) {
2080 TempBackwardActive = True;
2086 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2088 /* Check to see if triggered by a key release event for a repeating key.
2089 * If so the next queued event will be a key press of the same key at the same time */
2090 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2092 XPeekEvent(xDisplay, &next);
2093 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2094 next.xkey.keycode == event->xkey.keycode)
2098 TempBackwardActive = False;
2102 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2103 { // called as key binding
2106 if (nprms && *nprms > 0)
2110 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2116 { // called from menu
2117 ManInner(NULL, NULL, NULL, NULL);
2121 SetWindowTitle (char *text, char *title, char *icon)
2125 if (appData.titleInWindow) {
2127 XtSetArg(args[i], XtNlabel, text); i++;
2128 XtSetValues(titleWidget, args, i);
2131 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2132 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2133 XtSetValues(shellWidget, args, i);
2134 XSync(xDisplay, False);
2139 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2145 DisplayIcsInteractionTitle (String message)
2147 if (oldICSInteractionTitle == NULL) {
2148 /* Magic to find the old window title, adapted from vim */
2149 char *wina = getenv("WINDOWID");
2151 Window win = (Window) atoi(wina);
2152 Window root, parent, *children;
2153 unsigned int nchildren;
2154 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2156 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2157 if (!XQueryTree(xDisplay, win, &root, &parent,
2158 &children, &nchildren)) break;
2159 if (children) XFree((void *)children);
2160 if (parent == root || parent == 0) break;
2163 XSetErrorHandler(oldHandler);
2165 if (oldICSInteractionTitle == NULL) {
2166 oldICSInteractionTitle = "xterm";
2169 printf("\033]0;%s\007", message);
2174 XtIntervalId delayedEventTimerXID = 0;
2175 DelayedEventCallback delayedEventCallback = 0;
2180 delayedEventTimerXID = 0;
2181 delayedEventCallback();
2185 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2187 if(delayedEventTimerXID && delayedEventCallback == cb)
2188 // [HGM] alive: replace, rather than add or flush identical event
2189 XtRemoveTimeOut(delayedEventTimerXID);
2190 delayedEventCallback = cb;
2191 delayedEventTimerXID =
2192 XtAppAddTimeOut(appContext, millisec,
2193 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2196 DelayedEventCallback
2199 if (delayedEventTimerXID) {
2200 return delayedEventCallback;
2207 CancelDelayedEvent ()
2209 if (delayedEventTimerXID) {
2210 XtRemoveTimeOut(delayedEventTimerXID);
2211 delayedEventTimerXID = 0;
2215 XtIntervalId loadGameTimerXID = 0;
2218 LoadGameTimerRunning ()
2220 return loadGameTimerXID != 0;
2224 StopLoadGameTimer ()
2226 if (loadGameTimerXID != 0) {
2227 XtRemoveTimeOut(loadGameTimerXID);
2228 loadGameTimerXID = 0;
2236 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2238 loadGameTimerXID = 0;
2243 StartLoadGameTimer (long millisec)
2246 XtAppAddTimeOut(appContext, millisec,
2247 (XtTimerCallbackProc) LoadGameTimerCallback,
2251 XtIntervalId analysisClockXID = 0;
2254 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2256 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2257 || appData.icsEngineAnalyze) { // [DM]
2258 AnalysisPeriodicEvent(0);
2259 StartAnalysisClock();
2264 StartAnalysisClock ()
2267 XtAppAddTimeOut(appContext, 2000,
2268 (XtTimerCallbackProc) AnalysisClockCallback,
2272 XtIntervalId clockTimerXID = 0;
2275 ClockTimerRunning ()
2277 return clockTimerXID != 0;
2283 if (clockTimerXID != 0) {
2284 XtRemoveTimeOut(clockTimerXID);
2293 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2300 StartClockTimer (long millisec)
2303 XtAppAddTimeOut(appContext, millisec,
2304 (XtTimerCallbackProc) ClockTimerCallback,
2309 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2313 Widget w = (Widget) opt->handle;
2315 /* check for low time warning */
2316 Pixel foregroundOrWarningColor = timerForegroundPixel;
2319 appData.lowTimeWarning &&
2320 (timer / 1000) < appData.icsAlarmTime)
2321 foregroundOrWarningColor = lowTimeWarningColor;
2323 if (appData.clockMode) {
2324 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2325 XtSetArg(args[0], XtNlabel, buf);
2327 snprintf(buf, MSG_SIZ, "%s ", color);
2328 XtSetArg(args[0], XtNlabel, buf);
2333 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2334 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2336 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2337 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2340 XtSetValues(w, args, 3);
2343 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2346 SetClockIcon (int color)
2349 Pixmap pm = *clockIcons[color];
2350 if (iconPixmap != pm) {
2352 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2353 XtSetValues(shellWidget, args, 1);
2357 #define INPUT_SOURCE_BUF_SIZE 8192
2366 char buf[INPUT_SOURCE_BUF_SIZE];
2371 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2373 InputSource *is = (InputSource *) closure;
2378 if (is->lineByLine) {
2379 count = read(is->fd, is->unused,
2380 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2382 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2385 is->unused += count;
2387 while (p < is->unused) {
2388 q = memchr(p, '\n', is->unused - p);
2389 if (q == NULL) break;
2391 (is->func)(is, is->closure, p, q - p, 0);
2395 while (p < is->unused) {
2400 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2405 (is->func)(is, is->closure, is->buf, count, error);
2410 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2413 ChildProc *cp = (ChildProc *) pr;
2415 is = (InputSource *) calloc(1, sizeof(InputSource));
2416 is->lineByLine = lineByLine;
2420 is->fd = fileno(stdin);
2422 is->kind = cp->kind;
2423 is->fd = cp->fdFrom;
2426 is->unused = is->buf;
2429 is->xid = XtAppAddInput(appContext, is->fd,
2430 (XtPointer) (XtInputReadMask),
2431 (XtInputCallbackProc) DoInputCallback,
2433 is->closure = closure;
2434 return (InputSourceRef) is;
2438 RemoveInputSource (InputSourceRef isr)
2440 InputSource *is = (InputSource *) isr;
2442 if (is->xid == 0) return;
2443 XtRemoveInput(is->xid);
2449 static Boolean frameWaiting;
2452 FrameAlarm (int sig)
2454 frameWaiting = False;
2455 /* In case System-V style signals. Needed?? */
2456 signal(SIGALRM, FrameAlarm);
2460 FrameDelay (int time)
2462 struct itimerval delay;
2464 XSync(xDisplay, False);
2467 frameWaiting = True;
2468 signal(SIGALRM, FrameAlarm);
2469 delay.it_interval.tv_sec =
2470 delay.it_value.tv_sec = time / 1000;
2471 delay.it_interval.tv_usec =
2472 delay.it_value.tv_usec = (time % 1000) * 1000;
2473 setitimer(ITIMER_REAL, &delay, NULL);
2474 while (frameWaiting) pause();
2475 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2476 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2477 setitimer(ITIMER_REAL, &delay, NULL);
2484 FrameDelay (int time)
2486 XSync(xDisplay, False);
2488 usleep(time * 1000);
2494 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2496 char buf[MSG_SIZ], *logoName = buf;
2497 if(appData.logo[n][0]) {
2498 logoName = appData.logo[n];
2499 } else if(appData.autoLogo) {
2500 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2501 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2502 } else if(appData.directory[n] && appData.directory[n][0]) {
2503 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2507 { ASSIGN(cps->programLogo, logoName); }
2511 UpdateLogos (int displ)
2513 if(optList[W_WHITE-1].handle == NULL) return;
2514 LoadLogo(&first, 0, 0);
2515 LoadLogo(&second, 1, appData.icsActive);
2516 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);