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"
213 #define usleep(t) _sleep2(((t)+500)/1000)
217 # define _(s) gettext (s)
218 # define N_(s) gettext_noop (s)
224 int main P((int argc, char **argv));
225 RETSIGTYPE CmailSigHandler P((int sig));
226 RETSIGTYPE IntSigHandler P((int sig));
227 RETSIGTYPE TermSizeSigHandler P((int sig));
228 Widget CreateMenuBar P((Menu *mb, int boardWidth));
230 char *InsertPxlSize P((char *pattern, int targetPxlSize));
231 XFontSet CreateFontSet P((char *base_fnt_lst));
233 char *FindFont P((char *pattern, int targetPxlSize));
235 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
236 u_int wreq, u_int hreq));
237 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
238 void DelayedDrag P((void));
239 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
240 void HandlePV P((Widget w, XEvent * event,
241 String * params, Cardinal * nParams));
242 void DrawPositionProc P((Widget w, XEvent *event,
243 String *prms, Cardinal *nprms));
244 void CommentClick P((Widget w, XEvent * event,
245 String * params, Cardinal * nParams));
246 void ICSInputBoxPopUp P((void));
247 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
248 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
249 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
250 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
251 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
252 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
253 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
254 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
255 Boolean TempBackwardActive = False;
256 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
257 void DisplayMove P((int moveNumber));
258 void update_ics_width P(());
259 int CopyMemoProc P(());
262 * XBoard depends on Xt R4 or higher
264 int xtVersion = XtSpecificationRelease;
269 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
270 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
271 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
272 Option *optList; // contains all widgets of main window
274 XFontSet fontSet, clockFontSet;
277 XFontStruct *clockFontStruct;
279 Font coordFontID, countFontID;
280 XFontStruct *coordFontStruct, *countFontStruct;
281 XtAppContext appContext;
284 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
286 Position commentX = -1, commentY = -1;
287 Dimension commentW, commentH;
288 typedef unsigned int BoardSize;
290 Boolean chessProgram;
292 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
293 int smallLayout = 0, tinyLayout = 0,
294 marginW, marginH, // [HGM] for run-time resizing
295 fromX = -1, fromY = -1, toX, toY, commentUp = False,
296 errorExitStatus = -1, defaultLineGap;
297 Dimension textHeight;
298 Pixel timerForegroundPixel, timerBackgroundPixel;
299 Pixel buttonForegroundPixel, buttonBackgroundPixel;
300 char *chessDir, *programName, *programVersion;
301 Boolean alwaysOnTop = False;
302 char *icsTextMenuString;
304 char *firstChessProgramNames;
305 char *secondChessProgramNames;
307 WindowPlacement wpMain;
308 WindowPlacement wpConsole;
309 WindowPlacement wpComment;
310 WindowPlacement wpMoveHistory;
311 WindowPlacement wpEvalGraph;
312 WindowPlacement wpEngineOutput;
313 WindowPlacement wpGameList;
314 WindowPlacement wpTags;
315 WindowPlacement wpDualBoard;
318 /* This magic number is the number of intermediate frames used
319 in each half of the animation. For short moves it's reduced
320 by 1. The total number of frames will be factor * 2 + 1. */
323 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
330 DropMenuEnables dmEnables[] = {
347 XtResource clientResources[] = {
348 { "flashCount", "flashCount", XtRInt, sizeof(int),
349 XtOffset(AppDataPtr, flashCount), XtRImmediate,
350 (XtPointer) FLASH_COUNT },
353 XrmOptionDescRec shellOptions[] = {
354 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
355 { "-flash", "flashCount", XrmoptionNoArg, "3" },
356 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
359 XtActionsRec boardActions[] = {
360 { "DrawPosition", DrawPositionProc },
361 { "HandlePV", HandlePV },
362 { "SelectPV", SelectPV },
363 { "StopPV", StopPV },
364 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
365 { "QuitProc", QuitWrapper },
366 { "ManProc", ManInner },
367 { "TempBackwardProc", TempBackwardProc },
368 { "TempForwardProc", TempForwardProc },
369 { "CommentClick", (XtActionProc) CommentClick },
370 { "GenericPopDown", (XtActionProc) GenericPopDown },
371 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
372 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
373 { "SelectMove", (XtActionProc) SelectMoveX },
374 { "LoadSelectedProc", LoadSelectedProc },
375 { "SetFilterProc", SetFilterProc },
376 { "TypeInProc", TypeInProc },
377 { "EnterKeyProc", EnterKeyProc },
378 { "UpKeyProc", UpKeyProc },
379 { "DownKeyProc", DownKeyProc },
380 { "WheelProc", WheelProc },
381 { "TabProc", TabProc },
384 char globalTranslations[] =
385 ":Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
386 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
387 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
388 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
389 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
390 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
391 :<Key>Pause: MenuItem(Mode.Pause) \n \
392 :Ctrl<Key>d: MenuItem(DebugProc) \n \
393 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
394 :<Key>Left: MenuItem(Edit.Backward) \n \
395 :<Key>Right: MenuItem(Edit.Forward) \n \
396 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
397 #ifndef OPTIONSDIALOG
399 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
400 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
401 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
402 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
403 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
406 :<KeyDown>Return: TempBackwardProc() \n \
407 :<KeyUp>Return: TempForwardProc() \n";
409 char ICSInputTranslations[] =
410 "<Key>Up: UpKeyProc() \n "
411 "<Key>Down: DownKeyProc() \n "
412 "<Key>Return: EnterKeyProc() \n";
414 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
415 // as the widget is destroyed before the up-click can call extend-end
416 char commentTranslations[] = "<Btn3Down>: extend-end(PRIMARY) select-start() CommentClick() \n";
418 String xboardResources[] = {
419 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
424 /* Max possible square size */
425 #define MAXSQSIZE 256
427 /* Arrange to catch delete-window events */
428 Atom wm_delete_window;
430 CatchDeleteWindow (Widget w, String procname)
433 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
434 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
435 XtAugmentTranslations(w, XtParseTranslationTable(buf));
442 XtSetArg(args[0], XtNiconic, False);
443 XtSetValues(shellWidget, args, 1);
445 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
448 //---------------------------------------------------------------------------------------------------------
449 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
452 #define CW_USEDEFAULT (1<<31)
453 #define ICS_TEXT_MENU_SIZE 90
454 #define DEBUG_FILE "xboard.debug"
455 #define SetCurrentDirectory chdir
456 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
460 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
463 // front-end part of option handling
465 // [HGM] This platform-dependent table provides the location for storing the color info
466 extern char *crWhite, * crBlack;
470 &appData.whitePieceColor,
471 &appData.blackPieceColor,
472 &appData.lightSquareColor,
473 &appData.darkSquareColor,
474 &appData.highlightSquareColor,
475 &appData.premoveHighlightColor,
476 &appData.lowTimeWarningColor,
487 // [HGM] font: keep a font for each square size, even non-stndard ones
490 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
491 char *fontTable[NUM_FONTS][MAX_SIZE];
494 ParseFont (char *name, int number)
495 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
497 if(sscanf(name, "size%d:", &size)) {
498 // [HGM] font: font is meant for specific boardSize (likely from settings file);
499 // defer processing it until we know if it matches our board size
500 if(strstr(name, "-*-") && // only pay attention to things that look like X-fonts
501 size >= 0 && size<MAX_SIZE) { // for now, fixed limit
502 fontTable[number][size] = strdup(strchr(name, ':')+1);
503 fontValid[number][size] = True;
508 case 0: // CLOCK_FONT
509 appData.clockFont = strdup(name);
511 case 1: // MESSAGE_FONT
512 appData.font = strdup(name);
514 case 2: // COORD_FONT
515 appData.coordFont = strdup(name);
520 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
525 { // only 2 fonts currently
526 appData.clockFont = CLOCK_FONT_NAME;
527 appData.coordFont = COORD_FONT_NAME;
528 appData.font = DEFAULT_FONT_NAME;
533 { // no-op, until we identify the code for this already in XBoard and move it here
537 ParseColor (int n, char *name)
538 { // in XBoard, just copy the color-name string
539 if(colorVariable[n] && *name == '#') *(char**)colorVariable[n] = strdup(name);
545 return *(char**)colorVariable[n];
549 ParseTextAttribs (ColorClass cc, char *s)
551 (&appData.colorShout)[cc] = strdup(s);
555 ParseBoardSize (void *addr, char *name)
557 appData.boardSize = strdup(name);
562 { // In XBoard the sound-playing program takes care of obtaining the actual sound
566 SetCommPortDefaults ()
567 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
570 // [HGM] args: these three cases taken out to stay in front-end
572 SaveFontArg (FILE *f, ArgDescriptor *ad)
575 int i, n = (int)(intptr_t)ad->argLoc;
577 case 0: // CLOCK_FONT
578 name = appData.clockFont;
580 case 1: // MESSAGE_FONT
583 case 2: // COORD_FONT
584 name = appData.coordFont;
589 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
590 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
591 fontTable[n][squareSize] = strdup(name);
592 fontValid[n][squareSize] = True;
595 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
596 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
601 { // nothing to do, as the sounds are at all times represented by their text-string names already
605 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
606 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
607 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
611 SaveColor (FILE *f, ArgDescriptor *ad)
612 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
613 if(colorVariable[(int)(intptr_t)ad->argLoc])
614 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
618 SaveBoardSize (FILE *f, char *name, void *addr)
619 { // wrapper to shield back-end from BoardSize & sizeInfo
620 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
624 ParseCommPortSettings (char *s)
625 { // no such option in XBoard (yet)
631 GetActualPlacement (Widget wg, WindowPlacement *wp)
633 XWindowAttributes winAt;
640 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
641 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
642 wp->x = rx - winAt.x;
643 wp->y = ry - winAt.y;
644 wp->height = winAt.height;
645 wp->width = winAt.width;
646 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
650 GetPlacement (DialogClass dlg, WindowPlacement *wp)
651 { // wrapper to shield back-end from widget type
652 if(shellUp[dlg]) GetActualPlacement(shells[dlg], wp);
657 { // wrapper to shield use of window handles from back-end (make addressible by number?)
658 // In XBoard this will have to wait until awareness of window parameters is implemented
659 GetActualPlacement(shellWidget, &wpMain);
660 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
661 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
662 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
663 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
664 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
665 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
669 PrintCommPortSettings (FILE *f, char *name)
670 { // This option does not exist in XBoard
674 EnsureOnScreen (int *x, int *y, int minX, int minY)
681 { // [HGM] args: allows testing if main window is realized from back-end
682 return xBoardWindow != 0;
686 PopUpStartupDialog ()
687 { // start menu not implemented in XBoard
691 ConvertToLine (int argc, char **argv)
693 static char line[128*1024], buf[1024];
697 for(i=1; i<argc; i++)
699 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
700 && argv[i][0] != '{' )
701 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
703 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
704 strncat(line, buf, 128*1024 - strlen(line) - 1 );
707 line[strlen(line)-1] = NULLCHAR;
711 //--------------------------------------------------------------------------------------------
714 ResizeBoardWindow (int w, int h, int inhibit)
716 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
718 shellArgs[0].value = w;
719 shellArgs[1].value = h;
720 shellArgs[4].value = shellArgs[2].value = w;
721 shellArgs[5].value = shellArgs[3].value = h;
722 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
724 XSync(xDisplay, False);
728 MakeOneColor (char *name, Pixel *color)
731 if (!appData.monoMode) {
732 vFrom.addr = (caddr_t) name;
733 vFrom.size = strlen(name);
734 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
735 if (vTo.addr == NULL) {
736 appData.monoMode = True;
739 *color = *(Pixel *) vTo.addr;
747 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
748 int forceMono = False;
750 if (appData.lowTimeWarning)
751 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
752 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
753 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
759 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
760 { // detervtomine what fonts to use, and create them
764 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
765 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
766 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
767 appData.font = fontTable[MESSAGE_FONT][squareSize];
768 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
769 appData.coordFont = fontTable[COORD_FONT][squareSize];
772 appData.font = InsertPxlSize(appData.font, fontPxlSize);
773 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
774 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
775 fontSet = CreateFontSet(appData.font);
776 clockFontSet = CreateFontSet(appData.clockFont);
778 /* For the coordFont, use the 0th font of the fontset. */
779 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
780 XFontStruct **font_struct_list;
781 XFontSetExtents *fontSize;
782 char **font_name_list;
783 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
784 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
785 coordFontStruct = XQueryFont(xDisplay, coordFontID);
786 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
787 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
790 appData.font = FindFont(appData.font, fontPxlSize);
791 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
792 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
793 clockFontID = XLoadFont(xDisplay, appData.clockFont);
794 clockFontStruct = XQueryFont(xDisplay, clockFontID);
795 coordFontID = XLoadFont(xDisplay, appData.coordFont);
796 coordFontStruct = XQueryFont(xDisplay, coordFontID);
797 // textHeight in !NLS mode!
799 countFontID = coordFontID; // [HGM] holdings
800 countFontStruct = coordFontStruct;
802 xdb = XtDatabase(xDisplay);
804 XrmPutLineResource(&xdb, "*international: True");
805 vTo.size = sizeof(XFontSet);
806 vTo.addr = (XtPointer) &fontSet;
807 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
809 XrmPutStringResource(&xdb, "*font", appData.font);
819 case ArgInt: p = " N"; break;
820 case ArgString: p = " STR"; break;
821 case ArgBoolean: p = " TF"; break;
822 case ArgSettingsFilename:
823 case ArgBackupSettingsFile:
824 case ArgFilename: p = " FILE"; break;
825 case ArgX: p = " Nx"; break;
826 case ArgY: p = " Ny"; break;
827 case ArgAttribs: p = " TEXTCOL"; break;
828 case ArgColor: p = " COL"; break;
829 case ArgFont: p = " FONT"; break;
830 case ArgBoardSize: p = " SIZE"; break;
831 case ArgFloat: p = " FLOAT"; break;
836 case ArgCommSettings:
845 GenerateGlobalTranslationTable (void)
847 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
853 output[0] = strdup(""); // build keystrokes with and wo mod keys separately
854 output[1] = strdup(""); // so the more specific can preceed the other
856 /* loop over all menu entries */
857 for( i=0; menuBar[i-n].mi || !n++; i++)
859 mi = menuBar[i+n].mi; // kludge to access 'noMenu' behind sentinel
860 for(j=0; mi[j].proc; j++)
868 char *key,*test, *mods;
870 /* check for Ctrl/Alt */
871 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
872 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
873 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
875 /* remove all <...> */
876 test = strrchr(mi[j].accel, '>');
878 key = strdup(mi[j].accel);
880 key = strdup(++test); // remove ">"
882 /* instead of shift X11 uses the uppercase letter directly*/
883 if (shift && strlen(key)==1 )
885 *key = toupper(*key);
889 /* handle some special cases which have different names in X11 */
890 if ( strncmp(key, "Page_Down", 9) == 0 )
895 else if ( strncmp(key, "Page_Up", 7) == 0 )
901 /* create string of mods */
903 mods = strdup("Ctrl ");
909 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
910 strncat(mods, "Meta ", 5);
915 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
916 strncat(mods, "Shift ", 6);
919 // remove trailing space
920 if( isspace(mods[strlen(mods)-1]) )
921 mods[strlen(mods)-1]='\0';
923 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
924 char *name = malloc(MSG_SIZ);
925 if(n) snprintf(name, MSG_SIZ, "%s", mi[j].ref);
926 else snprintf(name, MSG_SIZ, "%s.%s", menuBar[i].ref, mi[j].ref);
928 char *buffer = malloc(MSG_SIZ);
929 snprintf(buffer, MSG_SIZ, ":%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 extern Option chatOptions[]; // FIXME: adapt Chat window, removing ICS pane and Hide button
995 chatOptions[6].type = chatOptions[10].type = Skip;
997 srandom(time(0)); // [HGM] book: make random truly random
999 setbuf(stdout, NULL);
1000 setbuf(stderr, NULL);
1003 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1004 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1008 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1013 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1014 typedef struct {char *name, *value; } Config;
1015 static Config configList[] = {
1016 { "Datadir", DATADIR },
1017 { "Sysconfdir", SYSCONFDIR },
1022 for(i=0; configList[i].name; i++) {
1023 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1024 if(argc > 2) printf("%s", configList[i].value);
1025 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1030 programName = strrchr(argv[0], '/');
1031 if (programName == NULL)
1032 programName = argv[0];
1037 XtSetLanguageProc(NULL, NULL, NULL);
1038 if (appData.debugMode) {
1039 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1042 bindtextdomain(PACKAGE, LOCALEDIR);
1043 textdomain(PACKAGE);
1046 appData.boardSize = "";
1047 InitAppData(ConvertToLine(argc, argv));
1049 if (p == NULL) p = "/tmp";
1050 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1051 gameCopyFilename = (char*) malloc(i);
1052 gamePasteFilename = (char*) malloc(i);
1053 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1054 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1056 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1057 static char buf[MSG_SIZ];
1058 EscapeExpand(buf, appData.firstInitString);
1059 appData.firstInitString = strdup(buf);
1060 EscapeExpand(buf, appData.secondInitString);
1061 appData.secondInitString = strdup(buf);
1062 EscapeExpand(buf, appData.firstComputerString);
1063 appData.firstComputerString = strdup(buf);
1064 EscapeExpand(buf, appData.secondComputerString);
1065 appData.secondComputerString = strdup(buf);
1068 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1071 if (chdir(chessDir) != 0) {
1072 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1078 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1079 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1080 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1081 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1084 setbuf(debugFP, NULL);
1087 /* [HGM,HR] make sure board size is acceptable */
1088 if(appData.NrFiles > BOARD_FILES ||
1089 appData.NrRanks > BOARD_RANKS )
1090 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1093 /* This feature does not work; animation needs a rewrite */
1094 appData.highlightDragging = FALSE;
1098 gameInfo.variant = StringToVariant(appData.variant);
1099 InitPosition(FALSE);
1102 XtAppInitialize(&appContext, "XBoard", shellOptions,
1103 XtNumber(shellOptions),
1104 &argc, argv, xboardResources, NULL, 0);
1106 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1107 clientResources, XtNumber(clientResources),
1110 xDisplay = XtDisplay(shellWidget);
1111 xScreen = DefaultScreen(xDisplay);
1112 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1115 * determine size, based on supplied or remembered -size, or screen size
1117 if (isdigit(appData.boardSize[0])) {
1118 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1119 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1120 &fontPxlSize, &smallLayout, &tinyLayout);
1122 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1123 programName, appData.boardSize);
1127 squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
1129 /* Find some defaults; use the nearest known size */
1130 SizeDefaults *szd, *nearest;
1131 int distance = 99999;
1132 nearest = szd = sizeDefaults;
1133 while (szd->name != NULL) {
1134 if (abs(szd->squareSize - squareSize) < distance) {
1136 distance = abs(szd->squareSize - squareSize);
1137 if (distance == 0) break;
1141 if (i < 2) lineGap = nearest->lineGap;
1142 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1143 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1144 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1145 if (i < 6) smallLayout = nearest->smallLayout;
1146 if (i < 7) tinyLayout = nearest->tinyLayout;
1149 SizeDefaults *szd = sizeDefaults;
1150 if (*appData.boardSize == NULLCHAR) {
1151 while (DisplayWidth(xDisplay, xScreen) < (szd->minScreenSize*BOARD_WIDTH + 4)/8 ||
1152 DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
1155 if (szd->name == NULL) szd--;
1156 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1158 while (szd->name != NULL &&
1159 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1160 if (szd->name == NULL) {
1161 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1162 programName, appData.boardSize);
1166 squareSize = szd->squareSize;
1167 lineGap = szd->lineGap;
1168 clockFontPxlSize = szd->clockFontPxlSize;
1169 coordFontPxlSize = szd->coordFontPxlSize;
1170 fontPxlSize = szd->fontPxlSize;
1171 smallLayout = szd->smallLayout;
1172 tinyLayout = szd->tinyLayout;
1173 // [HGM] font: use defaults from settings file if available and not overruled
1176 defaultLineGap = lineGap;
1177 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1179 /* [HR] height treated separately (hacked) */
1180 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1181 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1184 * Determine what fonts to use.
1186 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1189 * Detect if there are not enough colors available and adapt.
1191 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1192 appData.monoMode = True;
1195 forceMono = MakeColors();
1198 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1200 appData.monoMode = True;
1203 if (appData.monoMode && appData.debugMode) {
1204 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1205 (unsigned long) XWhitePixel(xDisplay, xScreen),
1206 (unsigned long) XBlackPixel(xDisplay, xScreen));
1209 ParseIcsTextColors();
1211 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1217 layoutName = "tinyLayout";
1218 } else if (smallLayout) {
1219 layoutName = "smallLayout";
1221 layoutName = "normalLayout";
1224 optList = BoardPopUp(squareSize, lineGap, (void*)
1230 InitDrawingHandle(optList + W_BOARD);
1231 currBoard = &optList[W_BOARD];
1232 boardWidget = optList[W_BOARD].handle;
1233 menuBarWidget = optList[W_MENU].handle;
1234 dropMenu = optList[W_DROP].handle;
1235 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1236 formWidget = XtParent(boardWidget);
1237 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1238 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1239 XtGetValues(optList[W_WHITE].handle, args, 2);
1240 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1241 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1242 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1243 XtGetValues(optList[W_PAUSE].handle, args, 2);
1246 xBoardWindow = XtWindow(boardWidget);
1248 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1249 // not need to go into InitDrawingSizes().
1252 * Create X checkmark bitmap and initialize option menu checks.
1254 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1255 checkmark_bits, checkmark_width, checkmark_height);
1261 ReadBitmap(&wIconPixmap, "icon_white.bm",
1262 icon_white_bits, icon_white_width, icon_white_height);
1263 ReadBitmap(&bIconPixmap, "icon_black.bm",
1264 icon_black_bits, icon_black_width, icon_black_height);
1265 iconPixmap = wIconPixmap;
1267 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1268 XtSetValues(shellWidget, args, i);
1271 * Create a cursor for the board widget.
1273 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1274 XChangeWindowAttributes(xDisplay, xBoardWindow,
1275 CWCursor, &window_attributes);
1278 * Inhibit shell resizing.
1280 shellArgs[0].value = (XtArgVal) &w;
1281 shellArgs[1].value = (XtArgVal) &h;
1282 XtGetValues(shellWidget, shellArgs, 2);
1283 shellArgs[4].value = shellArgs[2].value = w;
1284 shellArgs[5].value = shellArgs[3].value = h;
1285 // XtSetValues(shellWidget, &shellArgs[2], 4);
1286 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1287 marginH = h - boardHeight;
1289 CatchDeleteWindow(shellWidget, "QuitProc");
1294 if(appData.logoSize)
1295 { // locate and read user logo
1297 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1298 ASSIGN(userLogo, buf);
1301 if (appData.animate || appData.animateDragging)
1305 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1307 XtAugmentTranslations(formWidget,
1308 XtParseTranslationTable(globalTranslations));
1309 XtAugmentTranslations(formWidget,
1310 XtParseTranslationTable(TranslationsTableMenus));
1312 XtAddEventHandler(formWidget, KeyPressMask, False,
1313 (XtEventHandler) MoveTypeInProc, NULL);
1314 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1315 (XtEventHandler) EventProc, NULL);
1317 /* [AS] Restore layout */
1318 if( wpMoveHistory.visible ) {
1322 if( wpEvalGraph.visible )
1327 if( wpEngineOutput.visible ) {
1328 EngineOutputPopUp();
1331 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1336 if (errorExitStatus == -1) {
1337 if (appData.icsActive) {
1338 /* We now wait until we see "login:" from the ICS before
1339 sending the logon script (problems with timestamp otherwise) */
1340 /*ICSInitScript();*/
1341 if (appData.icsInputBox) ICSInputBoxPopUp();
1345 signal(SIGWINCH, TermSizeSigHandler);
1347 signal(SIGINT, IntSigHandler);
1348 signal(SIGTERM, IntSigHandler);
1349 if (*appData.cmailGameName != NULLCHAR) {
1350 signal(SIGUSR1, CmailSigHandler);
1355 // XtSetKeyboardFocus(shellWidget, formWidget);
1356 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1358 XtAppMainLoop(appContext);
1359 if (appData.debugMode) fclose(debugFP); // [DM] debug
1367 while((m = XtAppPending(appContext))) XtAppProcessEvent(appContext, m);
1371 TermSizeSigHandler (int sig)
1377 IntSigHandler (int sig)
1383 CmailSigHandler (int sig)
1388 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1390 /* Activate call-back function CmailSigHandlerCallBack() */
1391 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1393 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1397 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1400 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1402 /**** end signal code ****/
1405 #define Abs(n) ((n)<0 ? -(n) : (n))
1409 InsertPxlSize (char *pattern, int targetPxlSize)
1411 char *base_fnt_lst, strInt[12], *p, *q;
1412 int alternatives, i, len, strIntLen;
1415 * Replace the "*" (if present) in the pixel-size slot of each
1416 * alternative with the targetPxlSize.
1420 while ((p = strchr(p, ',')) != NULL) {
1424 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1425 strIntLen = strlen(strInt);
1426 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1430 while (alternatives--) {
1431 char *comma = strchr(p, ',');
1432 for (i=0; i<14; i++) {
1433 char *hyphen = strchr(p, '-');
1435 if (comma && hyphen > comma) break;
1436 len = hyphen + 1 - p;
1437 if (i == 7 && *p == '*' && len == 2) {
1439 memcpy(q, strInt, strIntLen);
1449 len = comma + 1 - p;
1456 return base_fnt_lst;
1460 CreateFontSet (char *base_fnt_lst)
1463 char **missing_list;
1467 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1468 &missing_list, &missing_count, &def_string);
1469 if (appData.debugMode) {
1471 XFontStruct **font_struct_list;
1472 char **font_name_list;
1473 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1475 fprintf(debugFP, " got list %s, locale %s\n",
1476 XBaseFontNameListOfFontSet(fntSet),
1477 XLocaleOfFontSet(fntSet));
1478 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1479 for (i = 0; i < count; i++) {
1480 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1483 for (i = 0; i < missing_count; i++) {
1484 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1487 if (fntSet == NULL) {
1488 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1493 #else // not ENABLE_NLS
1495 * Find a font that matches "pattern" that is as close as
1496 * possible to the targetPxlSize. Prefer fonts that are k
1497 * pixels smaller to fonts that are k pixels larger. The
1498 * pattern must be in the X Consortium standard format,
1499 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1500 * The return value should be freed with XtFree when no
1504 FindFont (char *pattern, int targetPxlSize)
1506 char **fonts, *p, *best, *scalable, *scalableTail;
1507 int i, j, nfonts, minerr, err, pxlSize;
1509 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1511 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1512 programName, pattern);
1519 for (i=0; i<nfonts; i++) {
1522 if (*p != '-') continue;
1524 if (*p == NULLCHAR) break;
1525 if (*p++ == '-') j++;
1527 if (j < 7) continue;
1530 scalable = fonts[i];
1533 err = pxlSize - targetPxlSize;
1534 if (Abs(err) < Abs(minerr) ||
1535 (minerr > 0 && err < 0 && -err == minerr)) {
1541 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1542 /* If the error is too big and there is a scalable font,
1543 use the scalable font. */
1544 int headlen = scalableTail - scalable;
1545 p = (char *) XtMalloc(strlen(scalable) + 10);
1546 while (isdigit(*scalableTail)) scalableTail++;
1547 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1549 p = (char *) XtMalloc(strlen(best) + 2);
1550 safeStrCpy(p, best, strlen(best)+1 );
1552 if (appData.debugMode) {
1553 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1554 pattern, targetPxlSize, p);
1556 XFreeFontNames(fonts);
1562 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1565 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1571 MarkMenuItem (char *menuRef, int state)
1573 MenuItem *item = MenuNameToItem(menuRef);
1577 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1578 XtSetValues(item->handle, args, 1);
1583 EnableNamedMenuItem (char *menuRef, int state)
1585 MenuItem *item = MenuNameToItem(menuRef);
1587 if(item) XtSetSensitive(item->handle, state);
1591 EnableButtonBar (int state)
1593 XtSetSensitive(optList[W_BUTTON].handle, state);
1598 SetMenuEnables (Enables *enab)
1600 while (enab->name != NULL) {
1601 EnableNamedMenuItem(enab->name, enab->value);
1607 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1608 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1610 if(*nprms == 0) return;
1611 item = MenuNameToItem(prms[0]);
1612 if(item) ((MenuProc *) item->proc) ();
1624 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1625 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1626 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1627 dmEnables[i].piece);
1628 XtSetSensitive(entry, p != NULL || !appData.testLegality
1629 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1630 && !appData.icsActive));
1632 while (p && *p++ == dmEnables[i].piece) count++;
1633 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1635 XtSetArg(args[j], XtNlabel, label); j++;
1636 XtSetValues(entry, args, j);
1641 do_flash_delay (unsigned long msec)
1647 FlashDelay (int flash_delay)
1649 XSync(xDisplay, False);
1650 if(flash_delay) do_flash_delay(flash_delay);
1654 Fraction (int x, int start, int stop)
1656 double f = ((double) x - start)/(stop - start);
1657 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1661 static WindowPlacement wpNew;
1664 CoDrag (Widget sh, WindowPlacement *wp)
1667 int j=0, touch=0, fudge = 2;
1668 GetActualPlacement(sh, wp);
1669 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1670 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1671 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1672 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1673 if(!touch ) return; // only windows that touch co-move
1674 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1675 int heightInc = wpNew.height - wpMain.height;
1676 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1677 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1678 wp->y += fracTop * heightInc;
1679 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1680 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1681 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1682 int widthInc = wpNew.width - wpMain.width;
1683 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1684 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1685 wp->y += fracLeft * widthInc;
1686 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1687 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1689 wp->x += wpNew.x - wpMain.x;
1690 wp->y += wpNew.y - wpMain.y;
1691 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1692 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1693 XtSetArg(args[j], XtNx, wp->x); j++;
1694 XtSetArg(args[j], XtNy, wp->y); j++;
1695 XtSetValues(sh, args, j);
1699 ReSize (WindowPlacement *wp)
1702 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1703 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1704 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1705 if(sqy < sqx) sqx = sqy;
1706 if(sqx != squareSize) {
1707 squareSize = sqx; // adopt new square size
1708 CreatePNGPieces(); // make newly scaled pieces
1709 InitDrawingSizes(0, 0); // creates grid etc.
1710 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1711 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1712 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1713 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1714 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1717 static XtIntervalId delayedDragID = 0;
1726 GetActualPlacement(shellWidget, &wpNew);
1727 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1728 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1729 busy = 0; return; // false alarm
1732 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1733 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1734 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1735 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1737 DrawPosition(True, NULL);
1738 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1746 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1748 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1752 EventProc (Widget widget, caddr_t unused, XEvent *event)
1754 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1755 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1759 * event handler for redrawing the board
1762 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1764 DrawPosition(True, NULL);
1769 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1770 { // [HGM] pv: walk PV
1771 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1774 extern int savedIndex; /* gross that this is global */
1777 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1780 XawTextPosition index, dummy;
1783 XawTextGetSelectionPos(w, &index, &dummy);
1784 XtSetArg(arg, XtNstring, &val);
1785 XtGetValues(w, &arg, 1);
1786 ReplaceComment(savedIndex, val);
1787 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1788 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1792 /* Disable all user input other than deleting the window */
1793 static int frozen = 0;
1799 /* Grab by a widget that doesn't accept input */
1800 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1804 /* Undo a FreezeUI */
1808 if (!frozen) return;
1809 XtRemoveGrab(optList[W_MESSG].handle);
1817 static int oldPausing = FALSE;
1818 static GameMode oldmode = (GameMode) -1;
1821 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1823 if (pausing != oldPausing) {
1824 oldPausing = pausing;
1825 MarkMenuItem("Mode.Pause", pausing);
1827 if (appData.showButtonBar) {
1828 /* Always toggle, don't set. Previous code messes up when
1829 invoked while the button is pressed, as releasing it
1830 toggles the state again. */
1833 XtSetArg(args[0], XtNbackground, &oldbg);
1834 XtSetArg(args[1], XtNforeground, &oldfg);
1835 XtGetValues(optList[W_PAUSE].handle,
1837 XtSetArg(args[0], XtNbackground, oldfg);
1838 XtSetArg(args[1], XtNforeground, oldbg);
1840 XtSetValues(optList[W_PAUSE].handle, args, 2);
1844 wname = ModeToWidgetName(oldmode);
1845 if (wname != NULL) {
1846 MarkMenuItem(wname, False);
1848 wname = ModeToWidgetName(gameMode);
1849 if (wname != NULL) {
1850 MarkMenuItem(wname, True);
1853 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1855 /* Maybe all the enables should be handled here, not just this one */
1856 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1858 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1863 * Button/menu procedures
1866 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1867 char *selected_fen_position=NULL;
1870 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1871 Atom *type_return, XtPointer *value_return,
1872 unsigned long *length_return, int *format_return)
1874 char *selection_tmp;
1876 // if (!selected_fen_position) return False; /* should never happen */
1877 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1878 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1879 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1882 if (f == NULL) return False;
1886 selection_tmp = XtMalloc(len + 1);
1887 count = fread(selection_tmp, 1, len, f);
1890 XtFree(selection_tmp);
1893 selection_tmp[len] = NULLCHAR;
1895 /* note: since no XtSelectionDoneProc was registered, Xt will
1896 * automatically call XtFree on the value returned. So have to
1897 * make a copy of it allocated with XtMalloc */
1898 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1899 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1902 *value_return=selection_tmp;
1903 *length_return=strlen(selection_tmp);
1904 *type_return=*target;
1905 *format_return = 8; /* bits per byte */
1907 } else if (*target == XA_TARGETS(xDisplay)) {
1908 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1909 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1910 targets_tmp[1] = XA_STRING;
1911 *value_return = targets_tmp;
1912 *type_return = XA_ATOM;
1915 // This code leads to a read of value_return out of bounds on 64-bit systems.
1916 // Other code which I have seen always sets *format_return to 32 independent of
1917 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1918 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1919 *format_return = 8 * sizeof(Atom);
1920 if (*format_return > 32) {
1921 *length_return *= *format_return / 32;
1922 *format_return = 32;
1925 *format_return = 32;
1933 /* note: when called from menu all parameters are NULL, so no clue what the
1934 * Widget which was clicked on was, or what the click event was
1937 CopySomething (char *src)
1939 selected_fen_position = src;
1941 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1942 * have a notion of a position that is selected but not copied.
1943 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1945 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1947 SendPositionSelection,
1948 NULL/* lose_ownership_proc */ ,
1949 NULL/* transfer_done_proc */);
1950 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1952 SendPositionSelection,
1953 NULL/* lose_ownership_proc */ ,
1954 NULL/* transfer_done_proc */);
1957 /* function called when the data to Paste is ready */
1959 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1960 Atom *type, XtPointer value, unsigned long *len, int *format)
1963 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1964 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1965 EditPositionPasteFEN(fenstr);
1969 /* called when Paste Position button is pressed,
1970 * all parameters will be NULL */
1972 PastePositionProc ()
1974 XtGetSelectionValue(menuBarWidget,
1975 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1976 /* (XtSelectionCallbackProc) */ PastePositionCB,
1977 NULL, /* client_data passed to PastePositionCB */
1979 /* better to use the time field from the event that triggered the
1980 * call to this function, but that isn't trivial to get
1987 /* note: when called from menu all parameters are NULL, so no clue what the
1988 * Widget which was clicked on was, or what the click event was
1990 /* function called when the data to Paste is ready */
1992 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1993 Atom *type, XtPointer value, unsigned long *len, int *format)
1996 if (value == NULL || *len == 0) {
1997 return; /* nothing had been selected to copy */
1999 f = fopen(gamePasteFilename, "w");
2001 DisplayError(_("Can't open temp file"), errno);
2004 fwrite(value, 1, *len, f);
2007 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2010 /* called when Paste Game button is pressed,
2011 * all parameters will be NULL */
2015 XtGetSelectionValue(menuBarWidget,
2016 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2017 /* (XtSelectionCallbackProc) */ PasteGameCB,
2018 NULL, /* client_data passed to PasteGameCB */
2020 /* better to use the time field from the event that triggered the
2021 * call to this function, but that isn't trivial to get
2030 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2037 { // bassic primitive for determining if modifier keys are pressed
2038 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2041 XQueryKeymap(xDisplay,keys);
2042 for(i=0; i<6; i++) {
2044 j = XKeysymToKeycode(xDisplay, codes[i]);
2045 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2051 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2055 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2056 if ( n == 1 && *buf >= 32 // printable
2057 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2058 ) BoxAutoPopUp (buf);
2062 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2063 { // [HGM] input: let up-arrow recall previous line from history
2068 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2069 { // [HGM] input: let down-arrow recall next line from history
2074 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2080 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2082 if (!TempBackwardActive) {
2083 TempBackwardActive = True;
2089 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2091 /* Check to see if triggered by a key release event for a repeating key.
2092 * If so the next queued event will be a key press of the same key at the same time */
2093 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2095 XPeekEvent(xDisplay, &next);
2096 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2097 next.xkey.keycode == event->xkey.keycode)
2101 TempBackwardActive = False;
2105 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2106 { // called as key binding
2109 if (nprms && *nprms > 0)
2113 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2119 { // called from menu
2120 ManInner(NULL, NULL, NULL, NULL);
2124 SetWindowTitle (char *text, char *title, char *icon)
2128 if (appData.titleInWindow) {
2130 XtSetArg(args[i], XtNlabel, text); i++;
2131 XtSetValues(titleWidget, args, i);
2134 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2135 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2136 XtSetValues(shellWidget, args, i);
2137 XSync(xDisplay, False);
2142 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2148 DisplayIcsInteractionTitle (String message)
2150 if (oldICSInteractionTitle == NULL) {
2151 /* Magic to find the old window title, adapted from vim */
2152 char *wina = getenv("WINDOWID");
2154 Window win = (Window) atoi(wina);
2155 Window root, parent, *children;
2156 unsigned int nchildren;
2157 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2159 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2160 if (!XQueryTree(xDisplay, win, &root, &parent,
2161 &children, &nchildren)) break;
2162 if (children) XFree((void *)children);
2163 if (parent == root || parent == 0) break;
2166 XSetErrorHandler(oldHandler);
2168 if (oldICSInteractionTitle == NULL) {
2169 oldICSInteractionTitle = "xterm";
2172 printf("\033]0;%s\007", message);
2177 XtIntervalId delayedEventTimerXID = 0;
2178 DelayedEventCallback delayedEventCallback = 0;
2183 delayedEventTimerXID = 0;
2184 delayedEventCallback();
2188 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2190 if(delayedEventTimerXID && delayedEventCallback == cb)
2191 // [HGM] alive: replace, rather than add or flush identical event
2192 XtRemoveTimeOut(delayedEventTimerXID);
2193 delayedEventCallback = cb;
2194 delayedEventTimerXID =
2195 XtAppAddTimeOut(appContext, millisec,
2196 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2199 DelayedEventCallback
2202 if (delayedEventTimerXID) {
2203 return delayedEventCallback;
2210 CancelDelayedEvent ()
2212 if (delayedEventTimerXID) {
2213 XtRemoveTimeOut(delayedEventTimerXID);
2214 delayedEventTimerXID = 0;
2218 XtIntervalId loadGameTimerXID = 0;
2221 LoadGameTimerRunning ()
2223 return loadGameTimerXID != 0;
2227 StopLoadGameTimer ()
2229 if (loadGameTimerXID != 0) {
2230 XtRemoveTimeOut(loadGameTimerXID);
2231 loadGameTimerXID = 0;
2239 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2241 loadGameTimerXID = 0;
2246 StartLoadGameTimer (long millisec)
2249 XtAppAddTimeOut(appContext, millisec,
2250 (XtTimerCallbackProc) LoadGameTimerCallback,
2254 XtIntervalId analysisClockXID = 0;
2257 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2259 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2260 || appData.icsEngineAnalyze) { // [DM]
2261 AnalysisPeriodicEvent(0);
2262 StartAnalysisClock();
2267 StartAnalysisClock ()
2270 XtAppAddTimeOut(appContext, 2000,
2271 (XtTimerCallbackProc) AnalysisClockCallback,
2275 XtIntervalId clockTimerXID = 0;
2278 ClockTimerRunning ()
2280 return clockTimerXID != 0;
2286 if (clockTimerXID != 0) {
2287 XtRemoveTimeOut(clockTimerXID);
2296 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2303 StartClockTimer (long millisec)
2306 XtAppAddTimeOut(appContext, millisec,
2307 (XtTimerCallbackProc) ClockTimerCallback,
2312 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2316 Widget w = (Widget) opt->handle;
2318 /* check for low time warning */
2319 Pixel foregroundOrWarningColor = timerForegroundPixel;
2322 appData.lowTimeWarning &&
2323 (timer / 1000) < appData.icsAlarmTime)
2324 foregroundOrWarningColor = lowTimeWarningColor;
2326 if (appData.clockMode) {
2327 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2328 XtSetArg(args[0], XtNlabel, buf);
2330 snprintf(buf, MSG_SIZ, "%s ", color);
2331 XtSetArg(args[0], XtNlabel, buf);
2336 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2337 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2339 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2340 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2343 XtSetValues(w, args, 3);
2346 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2349 SetClockIcon (int color)
2352 Pixmap pm = *clockIcons[color];
2353 if (iconPixmap != pm) {
2355 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2356 XtSetValues(shellWidget, args, 1);
2360 #define INPUT_SOURCE_BUF_SIZE 8192
2369 char buf[INPUT_SOURCE_BUF_SIZE];
2374 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2376 InputSource *is = (InputSource *) closure;
2381 if (is->lineByLine) {
2382 count = read(is->fd, is->unused,
2383 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2385 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2388 is->unused += count;
2390 while (p < is->unused) {
2391 q = memchr(p, '\n', is->unused - p);
2392 if (q == NULL) break;
2394 (is->func)(is, is->closure, p, q - p, 0);
2398 while (p < is->unused) {
2403 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2408 (is->func)(is, is->closure, is->buf, count, error);
2413 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2416 ChildProc *cp = (ChildProc *) pr;
2418 is = (InputSource *) calloc(1, sizeof(InputSource));
2419 is->lineByLine = lineByLine;
2423 is->fd = fileno(stdin);
2425 is->kind = cp->kind;
2426 is->fd = cp->fdFrom;
2429 is->unused = is->buf;
2432 is->xid = XtAppAddInput(appContext, is->fd,
2433 (XtPointer) (XtInputReadMask),
2434 (XtInputCallbackProc) DoInputCallback,
2436 is->closure = closure;
2437 return (InputSourceRef) is;
2441 RemoveInputSource (InputSourceRef isr)
2443 InputSource *is = (InputSource *) isr;
2445 if (is->xid == 0) return;
2446 XtRemoveInput(is->xid);
2452 static Boolean frameWaiting;
2455 FrameAlarm (int sig)
2457 frameWaiting = False;
2458 /* In case System-V style signals. Needed?? */
2459 signal(SIGALRM, FrameAlarm);
2463 FrameDelay (int time)
2465 struct itimerval delay;
2467 XSync(xDisplay, False);
2470 frameWaiting = True;
2471 signal(SIGALRM, FrameAlarm);
2472 delay.it_interval.tv_sec =
2473 delay.it_value.tv_sec = time / 1000;
2474 delay.it_interval.tv_usec =
2475 delay.it_value.tv_usec = (time % 1000) * 1000;
2476 setitimer(ITIMER_REAL, &delay, NULL);
2477 while (frameWaiting) pause();
2478 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2479 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2480 setitimer(ITIMER_REAL, &delay, NULL);
2487 FrameDelay (int time)
2489 XSync(xDisplay, False);
2491 usleep(time * 1000);
2497 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2499 char buf[MSG_SIZ], *logoName = buf;
2500 if(appData.logo[n][0]) {
2501 logoName = appData.logo[n];
2502 } else if(appData.autoLogo) {
2503 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2504 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2505 } else if(appData.logoDir && appData.logoDir[0]) {
2506 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2510 { ASSIGN(cps->programLogo, logoName); }
2514 UpdateLogos (int displ)
2516 if(optList[W_WHITE-1].handle == NULL) return;
2517 LoadLogo(&first, 0, 0);
2518 LoadLogo(&second, 1, appData.icsActive);
2519 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);