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 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"
211 #define usleep(t) _sleep2(((t)+500)/1000)
215 # define _(s) gettext (s)
216 # define N_(s) gettext_noop (s)
222 int main P((int argc, char **argv));
223 RETSIGTYPE CmailSigHandler P((int sig));
224 RETSIGTYPE IntSigHandler P((int sig));
225 RETSIGTYPE TermSizeSigHandler P((int sig));
226 Widget CreateMenuBar P((Menu *mb, int boardWidth));
228 char *InsertPxlSize P((char *pattern, int targetPxlSize));
229 XFontSet CreateFontSet P((char *base_fnt_lst));
231 char *FindFont P((char *pattern, int targetPxlSize));
233 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
234 u_int wreq, u_int hreq));
235 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
236 void DelayedDrag P((void));
237 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
238 void HandlePV P((Widget w, XEvent * event,
239 String * params, Cardinal * nParams));
240 void DrawPositionProc P((Widget w, XEvent *event,
241 String *prms, Cardinal *nprms));
242 void CommentClick P((Widget w, XEvent * event,
243 String * params, Cardinal * nParams));
244 void ICSInputBoxPopUp P((void));
245 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
246 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
247 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
248 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
249 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
250 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
251 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
252 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
253 Boolean TempBackwardActive = False;
254 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
255 void DisplayMove P((int moveNumber));
256 void update_ics_width P(());
257 int CopyMemoProc P(());
260 * XBoard depends on Xt R4 or higher
262 int xtVersion = XtSpecificationRelease;
267 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
268 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
269 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
270 Option *optList; // contains all widgets of main window
272 XFontSet fontSet, clockFontSet;
275 XFontStruct *clockFontStruct;
277 Font coordFontID, countFontID;
278 XFontStruct *coordFontStruct, *countFontStruct;
279 XtAppContext appContext;
282 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
284 Position commentX = -1, commentY = -1;
285 Dimension commentW, commentH;
286 typedef unsigned int BoardSize;
288 Boolean chessProgram;
290 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
291 int smallLayout = 0, tinyLayout = 0,
292 marginW, marginH, // [HGM] for run-time resizing
293 fromX = -1, fromY = -1, toX, toY, commentUp = False,
294 errorExitStatus = -1, defaultLineGap;
295 Dimension textHeight;
296 Pixel timerForegroundPixel, timerBackgroundPixel;
297 Pixel buttonForegroundPixel, buttonBackgroundPixel;
298 char *chessDir, *programName, *programVersion;
299 Boolean alwaysOnTop = False;
300 char *icsTextMenuString;
302 char *firstChessProgramNames;
303 char *secondChessProgramNames;
305 WindowPlacement wpMain;
306 WindowPlacement wpConsole;
307 WindowPlacement wpComment;
308 WindowPlacement wpMoveHistory;
309 WindowPlacement wpEvalGraph;
310 WindowPlacement wpEngineOutput;
311 WindowPlacement wpGameList;
312 WindowPlacement wpTags;
313 WindowPlacement wpDualBoard;
316 /* This magic number is the number of intermediate frames used
317 in each half of the animation. For short moves it's reduced
318 by 1. The total number of frames will be factor * 2 + 1. */
321 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
328 DropMenuEnables dmEnables[] = {
345 XtResource clientResources[] = {
346 { "flashCount", "flashCount", XtRInt, sizeof(int),
347 XtOffset(AppDataPtr, flashCount), XtRImmediate,
348 (XtPointer) FLASH_COUNT },
351 XrmOptionDescRec shellOptions[] = {
352 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
353 { "-flash", "flashCount", XrmoptionNoArg, "3" },
354 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
357 XtActionsRec boardActions[] = {
358 { "DrawPosition", DrawPositionProc },
359 { "HandlePV", HandlePV },
360 { "SelectPV", SelectPV },
361 { "StopPV", StopPV },
362 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
363 { "QuitProc", QuitWrapper },
364 { "ManProc", ManInner },
365 { "TempBackwardProc", TempBackwardProc },
366 { "TempForwardProc", TempForwardProc },
367 { "CommentClick", (XtActionProc) CommentClick },
368 { "GenericPopDown", (XtActionProc) GenericPopDown },
369 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
370 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
371 { "SelectMove", (XtActionProc) SelectMoveX },
372 { "LoadSelectedProc", LoadSelectedProc },
373 { "SetFilterProc", SetFilterProc },
374 { "TypeInProc", TypeInProc },
375 { "EnterKeyProc", EnterKeyProc },
376 { "UpKeyProc", UpKeyProc },
377 { "DownKeyProc", DownKeyProc },
378 { "WheelProc", WheelProc },
379 { "TabProc", TabProc },
382 char globalTranslations[] =
383 ":Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
384 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
385 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
386 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
387 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
388 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
389 :<Key>Pause: MenuItem(Mode.Pause) \n \
390 :Ctrl<Key>d: MenuItem(DebugProc) \n \
391 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
392 :<Key>Left: MenuItem(Edit.Backward) \n \
393 :<Key>Right: MenuItem(Edit.Forward) \n \
394 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
395 #ifndef OPTIONSDIALOG
397 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
398 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
399 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
400 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
401 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
404 :<KeyDown>Return: TempBackwardProc() \n \
405 :<KeyUp>Return: TempForwardProc() \n";
407 char ICSInputTranslations[] =
408 "<Key>Up: UpKeyProc() \n "
409 "<Key>Down: DownKeyProc() \n "
410 "<Key>Return: EnterKeyProc() \n";
412 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
413 // as the widget is destroyed before the up-click can call extend-end
414 char commentTranslations[] = "<Btn3Down>: extend-end(PRIMARY) select-start() CommentClick() \n";
416 String xboardResources[] = {
417 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
422 /* Max possible square size */
423 #define MAXSQSIZE 256
425 /* Arrange to catch delete-window events */
426 Atom wm_delete_window;
428 CatchDeleteWindow (Widget w, String procname)
431 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
432 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
433 XtAugmentTranslations(w, XtParseTranslationTable(buf));
440 XtSetArg(args[0], XtNiconic, False);
441 XtSetValues(shellWidget, args, 1);
443 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
446 //---------------------------------------------------------------------------------------------------------
447 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
450 #define CW_USEDEFAULT (1<<31)
451 #define ICS_TEXT_MENU_SIZE 90
452 #define DEBUG_FILE "xboard.debug"
453 #define SetCurrentDirectory chdir
454 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
458 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
461 // front-end part of option handling
463 // [HGM] This platform-dependent table provides the location for storing the color info
464 extern char *crWhite, * crBlack;
468 &appData.whitePieceColor,
469 &appData.blackPieceColor,
470 &appData.lightSquareColor,
471 &appData.darkSquareColor,
472 &appData.highlightSquareColor,
473 &appData.premoveHighlightColor,
474 &appData.lowTimeWarningColor,
485 // [HGM] font: keep a font for each square size, even non-stndard ones
488 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
489 char *fontTable[NUM_FONTS][MAX_SIZE];
492 ParseFont (char *name, int number)
493 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
495 if(sscanf(name, "size%d:", &size)) {
496 // [HGM] font: font is meant for specific boardSize (likely from settings file);
497 // defer processing it until we know if it matches our board size
498 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
499 fontTable[number][size] = strdup(strchr(name, ':')+1);
500 fontValid[number][size] = True;
505 case 0: // CLOCK_FONT
506 appData.clockFont = strdup(name);
508 case 1: // MESSAGE_FONT
509 appData.font = strdup(name);
511 case 2: // COORD_FONT
512 appData.coordFont = strdup(name);
517 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
522 { // only 2 fonts currently
523 appData.clockFont = CLOCK_FONT_NAME;
524 appData.coordFont = COORD_FONT_NAME;
525 appData.font = DEFAULT_FONT_NAME;
530 { // no-op, until we identify the code for this already in XBoard and move it here
534 ParseColor (int n, char *name)
535 { // in XBoard, just copy the color-name string
536 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
540 ParseTextAttribs (ColorClass cc, char *s)
542 (&appData.colorShout)[cc] = strdup(s);
546 ParseBoardSize (void *addr, char *name)
548 appData.boardSize = strdup(name);
553 { // In XBoard the sound-playing program takes care of obtaining the actual sound
557 SetCommPortDefaults ()
558 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
561 // [HGM] args: these three cases taken out to stay in front-end
563 SaveFontArg (FILE *f, ArgDescriptor *ad)
566 int i, n = (int)(intptr_t)ad->argLoc;
568 case 0: // CLOCK_FONT
569 name = appData.clockFont;
571 case 1: // MESSAGE_FONT
574 case 2: // COORD_FONT
575 name = appData.coordFont;
580 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
581 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
582 fontTable[n][squareSize] = strdup(name);
583 fontValid[n][squareSize] = True;
586 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
587 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
592 { // nothing to do, as the sounds are at all times represented by their text-string names already
596 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
597 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
598 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
602 SaveColor (FILE *f, ArgDescriptor *ad)
603 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
604 if(colorVariable[(int)(intptr_t)ad->argLoc])
605 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
609 SaveBoardSize (FILE *f, char *name, void *addr)
610 { // wrapper to shield back-end from BoardSize & sizeInfo
611 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
615 ParseCommPortSettings (char *s)
616 { // no such option in XBoard (yet)
622 GetActualPlacement (Widget wg, WindowPlacement *wp)
624 XWindowAttributes winAt;
631 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
632 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
633 wp->x = rx - winAt.x;
634 wp->y = ry - winAt.y;
635 wp->height = winAt.height;
636 wp->width = winAt.width;
637 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
642 { // wrapper to shield use of window handles from back-end (make addressible by number?)
643 // In XBoard this will have to wait until awareness of window parameters is implemented
644 GetActualPlacement(shellWidget, &wpMain);
645 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
646 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
647 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
648 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
649 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
650 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
654 PrintCommPortSettings (FILE *f, char *name)
655 { // This option does not exist in XBoard
659 EnsureOnScreen (int *x, int *y, int minX, int minY)
666 { // [HGM] args: allows testing if main window is realized from back-end
667 return xBoardWindow != 0;
671 PopUpStartupDialog ()
672 { // start menu not implemented in XBoard
676 ConvertToLine (int argc, char **argv)
678 static char line[128*1024], buf[1024];
682 for(i=1; i<argc; i++)
684 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
685 && argv[i][0] != '{' )
686 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
688 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
689 strncat(line, buf, 128*1024 - strlen(line) - 1 );
692 line[strlen(line)-1] = NULLCHAR;
696 //--------------------------------------------------------------------------------------------
699 ResizeBoardWindow (int w, int h, int inhibit)
701 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
703 shellArgs[0].value = w;
704 shellArgs[1].value = h;
705 shellArgs[4].value = shellArgs[2].value = w;
706 shellArgs[5].value = shellArgs[3].value = h;
707 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
709 XSync(xDisplay, False);
713 MakeOneColor (char *name, Pixel *color)
716 if (!appData.monoMode) {
717 vFrom.addr = (caddr_t) name;
718 vFrom.size = strlen(name);
719 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
720 if (vTo.addr == NULL) {
721 appData.monoMode = True;
724 *color = *(Pixel *) vTo.addr;
732 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
733 int forceMono = False;
735 if (appData.lowTimeWarning)
736 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
737 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
738 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
744 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
745 { // detervtomine what fonts to use, and create them
749 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
750 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
751 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
752 appData.font = fontTable[MESSAGE_FONT][squareSize];
753 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
754 appData.coordFont = fontTable[COORD_FONT][squareSize];
757 appData.font = InsertPxlSize(appData.font, fontPxlSize);
758 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
759 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
760 fontSet = CreateFontSet(appData.font);
761 clockFontSet = CreateFontSet(appData.clockFont);
763 /* For the coordFont, use the 0th font of the fontset. */
764 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
765 XFontStruct **font_struct_list;
766 XFontSetExtents *fontSize;
767 char **font_name_list;
768 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
769 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
770 coordFontStruct = XQueryFont(xDisplay, coordFontID);
771 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
772 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
775 appData.font = FindFont(appData.font, fontPxlSize);
776 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
777 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
778 clockFontID = XLoadFont(xDisplay, appData.clockFont);
779 clockFontStruct = XQueryFont(xDisplay, clockFontID);
780 coordFontID = XLoadFont(xDisplay, appData.coordFont);
781 coordFontStruct = XQueryFont(xDisplay, coordFontID);
782 // textHeight in !NLS mode!
784 countFontID = coordFontID; // [HGM] holdings
785 countFontStruct = coordFontStruct;
787 xdb = XtDatabase(xDisplay);
789 XrmPutLineResource(&xdb, "*international: True");
790 vTo.size = sizeof(XFontSet);
791 vTo.addr = (XtPointer) &fontSet;
792 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
794 XrmPutStringResource(&xdb, "*font", appData.font);
804 case ArgInt: p = " N"; break;
805 case ArgString: p = " STR"; break;
806 case ArgBoolean: p = " TF"; break;
807 case ArgSettingsFilename:
808 case ArgBackupSettingsFile:
809 case ArgFilename: p = " FILE"; break;
810 case ArgX: p = " Nx"; break;
811 case ArgY: p = " Ny"; break;
812 case ArgAttribs: p = " TEXTCOL"; break;
813 case ArgColor: p = " COL"; break;
814 case ArgFont: p = " FONT"; break;
815 case ArgBoardSize: p = " SIZE"; break;
816 case ArgFloat: p = " FLOAT"; break;
821 case ArgCommSettings:
829 GenerateGlobalTranslationTable (void)
831 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
839 /* loop over all menu entries */
840 for( i=0; menuBar[i].mi ; i++)
843 for(j=0; mi[j].proc; j++)
851 char *key,*test, *mods;
853 /* check for Ctrl/Alt */
854 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
855 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
856 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
858 /* remove all <...> */
859 test = strrchr(mi[j].accel, '>');
861 key = strdup(mi[j].accel);
863 key = strdup(++test); // remove ">"
865 /* instead of shift X11 uses the uppercase letter directly*/
866 if (shift && strlen(key)==1 )
868 *key = toupper(*key);
872 /* handle some special cases which have different names in X11 */
873 if ( strncmp(key, "Page_Down", 9) == 0 )
878 else if ( strncmp(key, "Page_Up", 7) == 0 )
884 /* create string of mods */
886 mods = strdup("Ctrl ");
892 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
893 strncat(mods, "Meta ", 5);
898 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
899 strncat(mods, "Shift ", 6);
902 // remove trailing space
903 if( isspace(mods[strlen(mods)-1]) )
904 mods[strlen(mods)-1]='\0';
906 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
907 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
908 char *name = malloc(namesize+1);
909 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
911 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
912 char *buffer = malloc(buffersize+1);
913 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
915 /* add string to the output */
916 output = realloc(output, strlen(output) + strlen(buffer)+1);
917 strncat(output, buffer, strlen(buffer));
936 ArgDescriptor *q, *p = argDescriptors+5;
937 printf("\nXBoard accepts the following options:\n"
938 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
939 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
940 " SIZE = board-size spec(s)\n"
941 " Within parentheses are short forms, or options to set to true or false.\n"
942 " Persistent options (saved in the settings file) are marked with *)\n\n");
944 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
945 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
946 if(p->save) strcat(buf+len, "*");
947 for(q=p+1; q->argLoc == p->argLoc; q++) {
948 if(q->argName[0] == '-') continue;
949 strcat(buf+len, q == p+1 ? " (" : " ");
950 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
952 if(q != p+1) strcat(buf+len, ")");
954 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
957 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
961 SlaveResize (Option *opt)
966 main (int argc, char **argv)
968 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
969 XSetWindowAttributes window_attributes;
971 Dimension boardWidth, boardHeight, w, h;
973 int forceMono = False;
975 srandom(time(0)); // [HGM] book: make random truly random
977 setbuf(stdout, NULL);
978 setbuf(stderr, NULL);
981 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
982 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
986 if(argc > 1 && !strcmp(argv[1], "--help" )) {
991 programName = strrchr(argv[0], '/');
992 if (programName == NULL)
993 programName = argv[0];
998 XtSetLanguageProc(NULL, NULL, NULL);
999 if (appData.debugMode) {
1000 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1003 bindtextdomain(PACKAGE, LOCALEDIR);
1004 textdomain(PACKAGE);
1007 appData.boardSize = "";
1008 InitAppData(ConvertToLine(argc, argv));
1010 if (p == NULL) p = "/tmp";
1011 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1012 gameCopyFilename = (char*) malloc(i);
1013 gamePasteFilename = (char*) malloc(i);
1014 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1015 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1017 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1018 static char buf[MSG_SIZ];
1019 EscapeExpand(buf, appData.firstInitString);
1020 appData.firstInitString = strdup(buf);
1021 EscapeExpand(buf, appData.secondInitString);
1022 appData.secondInitString = strdup(buf);
1023 EscapeExpand(buf, appData.firstComputerString);
1024 appData.firstComputerString = strdup(buf);
1025 EscapeExpand(buf, appData.secondComputerString);
1026 appData.secondComputerString = strdup(buf);
1029 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1032 if (chdir(chessDir) != 0) {
1033 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1039 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1040 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1041 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1042 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1045 setbuf(debugFP, NULL);
1048 /* [HGM,HR] make sure board size is acceptable */
1049 if(appData.NrFiles > BOARD_FILES ||
1050 appData.NrRanks > BOARD_RANKS )
1051 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1054 /* This feature does not work; animation needs a rewrite */
1055 appData.highlightDragging = FALSE;
1059 gameInfo.variant = StringToVariant(appData.variant);
1060 InitPosition(FALSE);
1063 XtAppInitialize(&appContext, "XBoard", shellOptions,
1064 XtNumber(shellOptions),
1065 &argc, argv, xboardResources, NULL, 0);
1067 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1068 clientResources, XtNumber(clientResources),
1071 xDisplay = XtDisplay(shellWidget);
1072 xScreen = DefaultScreen(xDisplay);
1073 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1076 * determine size, based on supplied or remembered -size, or screen size
1078 if (isdigit(appData.boardSize[0])) {
1079 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1080 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1081 &fontPxlSize, &smallLayout, &tinyLayout);
1083 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1084 programName, appData.boardSize);
1088 /* Find some defaults; use the nearest known size */
1089 SizeDefaults *szd, *nearest;
1090 int distance = 99999;
1091 nearest = szd = sizeDefaults;
1092 while (szd->name != NULL) {
1093 if (abs(szd->squareSize - squareSize) < distance) {
1095 distance = abs(szd->squareSize - squareSize);
1096 if (distance == 0) break;
1100 if (i < 2) lineGap = nearest->lineGap;
1101 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1102 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1103 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1104 if (i < 6) smallLayout = nearest->smallLayout;
1105 if (i < 7) tinyLayout = nearest->tinyLayout;
1108 SizeDefaults *szd = sizeDefaults;
1109 if (*appData.boardSize == NULLCHAR) {
1110 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1111 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1114 if (szd->name == NULL) szd--;
1115 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1117 while (szd->name != NULL &&
1118 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1119 if (szd->name == NULL) {
1120 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1121 programName, appData.boardSize);
1125 squareSize = szd->squareSize;
1126 lineGap = szd->lineGap;
1127 clockFontPxlSize = szd->clockFontPxlSize;
1128 coordFontPxlSize = szd->coordFontPxlSize;
1129 fontPxlSize = szd->fontPxlSize;
1130 smallLayout = szd->smallLayout;
1131 tinyLayout = szd->tinyLayout;
1132 // [HGM] font: use defaults from settings file if available and not overruled
1135 defaultLineGap = lineGap;
1136 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1138 /* [HR] height treated separately (hacked) */
1139 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1140 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1143 * Determine what fonts to use.
1145 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1148 * Detect if there are not enough colors available and adapt.
1150 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1151 appData.monoMode = True;
1154 forceMono = MakeColors();
1157 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1159 appData.monoMode = True;
1162 if (appData.monoMode && appData.debugMode) {
1163 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1164 (unsigned long) XWhitePixel(xDisplay, xScreen),
1165 (unsigned long) XBlackPixel(xDisplay, xScreen));
1168 ParseIcsTextColors();
1170 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1176 layoutName = "tinyLayout";
1177 } else if (smallLayout) {
1178 layoutName = "smallLayout";
1180 layoutName = "normalLayout";
1183 optList = BoardPopUp(squareSize, lineGap, (void*)
1189 InitDrawingHandle(optList + W_BOARD);
1190 currBoard = &optList[W_BOARD];
1191 boardWidget = optList[W_BOARD].handle;
1192 menuBarWidget = optList[W_MENU].handle;
1193 dropMenu = optList[W_DROP].handle;
1194 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1195 formWidget = XtParent(boardWidget);
1196 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1197 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1198 XtGetValues(optList[W_WHITE].handle, args, 2);
1199 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1200 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1201 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1202 XtGetValues(optList[W_PAUSE].handle, args, 2);
1205 xBoardWindow = XtWindow(boardWidget);
1207 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1208 // not need to go into InitDrawingSizes().
1211 * Create X checkmark bitmap and initialize option menu checks.
1213 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1214 checkmark_bits, checkmark_width, checkmark_height);
1220 ReadBitmap(&wIconPixmap, "icon_white.bm",
1221 icon_white_bits, icon_white_width, icon_white_height);
1222 ReadBitmap(&bIconPixmap, "icon_black.bm",
1223 icon_black_bits, icon_black_width, icon_black_height);
1224 iconPixmap = wIconPixmap;
1226 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1227 XtSetValues(shellWidget, args, i);
1230 * Create a cursor for the board widget.
1232 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1233 XChangeWindowAttributes(xDisplay, xBoardWindow,
1234 CWCursor, &window_attributes);
1237 * Inhibit shell resizing.
1239 shellArgs[0].value = (XtArgVal) &w;
1240 shellArgs[1].value = (XtArgVal) &h;
1241 XtGetValues(shellWidget, shellArgs, 2);
1242 shellArgs[4].value = shellArgs[2].value = w;
1243 shellArgs[5].value = shellArgs[3].value = h;
1244 // XtSetValues(shellWidget, &shellArgs[2], 4);
1245 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1246 marginH = h - boardHeight;
1248 CatchDeleteWindow(shellWidget, "QuitProc");
1253 if(appData.logoSize)
1254 { // locate and read user logo
1256 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1257 ASSIGN(userLogo, buf);
1260 if (appData.animate || appData.animateDragging)
1264 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1266 XtAugmentTranslations(formWidget,
1267 XtParseTranslationTable(globalTranslations));
1268 XtAugmentTranslations(formWidget,
1269 XtParseTranslationTable(TranslationsTableMenus));
1271 XtAddEventHandler(formWidget, KeyPressMask, False,
1272 (XtEventHandler) MoveTypeInProc, NULL);
1273 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1274 (XtEventHandler) EventProc, NULL);
1276 /* [AS] Restore layout */
1277 if( wpMoveHistory.visible ) {
1281 if( wpEvalGraph.visible )
1286 if( wpEngineOutput.visible ) {
1287 EngineOutputPopUp();
1292 if (errorExitStatus == -1) {
1293 if (appData.icsActive) {
1294 /* We now wait until we see "login:" from the ICS before
1295 sending the logon script (problems with timestamp otherwise) */
1296 /*ICSInitScript();*/
1297 if (appData.icsInputBox) ICSInputBoxPopUp();
1301 signal(SIGWINCH, TermSizeSigHandler);
1303 signal(SIGINT, IntSigHandler);
1304 signal(SIGTERM, IntSigHandler);
1305 if (*appData.cmailGameName != NULLCHAR) {
1306 signal(SIGUSR1, CmailSigHandler);
1310 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1313 // XtSetKeyboardFocus(shellWidget, formWidget);
1314 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1316 XtAppMainLoop(appContext);
1317 if (appData.debugMode) fclose(debugFP); // [DM] debug
1322 TermSizeSigHandler (int sig)
1328 IntSigHandler (int sig)
1334 CmailSigHandler (int sig)
1339 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1341 /* Activate call-back function CmailSigHandlerCallBack() */
1342 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1344 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1348 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1351 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1353 /**** end signal code ****/
1356 #define Abs(n) ((n)<0 ? -(n) : (n))
1360 InsertPxlSize (char *pattern, int targetPxlSize)
1362 char *base_fnt_lst, strInt[12], *p, *q;
1363 int alternatives, i, len, strIntLen;
1366 * Replace the "*" (if present) in the pixel-size slot of each
1367 * alternative with the targetPxlSize.
1371 while ((p = strchr(p, ',')) != NULL) {
1375 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1376 strIntLen = strlen(strInt);
1377 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1381 while (alternatives--) {
1382 char *comma = strchr(p, ',');
1383 for (i=0; i<14; i++) {
1384 char *hyphen = strchr(p, '-');
1386 if (comma && hyphen > comma) break;
1387 len = hyphen + 1 - p;
1388 if (i == 7 && *p == '*' && len == 2) {
1390 memcpy(q, strInt, strIntLen);
1400 len = comma + 1 - p;
1407 return base_fnt_lst;
1411 CreateFontSet (char *base_fnt_lst)
1414 char **missing_list;
1418 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1419 &missing_list, &missing_count, &def_string);
1420 if (appData.debugMode) {
1422 XFontStruct **font_struct_list;
1423 char **font_name_list;
1424 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1426 fprintf(debugFP, " got list %s, locale %s\n",
1427 XBaseFontNameListOfFontSet(fntSet),
1428 XLocaleOfFontSet(fntSet));
1429 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1430 for (i = 0; i < count; i++) {
1431 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1434 for (i = 0; i < missing_count; i++) {
1435 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1438 if (fntSet == NULL) {
1439 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1444 #else // not ENABLE_NLS
1446 * Find a font that matches "pattern" that is as close as
1447 * possible to the targetPxlSize. Prefer fonts that are k
1448 * pixels smaller to fonts that are k pixels larger. The
1449 * pattern must be in the X Consortium standard format,
1450 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1451 * The return value should be freed with XtFree when no
1455 FindFont (char *pattern, int targetPxlSize)
1457 char **fonts, *p, *best, *scalable, *scalableTail;
1458 int i, j, nfonts, minerr, err, pxlSize;
1460 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1462 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1463 programName, pattern);
1470 for (i=0; i<nfonts; i++) {
1473 if (*p != '-') continue;
1475 if (*p == NULLCHAR) break;
1476 if (*p++ == '-') j++;
1478 if (j < 7) continue;
1481 scalable = fonts[i];
1484 err = pxlSize - targetPxlSize;
1485 if (Abs(err) < Abs(minerr) ||
1486 (minerr > 0 && err < 0 && -err == minerr)) {
1492 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1493 /* If the error is too big and there is a scalable font,
1494 use the scalable font. */
1495 int headlen = scalableTail - scalable;
1496 p = (char *) XtMalloc(strlen(scalable) + 10);
1497 while (isdigit(*scalableTail)) scalableTail++;
1498 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1500 p = (char *) XtMalloc(strlen(best) + 2);
1501 safeStrCpy(p, best, strlen(best)+1 );
1503 if (appData.debugMode) {
1504 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1505 pattern, targetPxlSize, p);
1507 XFreeFontNames(fonts);
1513 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1516 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1522 MarkMenuItem (char *menuRef, int state)
1524 MenuItem *item = MenuNameToItem(menuRef);
1528 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1529 XtSetValues(item->handle, args, 1);
1534 EnableNamedMenuItem (char *menuRef, int state)
1536 MenuItem *item = MenuNameToItem(menuRef);
1538 if(item) XtSetSensitive(item->handle, state);
1542 EnableButtonBar (int state)
1544 XtSetSensitive(optList[W_BUTTON].handle, state);
1549 SetMenuEnables (Enables *enab)
1551 while (enab->name != NULL) {
1552 EnableNamedMenuItem(enab->name, enab->value);
1558 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1559 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1561 if(*nprms == 0) return;
1562 item = MenuNameToItem(prms[0]);
1563 if(item) ((MenuProc *) item->proc) ();
1575 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1576 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1577 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1578 dmEnables[i].piece);
1579 XtSetSensitive(entry, p != NULL || !appData.testLegality
1580 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1581 && !appData.icsActive));
1583 while (p && *p++ == dmEnables[i].piece) count++;
1584 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1586 XtSetArg(args[j], XtNlabel, label); j++;
1587 XtSetValues(entry, args, j);
1592 do_flash_delay (unsigned long msec)
1598 FlashDelay (int flash_delay)
1600 XSync(xDisplay, False);
1601 if(flash_delay) do_flash_delay(flash_delay);
1605 Fraction (int x, int start, int stop)
1607 double f = ((double) x - start)/(stop - start);
1608 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1612 static WindowPlacement wpNew;
1615 CoDrag (Widget sh, WindowPlacement *wp)
1618 int j=0, touch=0, fudge = 2;
1619 GetActualPlacement(sh, wp);
1620 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1621 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1622 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1623 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1624 if(!touch ) return; // only windows that touch co-move
1625 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1626 int heightInc = wpNew.height - wpMain.height;
1627 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1628 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1629 wp->y += fracTop * heightInc;
1630 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1631 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1632 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1633 int widthInc = wpNew.width - wpMain.width;
1634 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1635 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1636 wp->y += fracLeft * widthInc;
1637 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1638 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1640 wp->x += wpNew.x - wpMain.x;
1641 wp->y += wpNew.y - wpMain.y;
1642 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1643 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1644 XtSetArg(args[j], XtNx, wp->x); j++;
1645 XtSetArg(args[j], XtNy, wp->y); j++;
1646 XtSetValues(sh, args, j);
1650 ReSize (WindowPlacement *wp)
1653 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1654 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1655 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1656 if(sqy < sqx) sqx = sqy;
1657 if(sqx != squareSize) {
1658 squareSize = sqx; // adopt new square size
1659 CreatePNGPieces(); // make newly scaled pieces
1660 InitDrawingSizes(0, 0); // creates grid etc.
1661 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1662 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1663 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1664 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1665 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1668 static XtIntervalId delayedDragID = 0;
1677 GetActualPlacement(shellWidget, &wpNew);
1678 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1679 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1680 busy = 0; return; // false alarm
1683 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1684 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1685 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1686 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1688 DrawPosition(True, NULL);
1689 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1697 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1699 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1703 EventProc (Widget widget, caddr_t unused, XEvent *event)
1705 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1706 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1710 * event handler for redrawing the board
1713 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1715 DrawPosition(True, NULL);
1720 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1721 { // [HGM] pv: walk PV
1722 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1725 extern int savedIndex; /* gross that this is global */
1728 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1731 XawTextPosition index, dummy;
1734 XawTextGetSelectionPos(w, &index, &dummy);
1735 XtSetArg(arg, XtNstring, &val);
1736 XtGetValues(w, &arg, 1);
1737 ReplaceComment(savedIndex, val);
1738 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1739 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1743 /* Disable all user input other than deleting the window */
1744 static int frozen = 0;
1750 /* Grab by a widget that doesn't accept input */
1751 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1755 /* Undo a FreezeUI */
1759 if (!frozen) return;
1760 XtRemoveGrab(optList[W_MESSG].handle);
1768 static int oldPausing = FALSE;
1769 static GameMode oldmode = (GameMode) -1;
1772 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1774 if (pausing != oldPausing) {
1775 oldPausing = pausing;
1776 MarkMenuItem("Mode.Pause", pausing);
1778 if (appData.showButtonBar) {
1779 /* Always toggle, don't set. Previous code messes up when
1780 invoked while the button is pressed, as releasing it
1781 toggles the state again. */
1784 XtSetArg(args[0], XtNbackground, &oldbg);
1785 XtSetArg(args[1], XtNforeground, &oldfg);
1786 XtGetValues(optList[W_PAUSE].handle,
1788 XtSetArg(args[0], XtNbackground, oldfg);
1789 XtSetArg(args[1], XtNforeground, oldbg);
1791 XtSetValues(optList[W_PAUSE].handle, args, 2);
1795 wname = ModeToWidgetName(oldmode);
1796 if (wname != NULL) {
1797 MarkMenuItem(wname, False);
1799 wname = ModeToWidgetName(gameMode);
1800 if (wname != NULL) {
1801 MarkMenuItem(wname, True);
1804 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1806 /* Maybe all the enables should be handled here, not just this one */
1807 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1809 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1814 * Button/menu procedures
1817 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1818 char *selected_fen_position=NULL;
1821 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1822 Atom *type_return, XtPointer *value_return,
1823 unsigned long *length_return, int *format_return)
1825 char *selection_tmp;
1827 // if (!selected_fen_position) return False; /* should never happen */
1828 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1829 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1830 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1833 if (f == NULL) return False;
1837 selection_tmp = XtMalloc(len + 1);
1838 count = fread(selection_tmp, 1, len, f);
1841 XtFree(selection_tmp);
1844 selection_tmp[len] = NULLCHAR;
1846 /* note: since no XtSelectionDoneProc was registered, Xt will
1847 * automatically call XtFree on the value returned. So have to
1848 * make a copy of it allocated with XtMalloc */
1849 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1850 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1853 *value_return=selection_tmp;
1854 *length_return=strlen(selection_tmp);
1855 *type_return=*target;
1856 *format_return = 8; /* bits per byte */
1858 } else if (*target == XA_TARGETS(xDisplay)) {
1859 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1860 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1861 targets_tmp[1] = XA_STRING;
1862 *value_return = targets_tmp;
1863 *type_return = XA_ATOM;
1866 // This code leads to a read of value_return out of bounds on 64-bit systems.
1867 // Other code which I have seen always sets *format_return to 32 independent of
1868 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1869 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1870 *format_return = 8 * sizeof(Atom);
1871 if (*format_return > 32) {
1872 *length_return *= *format_return / 32;
1873 *format_return = 32;
1876 *format_return = 32;
1884 /* note: when called from menu all parameters are NULL, so no clue what the
1885 * Widget which was clicked on was, or what the click event was
1888 CopySomething (char *src)
1890 selected_fen_position = src;
1892 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1893 * have a notion of a position that is selected but not copied.
1894 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1896 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1898 SendPositionSelection,
1899 NULL/* lose_ownership_proc */ ,
1900 NULL/* transfer_done_proc */);
1901 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1903 SendPositionSelection,
1904 NULL/* lose_ownership_proc */ ,
1905 NULL/* transfer_done_proc */);
1908 /* function called when the data to Paste is ready */
1910 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1911 Atom *type, XtPointer value, unsigned long *len, int *format)
1914 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1915 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1916 EditPositionPasteFEN(fenstr);
1920 /* called when Paste Position button is pressed,
1921 * all parameters will be NULL */
1923 PastePositionProc ()
1925 XtGetSelectionValue(menuBarWidget,
1926 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1927 /* (XtSelectionCallbackProc) */ PastePositionCB,
1928 NULL, /* client_data passed to PastePositionCB */
1930 /* better to use the time field from the event that triggered the
1931 * call to this function, but that isn't trivial to get
1938 /* note: when called from menu all parameters are NULL, so no clue what the
1939 * Widget which was clicked on was, or what the click event was
1941 /* function called when the data to Paste is ready */
1943 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1944 Atom *type, XtPointer value, unsigned long *len, int *format)
1947 if (value == NULL || *len == 0) {
1948 return; /* nothing had been selected to copy */
1950 f = fopen(gamePasteFilename, "w");
1952 DisplayError(_("Can't open temp file"), errno);
1955 fwrite(value, 1, *len, f);
1958 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1961 /* called when Paste Game button is pressed,
1962 * all parameters will be NULL */
1966 XtGetSelectionValue(menuBarWidget,
1967 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1968 /* (XtSelectionCallbackProc) */ PasteGameCB,
1969 NULL, /* client_data passed to PasteGameCB */
1971 /* better to use the time field from the event that triggered the
1972 * call to this function, but that isn't trivial to get
1981 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1988 { // bassic primitive for determining if modifier keys are pressed
1989 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
1992 XQueryKeymap(xDisplay,keys);
1993 for(i=0; i<6; i++) {
1995 j = XKeysymToKeycode(xDisplay, codes[i]);
1996 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2002 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2006 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2007 if ( n == 1 && *buf >= 32 // printable
2008 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2009 ) BoxAutoPopUp (buf);
2013 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2014 { // [HGM] input: let up-arrow recall previous line from history
2019 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2020 { // [HGM] input: let down-arrow recall next line from history
2025 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2031 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2033 if (!TempBackwardActive) {
2034 TempBackwardActive = True;
2040 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2042 /* Check to see if triggered by a key release event for a repeating key.
2043 * If so the next queued event will be a key press of the same key at the same time */
2044 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2046 XPeekEvent(xDisplay, &next);
2047 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2048 next.xkey.keycode == event->xkey.keycode)
2052 TempBackwardActive = False;
2056 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2057 { // called as key binding
2060 if (nprms && *nprms > 0)
2064 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2070 { // called from menu
2071 ManInner(NULL, NULL, NULL, NULL);
2075 SetWindowTitle (char *text, char *title, char *icon)
2079 if (appData.titleInWindow) {
2081 XtSetArg(args[i], XtNlabel, text); i++;
2082 XtSetValues(titleWidget, args, i);
2085 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2086 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2087 XtSetValues(shellWidget, args, i);
2088 XSync(xDisplay, False);
2093 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2099 DisplayIcsInteractionTitle (String message)
2101 if (oldICSInteractionTitle == NULL) {
2102 /* Magic to find the old window title, adapted from vim */
2103 char *wina = getenv("WINDOWID");
2105 Window win = (Window) atoi(wina);
2106 Window root, parent, *children;
2107 unsigned int nchildren;
2108 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2110 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2111 if (!XQueryTree(xDisplay, win, &root, &parent,
2112 &children, &nchildren)) break;
2113 if (children) XFree((void *)children);
2114 if (parent == root || parent == 0) break;
2117 XSetErrorHandler(oldHandler);
2119 if (oldICSInteractionTitle == NULL) {
2120 oldICSInteractionTitle = "xterm";
2123 printf("\033]0;%s\007", message);
2128 XtIntervalId delayedEventTimerXID = 0;
2129 DelayedEventCallback delayedEventCallback = 0;
2134 delayedEventTimerXID = 0;
2135 delayedEventCallback();
2139 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2141 if(delayedEventTimerXID && delayedEventCallback == cb)
2142 // [HGM] alive: replace, rather than add or flush identical event
2143 XtRemoveTimeOut(delayedEventTimerXID);
2144 delayedEventCallback = cb;
2145 delayedEventTimerXID =
2146 XtAppAddTimeOut(appContext, millisec,
2147 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2150 DelayedEventCallback
2153 if (delayedEventTimerXID) {
2154 return delayedEventCallback;
2161 CancelDelayedEvent ()
2163 if (delayedEventTimerXID) {
2164 XtRemoveTimeOut(delayedEventTimerXID);
2165 delayedEventTimerXID = 0;
2169 XtIntervalId loadGameTimerXID = 0;
2172 LoadGameTimerRunning ()
2174 return loadGameTimerXID != 0;
2178 StopLoadGameTimer ()
2180 if (loadGameTimerXID != 0) {
2181 XtRemoveTimeOut(loadGameTimerXID);
2182 loadGameTimerXID = 0;
2190 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2192 loadGameTimerXID = 0;
2197 StartLoadGameTimer (long millisec)
2200 XtAppAddTimeOut(appContext, millisec,
2201 (XtTimerCallbackProc) LoadGameTimerCallback,
2205 XtIntervalId analysisClockXID = 0;
2208 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2210 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2211 || appData.icsEngineAnalyze) { // [DM]
2212 AnalysisPeriodicEvent(0);
2213 StartAnalysisClock();
2218 StartAnalysisClock ()
2221 XtAppAddTimeOut(appContext, 2000,
2222 (XtTimerCallbackProc) AnalysisClockCallback,
2226 XtIntervalId clockTimerXID = 0;
2229 ClockTimerRunning ()
2231 return clockTimerXID != 0;
2237 if (clockTimerXID != 0) {
2238 XtRemoveTimeOut(clockTimerXID);
2247 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2254 StartClockTimer (long millisec)
2257 XtAppAddTimeOut(appContext, millisec,
2258 (XtTimerCallbackProc) ClockTimerCallback,
2263 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2267 Widget w = (Widget) opt->handle;
2269 /* check for low time warning */
2270 Pixel foregroundOrWarningColor = timerForegroundPixel;
2273 appData.lowTimeWarning &&
2274 (timer / 1000) < appData.icsAlarmTime)
2275 foregroundOrWarningColor = lowTimeWarningColor;
2277 if (appData.clockMode) {
2278 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2279 XtSetArg(args[0], XtNlabel, buf);
2281 snprintf(buf, MSG_SIZ, "%s ", color);
2282 XtSetArg(args[0], XtNlabel, buf);
2287 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2288 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2290 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2291 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2294 XtSetValues(w, args, 3);
2297 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2300 SetClockIcon (int color)
2303 Pixmap pm = *clockIcons[color];
2304 if (iconPixmap != pm) {
2306 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2307 XtSetValues(shellWidget, args, 1);
2311 #define INPUT_SOURCE_BUF_SIZE 8192
2320 char buf[INPUT_SOURCE_BUF_SIZE];
2325 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2327 InputSource *is = (InputSource *) closure;
2332 if (is->lineByLine) {
2333 count = read(is->fd, is->unused,
2334 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2336 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2339 is->unused += count;
2341 while (p < is->unused) {
2342 q = memchr(p, '\n', is->unused - p);
2343 if (q == NULL) break;
2345 (is->func)(is, is->closure, p, q - p, 0);
2349 while (p < is->unused) {
2354 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2359 (is->func)(is, is->closure, is->buf, count, error);
2364 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2367 ChildProc *cp = (ChildProc *) pr;
2369 is = (InputSource *) calloc(1, sizeof(InputSource));
2370 is->lineByLine = lineByLine;
2374 is->fd = fileno(stdin);
2376 is->kind = cp->kind;
2377 is->fd = cp->fdFrom;
2380 is->unused = is->buf;
2383 is->xid = XtAppAddInput(appContext, is->fd,
2384 (XtPointer) (XtInputReadMask),
2385 (XtInputCallbackProc) DoInputCallback,
2387 is->closure = closure;
2388 return (InputSourceRef) is;
2392 RemoveInputSource (InputSourceRef isr)
2394 InputSource *is = (InputSource *) isr;
2396 if (is->xid == 0) return;
2397 XtRemoveInput(is->xid);
2403 static Boolean frameWaiting;
2406 FrameAlarm (int sig)
2408 frameWaiting = False;
2409 /* In case System-V style signals. Needed?? */
2410 signal(SIGALRM, FrameAlarm);
2414 FrameDelay (int time)
2416 struct itimerval delay;
2418 XSync(xDisplay, False);
2421 frameWaiting = True;
2422 signal(SIGALRM, FrameAlarm);
2423 delay.it_interval.tv_sec =
2424 delay.it_value.tv_sec = time / 1000;
2425 delay.it_interval.tv_usec =
2426 delay.it_value.tv_usec = (time % 1000) * 1000;
2427 setitimer(ITIMER_REAL, &delay, NULL);
2428 while (frameWaiting) pause();
2429 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2430 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2431 setitimer(ITIMER_REAL, &delay, NULL);
2438 FrameDelay (int time)
2440 XSync(xDisplay, False);
2442 usleep(time * 1000);
2448 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2450 char buf[MSG_SIZ], *logoName = buf;
2451 if(appData.logo[n][0]) {
2452 logoName = appData.logo[n];
2453 } else if(appData.autoLogo) {
2454 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2455 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2456 } else if(appData.directory[n] && appData.directory[n][0]) {
2457 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2461 { ASSIGN(cps->programLogo, logoName); }
2465 UpdateLogos (int displ)
2467 if(optList[W_WHITE-1].handle == NULL) return;
2468 LoadLogo(&first, 0, 0);
2469 LoadLogo(&second, 1, appData.icsActive);
2470 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);