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] && *name == '#') *(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-n].mi || !n++; i++)
858 mi = menuBar[i+n].mi; // kludge to access 'noMenu' behind sentinel
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 char *name = malloc(MSG_SIZ);
924 if(n) snprintf(name, MSG_SIZ, "%s", mi[j].ref);
925 else snprintf(name, MSG_SIZ, "%s.%s", menuBar[i].ref, mi[j].ref);
927 char *buffer = malloc(MSG_SIZ);
928 snprintf(buffer, MSG_SIZ, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
930 /* add string to the output */
931 output[shift|alt|ctrl] = realloc(output[shift|alt|ctrl], strlen(output[shift|alt|ctrl]) + strlen(buffer)+1);
932 strncat(output[shift|alt|ctrl], buffer, strlen(buffer));
942 output[1] = realloc(output[1], strlen(output[1]) + strlen(output[0])+1);
943 strncat(output[1], output[0], strlen(output[0]));
954 ArgDescriptor *q, *p = argDescriptors+5;
955 printf("\nXBoard accepts the following options:\n"
956 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
957 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
958 " SIZE = board-size spec(s)\n"
959 " Within parentheses are short forms, or options to set to true or false.\n"
960 " Persistent options (saved in the settings file) are marked with *)\n\n");
962 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
963 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
964 if(p->save) strcat(buf+len, "*");
965 for(q=p+1; q->argLoc == p->argLoc; q++) {
966 if(q->argName[0] == '-') continue;
967 strcat(buf+len, q == p+1 ? " (" : " ");
968 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
970 if(q != p+1) strcat(buf+len, ")");
972 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
975 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
979 SlaveResize (Option *opt)
984 main (int argc, char **argv)
986 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
987 XSetWindowAttributes window_attributes;
989 Dimension boardWidth, boardHeight, w, h;
991 int forceMono = False;
993 extern Option chatOptions[]; // FIXME: adapt Chat window, removing ICS pane and Hide button
994 chatOptions[6].type = chatOptions[10].type = Skip;
996 srandom(time(0)); // [HGM] book: make random truly random
998 setbuf(stdout, NULL);
999 setbuf(stderr, NULL);
1002 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1003 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1007 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1012 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1013 typedef struct {char *name, *value; } Config;
1014 static Config configList[] = {
1015 { "Datadir", DATADIR },
1016 { "Sysconfdir", SYSCONFDIR },
1021 for(i=0; configList[i].name; i++) {
1022 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1023 if(argc > 2) printf("%s", configList[i].value);
1024 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1029 programName = strrchr(argv[0], '/');
1030 if (programName == NULL)
1031 programName = argv[0];
1036 XtSetLanguageProc(NULL, NULL, NULL);
1037 if (appData.debugMode) {
1038 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1041 bindtextdomain(PACKAGE, LOCALEDIR);
1042 textdomain(PACKAGE);
1045 appData.boardSize = "";
1046 InitAppData(ConvertToLine(argc, argv));
1048 if (p == NULL) p = "/tmp";
1049 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1050 gameCopyFilename = (char*) malloc(i);
1051 gamePasteFilename = (char*) malloc(i);
1052 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1053 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1055 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1056 static char buf[MSG_SIZ];
1057 EscapeExpand(buf, appData.firstInitString);
1058 appData.firstInitString = strdup(buf);
1059 EscapeExpand(buf, appData.secondInitString);
1060 appData.secondInitString = strdup(buf);
1061 EscapeExpand(buf, appData.firstComputerString);
1062 appData.firstComputerString = strdup(buf);
1063 EscapeExpand(buf, appData.secondComputerString);
1064 appData.secondComputerString = strdup(buf);
1067 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1070 if (chdir(chessDir) != 0) {
1071 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1077 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1078 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1079 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1080 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1083 setbuf(debugFP, NULL);
1086 /* [HGM,HR] make sure board size is acceptable */
1087 if(appData.NrFiles > BOARD_FILES ||
1088 appData.NrRanks > BOARD_RANKS )
1089 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1092 /* This feature does not work; animation needs a rewrite */
1093 appData.highlightDragging = FALSE;
1097 gameInfo.variant = StringToVariant(appData.variant);
1098 InitPosition(FALSE);
1101 XtAppInitialize(&appContext, "XBoard", shellOptions,
1102 XtNumber(shellOptions),
1103 &argc, argv, xboardResources, NULL, 0);
1105 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1106 clientResources, XtNumber(clientResources),
1109 xDisplay = XtDisplay(shellWidget);
1110 xScreen = DefaultScreen(xDisplay);
1111 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1114 * determine size, based on supplied or remembered -size, or screen size
1116 if (isdigit(appData.boardSize[0])) {
1117 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1118 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1119 &fontPxlSize, &smallLayout, &tinyLayout);
1121 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1122 programName, appData.boardSize);
1126 squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
1128 /* Find some defaults; use the nearest known size */
1129 SizeDefaults *szd, *nearest;
1130 int distance = 99999;
1131 nearest = szd = sizeDefaults;
1132 while (szd->name != NULL) {
1133 if (abs(szd->squareSize - squareSize) < distance) {
1135 distance = abs(szd->squareSize - squareSize);
1136 if (distance == 0) break;
1140 if (i < 2) lineGap = nearest->lineGap;
1141 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1142 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1143 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1144 if (i < 6) smallLayout = nearest->smallLayout;
1145 if (i < 7) tinyLayout = nearest->tinyLayout;
1148 SizeDefaults *szd = sizeDefaults;
1149 if (*appData.boardSize == NULLCHAR) {
1150 while (DisplayWidth(xDisplay, xScreen) < (szd->minScreenSize*BOARD_WIDTH + 4)/8 ||
1151 DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
1154 if (szd->name == NULL) szd--;
1155 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1157 while (szd->name != NULL &&
1158 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1159 if (szd->name == NULL) {
1160 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1161 programName, appData.boardSize);
1165 squareSize = szd->squareSize;
1166 lineGap = szd->lineGap;
1167 clockFontPxlSize = szd->clockFontPxlSize;
1168 coordFontPxlSize = szd->coordFontPxlSize;
1169 fontPxlSize = szd->fontPxlSize;
1170 smallLayout = szd->smallLayout;
1171 tinyLayout = szd->tinyLayout;
1172 // [HGM] font: use defaults from settings file if available and not overruled
1175 defaultLineGap = lineGap;
1176 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1178 /* [HR] height treated separately (hacked) */
1179 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1180 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1183 * Determine what fonts to use.
1185 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1188 * Detect if there are not enough colors available and adapt.
1190 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1191 appData.monoMode = True;
1194 forceMono = MakeColors();
1197 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1199 appData.monoMode = True;
1202 if (appData.monoMode && appData.debugMode) {
1203 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1204 (unsigned long) XWhitePixel(xDisplay, xScreen),
1205 (unsigned long) XBlackPixel(xDisplay, xScreen));
1208 ParseIcsTextColors();
1210 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1216 layoutName = "tinyLayout";
1217 } else if (smallLayout) {
1218 layoutName = "smallLayout";
1220 layoutName = "normalLayout";
1223 optList = BoardPopUp(squareSize, lineGap, (void*)
1229 InitDrawingHandle(optList + W_BOARD);
1230 currBoard = &optList[W_BOARD];
1231 boardWidget = optList[W_BOARD].handle;
1232 menuBarWidget = optList[W_MENU].handle;
1233 dropMenu = optList[W_DROP].handle;
1234 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1235 formWidget = XtParent(boardWidget);
1236 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1237 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1238 XtGetValues(optList[W_WHITE].handle, args, 2);
1239 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1240 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1241 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1242 XtGetValues(optList[W_PAUSE].handle, args, 2);
1245 xBoardWindow = XtWindow(boardWidget);
1247 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1248 // not need to go into InitDrawingSizes().
1251 * Create X checkmark bitmap and initialize option menu checks.
1253 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1254 checkmark_bits, checkmark_width, checkmark_height);
1260 ReadBitmap(&wIconPixmap, "icon_white.bm",
1261 icon_white_bits, icon_white_width, icon_white_height);
1262 ReadBitmap(&bIconPixmap, "icon_black.bm",
1263 icon_black_bits, icon_black_width, icon_black_height);
1264 iconPixmap = wIconPixmap;
1266 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1267 XtSetValues(shellWidget, args, i);
1270 * Create a cursor for the board widget.
1272 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1273 XChangeWindowAttributes(xDisplay, xBoardWindow,
1274 CWCursor, &window_attributes);
1277 * Inhibit shell resizing.
1279 shellArgs[0].value = (XtArgVal) &w;
1280 shellArgs[1].value = (XtArgVal) &h;
1281 XtGetValues(shellWidget, shellArgs, 2);
1282 shellArgs[4].value = shellArgs[2].value = w;
1283 shellArgs[5].value = shellArgs[3].value = h;
1284 // XtSetValues(shellWidget, &shellArgs[2], 4);
1285 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1286 marginH = h - boardHeight;
1288 CatchDeleteWindow(shellWidget, "QuitProc");
1293 if(appData.logoSize)
1294 { // locate and read user logo
1296 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1297 ASSIGN(userLogo, buf);
1300 if (appData.animate || appData.animateDragging)
1304 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1306 XtAugmentTranslations(formWidget,
1307 XtParseTranslationTable(globalTranslations));
1308 XtAugmentTranslations(formWidget,
1309 XtParseTranslationTable(TranslationsTableMenus));
1311 XtAddEventHandler(formWidget, KeyPressMask, False,
1312 (XtEventHandler) MoveTypeInProc, NULL);
1313 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1314 (XtEventHandler) EventProc, NULL);
1316 /* [AS] Restore layout */
1317 if( wpMoveHistory.visible ) {
1321 if( wpEvalGraph.visible )
1326 if( wpEngineOutput.visible ) {
1327 EngineOutputPopUp();
1330 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1335 if (errorExitStatus == -1) {
1336 if (appData.icsActive) {
1337 /* We now wait until we see "login:" from the ICS before
1338 sending the logon script (problems with timestamp otherwise) */
1339 /*ICSInitScript();*/
1340 if (appData.icsInputBox) ICSInputBoxPopUp();
1344 signal(SIGWINCH, TermSizeSigHandler);
1346 signal(SIGINT, IntSigHandler);
1347 signal(SIGTERM, IntSigHandler);
1348 if (*appData.cmailGameName != NULLCHAR) {
1349 signal(SIGUSR1, CmailSigHandler);
1354 // XtSetKeyboardFocus(shellWidget, formWidget);
1355 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1357 XtAppMainLoop(appContext);
1358 if (appData.debugMode) fclose(debugFP); // [DM] debug
1366 while((m = XtAppPending(appContext))) XtAppProcessEvent(appContext, m);
1370 TermSizeSigHandler (int sig)
1376 IntSigHandler (int sig)
1382 CmailSigHandler (int sig)
1387 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1389 /* Activate call-back function CmailSigHandlerCallBack() */
1390 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1392 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1396 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1399 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1401 /**** end signal code ****/
1404 #define Abs(n) ((n)<0 ? -(n) : (n))
1408 InsertPxlSize (char *pattern, int targetPxlSize)
1410 char *base_fnt_lst, strInt[12], *p, *q;
1411 int alternatives, i, len, strIntLen;
1414 * Replace the "*" (if present) in the pixel-size slot of each
1415 * alternative with the targetPxlSize.
1419 while ((p = strchr(p, ',')) != NULL) {
1423 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1424 strIntLen = strlen(strInt);
1425 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1429 while (alternatives--) {
1430 char *comma = strchr(p, ',');
1431 for (i=0; i<14; i++) {
1432 char *hyphen = strchr(p, '-');
1434 if (comma && hyphen > comma) break;
1435 len = hyphen + 1 - p;
1436 if (i == 7 && *p == '*' && len == 2) {
1438 memcpy(q, strInt, strIntLen);
1448 len = comma + 1 - p;
1455 return base_fnt_lst;
1459 CreateFontSet (char *base_fnt_lst)
1462 char **missing_list;
1466 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1467 &missing_list, &missing_count, &def_string);
1468 if (appData.debugMode) {
1470 XFontStruct **font_struct_list;
1471 char **font_name_list;
1472 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1474 fprintf(debugFP, " got list %s, locale %s\n",
1475 XBaseFontNameListOfFontSet(fntSet),
1476 XLocaleOfFontSet(fntSet));
1477 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1478 for (i = 0; i < count; i++) {
1479 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1482 for (i = 0; i < missing_count; i++) {
1483 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1486 if (fntSet == NULL) {
1487 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1492 #else // not ENABLE_NLS
1494 * Find a font that matches "pattern" that is as close as
1495 * possible to the targetPxlSize. Prefer fonts that are k
1496 * pixels smaller to fonts that are k pixels larger. The
1497 * pattern must be in the X Consortium standard format,
1498 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1499 * The return value should be freed with XtFree when no
1503 FindFont (char *pattern, int targetPxlSize)
1505 char **fonts, *p, *best, *scalable, *scalableTail;
1506 int i, j, nfonts, minerr, err, pxlSize;
1508 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1510 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1511 programName, pattern);
1518 for (i=0; i<nfonts; i++) {
1521 if (*p != '-') continue;
1523 if (*p == NULLCHAR) break;
1524 if (*p++ == '-') j++;
1526 if (j < 7) continue;
1529 scalable = fonts[i];
1532 err = pxlSize - targetPxlSize;
1533 if (Abs(err) < Abs(minerr) ||
1534 (minerr > 0 && err < 0 && -err == minerr)) {
1540 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1541 /* If the error is too big and there is a scalable font,
1542 use the scalable font. */
1543 int headlen = scalableTail - scalable;
1544 p = (char *) XtMalloc(strlen(scalable) + 10);
1545 while (isdigit(*scalableTail)) scalableTail++;
1546 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1548 p = (char *) XtMalloc(strlen(best) + 2);
1549 safeStrCpy(p, best, strlen(best)+1 );
1551 if (appData.debugMode) {
1552 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1553 pattern, targetPxlSize, p);
1555 XFreeFontNames(fonts);
1561 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1564 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1570 MarkMenuItem (char *menuRef, int state)
1572 MenuItem *item = MenuNameToItem(menuRef);
1576 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1577 XtSetValues(item->handle, args, 1);
1582 EnableNamedMenuItem (char *menuRef, int state)
1584 MenuItem *item = MenuNameToItem(menuRef);
1586 if(item) XtSetSensitive(item->handle, state);
1590 EnableButtonBar (int state)
1592 XtSetSensitive(optList[W_BUTTON].handle, state);
1597 SetMenuEnables (Enables *enab)
1599 while (enab->name != NULL) {
1600 EnableNamedMenuItem(enab->name, enab->value);
1606 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1607 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1609 if(*nprms == 0) return;
1610 item = MenuNameToItem(prms[0]);
1611 if(item) ((MenuProc *) item->proc) ();
1623 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1624 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1625 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1626 dmEnables[i].piece);
1627 XtSetSensitive(entry, p != NULL || !appData.testLegality
1628 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1629 && !appData.icsActive));
1631 while (p && *p++ == dmEnables[i].piece) count++;
1632 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1634 XtSetArg(args[j], XtNlabel, label); j++;
1635 XtSetValues(entry, args, j);
1640 do_flash_delay (unsigned long msec)
1646 FlashDelay (int flash_delay)
1648 XSync(xDisplay, False);
1649 if(flash_delay) do_flash_delay(flash_delay);
1653 Fraction (int x, int start, int stop)
1655 double f = ((double) x - start)/(stop - start);
1656 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1660 static WindowPlacement wpNew;
1663 CoDrag (Widget sh, WindowPlacement *wp)
1666 int j=0, touch=0, fudge = 2;
1667 GetActualPlacement(sh, wp);
1668 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1669 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1670 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1671 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1672 if(!touch ) return; // only windows that touch co-move
1673 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1674 int heightInc = wpNew.height - wpMain.height;
1675 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1676 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1677 wp->y += fracTop * heightInc;
1678 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1679 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1680 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1681 int widthInc = wpNew.width - wpMain.width;
1682 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1683 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1684 wp->y += fracLeft * widthInc;
1685 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1686 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1688 wp->x += wpNew.x - wpMain.x;
1689 wp->y += wpNew.y - wpMain.y;
1690 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1691 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1692 XtSetArg(args[j], XtNx, wp->x); j++;
1693 XtSetArg(args[j], XtNy, wp->y); j++;
1694 XtSetValues(sh, args, j);
1698 ReSize (WindowPlacement *wp)
1701 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1702 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1703 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1704 if(sqy < sqx) sqx = sqy;
1705 if(sqx != squareSize) {
1706 squareSize = sqx; // adopt new square size
1707 CreatePNGPieces(); // make newly scaled pieces
1708 InitDrawingSizes(0, 0); // creates grid etc.
1709 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1710 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1711 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1712 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1713 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1716 static XtIntervalId delayedDragID = 0;
1725 GetActualPlacement(shellWidget, &wpNew);
1726 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1727 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1728 busy = 0; return; // false alarm
1731 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1732 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1733 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1734 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1736 DrawPosition(True, NULL);
1737 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1745 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1747 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1751 EventProc (Widget widget, caddr_t unused, XEvent *event)
1753 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1754 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1758 * event handler for redrawing the board
1761 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1763 DrawPosition(True, NULL);
1768 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1769 { // [HGM] pv: walk PV
1770 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1773 extern int savedIndex; /* gross that this is global */
1776 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1779 XawTextPosition index, dummy;
1782 XawTextGetSelectionPos(w, &index, &dummy);
1783 XtSetArg(arg, XtNstring, &val);
1784 XtGetValues(w, &arg, 1);
1785 ReplaceComment(savedIndex, val);
1786 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1787 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1791 /* Disable all user input other than deleting the window */
1792 static int frozen = 0;
1798 /* Grab by a widget that doesn't accept input */
1799 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1803 /* Undo a FreezeUI */
1807 if (!frozen) return;
1808 XtRemoveGrab(optList[W_MESSG].handle);
1816 static int oldPausing = FALSE;
1817 static GameMode oldmode = (GameMode) -1;
1820 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1822 if (pausing != oldPausing) {
1823 oldPausing = pausing;
1824 MarkMenuItem("Mode.Pause", pausing);
1826 if (appData.showButtonBar) {
1827 /* Always toggle, don't set. Previous code messes up when
1828 invoked while the button is pressed, as releasing it
1829 toggles the state again. */
1832 XtSetArg(args[0], XtNbackground, &oldbg);
1833 XtSetArg(args[1], XtNforeground, &oldfg);
1834 XtGetValues(optList[W_PAUSE].handle,
1836 XtSetArg(args[0], XtNbackground, oldfg);
1837 XtSetArg(args[1], XtNforeground, oldbg);
1839 XtSetValues(optList[W_PAUSE].handle, args, 2);
1843 wname = ModeToWidgetName(oldmode);
1844 if (wname != NULL) {
1845 MarkMenuItem(wname, False);
1847 wname = ModeToWidgetName(gameMode);
1848 if (wname != NULL) {
1849 MarkMenuItem(wname, True);
1852 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1854 /* Maybe all the enables should be handled here, not just this one */
1855 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1857 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1862 * Button/menu procedures
1865 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1866 char *selected_fen_position=NULL;
1869 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1870 Atom *type_return, XtPointer *value_return,
1871 unsigned long *length_return, int *format_return)
1873 char *selection_tmp;
1875 // if (!selected_fen_position) return False; /* should never happen */
1876 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1877 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1878 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1881 if (f == NULL) return False;
1885 selection_tmp = XtMalloc(len + 1);
1886 count = fread(selection_tmp, 1, len, f);
1889 XtFree(selection_tmp);
1892 selection_tmp[len] = NULLCHAR;
1894 /* note: since no XtSelectionDoneProc was registered, Xt will
1895 * automatically call XtFree on the value returned. So have to
1896 * make a copy of it allocated with XtMalloc */
1897 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1898 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1901 *value_return=selection_tmp;
1902 *length_return=strlen(selection_tmp);
1903 *type_return=*target;
1904 *format_return = 8; /* bits per byte */
1906 } else if (*target == XA_TARGETS(xDisplay)) {
1907 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1908 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1909 targets_tmp[1] = XA_STRING;
1910 *value_return = targets_tmp;
1911 *type_return = XA_ATOM;
1914 // This code leads to a read of value_return out of bounds on 64-bit systems.
1915 // Other code which I have seen always sets *format_return to 32 independent of
1916 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1917 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1918 *format_return = 8 * sizeof(Atom);
1919 if (*format_return > 32) {
1920 *length_return *= *format_return / 32;
1921 *format_return = 32;
1924 *format_return = 32;
1932 /* note: when called from menu all parameters are NULL, so no clue what the
1933 * Widget which was clicked on was, or what the click event was
1936 CopySomething (char *src)
1938 selected_fen_position = src;
1940 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1941 * have a notion of a position that is selected but not copied.
1942 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1944 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1946 SendPositionSelection,
1947 NULL/* lose_ownership_proc */ ,
1948 NULL/* transfer_done_proc */);
1949 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1951 SendPositionSelection,
1952 NULL/* lose_ownership_proc */ ,
1953 NULL/* transfer_done_proc */);
1956 /* function called when the data to Paste is ready */
1958 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1959 Atom *type, XtPointer value, unsigned long *len, int *format)
1962 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1963 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1964 EditPositionPasteFEN(fenstr);
1968 /* called when Paste Position button is pressed,
1969 * all parameters will be NULL */
1971 PastePositionProc ()
1973 XtGetSelectionValue(menuBarWidget,
1974 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1975 /* (XtSelectionCallbackProc) */ PastePositionCB,
1976 NULL, /* client_data passed to PastePositionCB */
1978 /* better to use the time field from the event that triggered the
1979 * call to this function, but that isn't trivial to get
1986 /* note: when called from menu all parameters are NULL, so no clue what the
1987 * Widget which was clicked on was, or what the click event was
1989 /* function called when the data to Paste is ready */
1991 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1992 Atom *type, XtPointer value, unsigned long *len, int *format)
1995 if (value == NULL || *len == 0) {
1996 return; /* nothing had been selected to copy */
1998 f = fopen(gamePasteFilename, "w");
2000 DisplayError(_("Can't open temp file"), errno);
2003 fwrite(value, 1, *len, f);
2006 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2009 /* called when Paste Game button is pressed,
2010 * all parameters will be NULL */
2014 XtGetSelectionValue(menuBarWidget,
2015 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2016 /* (XtSelectionCallbackProc) */ PasteGameCB,
2017 NULL, /* client_data passed to PasteGameCB */
2019 /* better to use the time field from the event that triggered the
2020 * call to this function, but that isn't trivial to get
2029 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2036 { // bassic primitive for determining if modifier keys are pressed
2037 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2040 XQueryKeymap(xDisplay,keys);
2041 for(i=0; i<6; i++) {
2043 j = XKeysymToKeycode(xDisplay, codes[i]);
2044 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2050 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2054 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2055 if ( n == 1 && *buf >= 32 // printable
2056 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2057 ) BoxAutoPopUp (buf);
2061 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2062 { // [HGM] input: let up-arrow recall previous line from history
2067 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2068 { // [HGM] input: let down-arrow recall next line from history
2073 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2079 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2081 if (!TempBackwardActive) {
2082 TempBackwardActive = True;
2088 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2090 /* Check to see if triggered by a key release event for a repeating key.
2091 * If so the next queued event will be a key press of the same key at the same time */
2092 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2094 XPeekEvent(xDisplay, &next);
2095 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2096 next.xkey.keycode == event->xkey.keycode)
2100 TempBackwardActive = False;
2104 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2105 { // called as key binding
2108 if (nprms && *nprms > 0)
2112 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2118 { // called from menu
2119 ManInner(NULL, NULL, NULL, NULL);
2123 SetWindowTitle (char *text, char *title, char *icon)
2127 if (appData.titleInWindow) {
2129 XtSetArg(args[i], XtNlabel, text); i++;
2130 XtSetValues(titleWidget, args, i);
2133 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2134 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2135 XtSetValues(shellWidget, args, i);
2136 XSync(xDisplay, False);
2141 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2147 DisplayIcsInteractionTitle (String message)
2149 if (oldICSInteractionTitle == NULL) {
2150 /* Magic to find the old window title, adapted from vim */
2151 char *wina = getenv("WINDOWID");
2153 Window win = (Window) atoi(wina);
2154 Window root, parent, *children;
2155 unsigned int nchildren;
2156 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2158 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2159 if (!XQueryTree(xDisplay, win, &root, &parent,
2160 &children, &nchildren)) break;
2161 if (children) XFree((void *)children);
2162 if (parent == root || parent == 0) break;
2165 XSetErrorHandler(oldHandler);
2167 if (oldICSInteractionTitle == NULL) {
2168 oldICSInteractionTitle = "xterm";
2171 printf("\033]0;%s\007", message);
2176 XtIntervalId delayedEventTimerXID = 0;
2177 DelayedEventCallback delayedEventCallback = 0;
2182 delayedEventTimerXID = 0;
2183 delayedEventCallback();
2187 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2189 if(delayedEventTimerXID && delayedEventCallback == cb)
2190 // [HGM] alive: replace, rather than add or flush identical event
2191 XtRemoveTimeOut(delayedEventTimerXID);
2192 delayedEventCallback = cb;
2193 delayedEventTimerXID =
2194 XtAppAddTimeOut(appContext, millisec,
2195 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2198 DelayedEventCallback
2201 if (delayedEventTimerXID) {
2202 return delayedEventCallback;
2209 CancelDelayedEvent ()
2211 if (delayedEventTimerXID) {
2212 XtRemoveTimeOut(delayedEventTimerXID);
2213 delayedEventTimerXID = 0;
2217 XtIntervalId loadGameTimerXID = 0;
2220 LoadGameTimerRunning ()
2222 return loadGameTimerXID != 0;
2226 StopLoadGameTimer ()
2228 if (loadGameTimerXID != 0) {
2229 XtRemoveTimeOut(loadGameTimerXID);
2230 loadGameTimerXID = 0;
2238 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2240 loadGameTimerXID = 0;
2245 StartLoadGameTimer (long millisec)
2248 XtAppAddTimeOut(appContext, millisec,
2249 (XtTimerCallbackProc) LoadGameTimerCallback,
2253 XtIntervalId analysisClockXID = 0;
2256 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2258 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2259 || appData.icsEngineAnalyze) { // [DM]
2260 AnalysisPeriodicEvent(0);
2261 StartAnalysisClock();
2266 StartAnalysisClock ()
2269 XtAppAddTimeOut(appContext, 2000,
2270 (XtTimerCallbackProc) AnalysisClockCallback,
2274 XtIntervalId clockTimerXID = 0;
2277 ClockTimerRunning ()
2279 return clockTimerXID != 0;
2285 if (clockTimerXID != 0) {
2286 XtRemoveTimeOut(clockTimerXID);
2295 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2302 StartClockTimer (long millisec)
2305 XtAppAddTimeOut(appContext, millisec,
2306 (XtTimerCallbackProc) ClockTimerCallback,
2311 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2315 Widget w = (Widget) opt->handle;
2317 /* check for low time warning */
2318 Pixel foregroundOrWarningColor = timerForegroundPixel;
2321 appData.lowTimeWarning &&
2322 (timer / 1000) < appData.icsAlarmTime)
2323 foregroundOrWarningColor = lowTimeWarningColor;
2325 if (appData.clockMode) {
2326 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2327 XtSetArg(args[0], XtNlabel, buf);
2329 snprintf(buf, MSG_SIZ, "%s ", color);
2330 XtSetArg(args[0], XtNlabel, buf);
2335 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2336 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2338 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2339 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2342 XtSetValues(w, args, 3);
2345 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2348 SetClockIcon (int color)
2351 Pixmap pm = *clockIcons[color];
2352 if (iconPixmap != pm) {
2354 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2355 XtSetValues(shellWidget, args, 1);
2359 #define INPUT_SOURCE_BUF_SIZE 8192
2368 char buf[INPUT_SOURCE_BUF_SIZE];
2373 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2375 InputSource *is = (InputSource *) closure;
2380 if (is->lineByLine) {
2381 count = read(is->fd, is->unused,
2382 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2384 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2387 is->unused += count;
2389 while (p < is->unused) {
2390 q = memchr(p, '\n', is->unused - p);
2391 if (q == NULL) break;
2393 (is->func)(is, is->closure, p, q - p, 0);
2397 while (p < is->unused) {
2402 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2407 (is->func)(is, is->closure, is->buf, count, error);
2412 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2415 ChildProc *cp = (ChildProc *) pr;
2417 is = (InputSource *) calloc(1, sizeof(InputSource));
2418 is->lineByLine = lineByLine;
2422 is->fd = fileno(stdin);
2424 is->kind = cp->kind;
2425 is->fd = cp->fdFrom;
2428 is->unused = is->buf;
2431 is->xid = XtAppAddInput(appContext, is->fd,
2432 (XtPointer) (XtInputReadMask),
2433 (XtInputCallbackProc) DoInputCallback,
2435 is->closure = closure;
2436 return (InputSourceRef) is;
2440 RemoveInputSource (InputSourceRef isr)
2442 InputSource *is = (InputSource *) isr;
2444 if (is->xid == 0) return;
2445 XtRemoveInput(is->xid);
2451 static Boolean frameWaiting;
2454 FrameAlarm (int sig)
2456 frameWaiting = False;
2457 /* In case System-V style signals. Needed?? */
2458 signal(SIGALRM, FrameAlarm);
2462 FrameDelay (int time)
2464 struct itimerval delay;
2466 XSync(xDisplay, False);
2469 frameWaiting = True;
2470 signal(SIGALRM, FrameAlarm);
2471 delay.it_interval.tv_sec =
2472 delay.it_value.tv_sec = time / 1000;
2473 delay.it_interval.tv_usec =
2474 delay.it_value.tv_usec = (time % 1000) * 1000;
2475 setitimer(ITIMER_REAL, &delay, NULL);
2476 while (frameWaiting) pause();
2477 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2478 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2479 setitimer(ITIMER_REAL, &delay, NULL);
2486 FrameDelay (int time)
2488 XSync(xDisplay, False);
2490 usleep(time * 1000);
2496 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2498 char buf[MSG_SIZ], *logoName = buf;
2499 if(appData.logo[n][0]) {
2500 logoName = appData.logo[n];
2501 } else if(appData.autoLogo) {
2502 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2503 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2504 } else if(appData.logoDir && appData.logoDir[0]) {
2505 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2509 { ASSIGN(cps->programLogo, logoName); }
2513 UpdateLogos (int displ)
2515 if(optList[W_WHITE-1].handle == NULL) return;
2516 LoadLogo(&first, 0, 0);
2517 LoadLogo(&second, 1, appData.icsActive);
2518 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);