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:
830 GenerateGlobalTranslationTable (void)
832 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
840 /* loop over all menu entries */
841 for( i=0; menuBar[i].mi ; i++)
844 for(j=0; mi[j].proc; j++)
852 char *key,*test, *mods;
854 /* check for Ctrl/Alt */
855 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
856 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
857 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
859 /* remove all <...> */
860 test = strrchr(mi[j].accel, '>');
862 key = strdup(mi[j].accel);
864 key = strdup(++test); // remove ">"
866 /* instead of shift X11 uses the uppercase letter directly*/
867 if (shift && strlen(key)==1 )
869 *key = toupper(*key);
873 /* handle some special cases which have different names in X11 */
874 if ( strncmp(key, "Page_Down", 9) == 0 )
879 else if ( strncmp(key, "Page_Up", 7) == 0 )
885 /* create string of mods */
887 mods = strdup("Ctrl ");
893 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
894 strncat(mods, "Meta ", 5);
899 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
900 strncat(mods, "Shift ", 6);
903 // remove trailing space
904 if( isspace(mods[strlen(mods)-1]) )
905 mods[strlen(mods)-1]='\0';
907 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
908 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
909 char *name = malloc(namesize+1);
910 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
912 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
913 char *buffer = malloc(buffersize+1);
914 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
916 /* add string to the output */
917 output = realloc(output, strlen(output) + strlen(buffer)+1);
918 strncat(output, buffer, strlen(buffer));
937 ArgDescriptor *q, *p = argDescriptors+5;
938 printf("\nXBoard accepts the following options:\n"
939 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
940 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
941 " SIZE = board-size spec(s)\n"
942 " Within parentheses are short forms, or options to set to true or false.\n"
943 " Persistent options (saved in the settings file) are marked with *)\n\n");
945 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
946 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
947 if(p->save) strcat(buf+len, "*");
948 for(q=p+1; q->argLoc == p->argLoc; q++) {
949 if(q->argName[0] == '-') continue;
950 strcat(buf+len, q == p+1 ? " (" : " ");
951 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
953 if(q != p+1) strcat(buf+len, ")");
955 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
958 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
962 SlaveResize (Option *opt)
967 main (int argc, char **argv)
969 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
970 XSetWindowAttributes window_attributes;
972 Dimension boardWidth, boardHeight, w, h;
974 int forceMono = False;
976 srandom(time(0)); // [HGM] book: make random truly random
978 setbuf(stdout, NULL);
979 setbuf(stderr, NULL);
982 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
983 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
987 if(argc > 1 && !strcmp(argv[1], "--help" )) {
992 programName = strrchr(argv[0], '/');
993 if (programName == NULL)
994 programName = argv[0];
999 XtSetLanguageProc(NULL, NULL, NULL);
1000 if (appData.debugMode) {
1001 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1004 bindtextdomain(PACKAGE, LOCALEDIR);
1005 textdomain(PACKAGE);
1008 appData.boardSize = "";
1009 InitAppData(ConvertToLine(argc, argv));
1011 if (p == NULL) p = "/tmp";
1012 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1013 gameCopyFilename = (char*) malloc(i);
1014 gamePasteFilename = (char*) malloc(i);
1015 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1016 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1018 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1019 static char buf[MSG_SIZ];
1020 EscapeExpand(buf, appData.firstInitString);
1021 appData.firstInitString = strdup(buf);
1022 EscapeExpand(buf, appData.secondInitString);
1023 appData.secondInitString = strdup(buf);
1024 EscapeExpand(buf, appData.firstComputerString);
1025 appData.firstComputerString = strdup(buf);
1026 EscapeExpand(buf, appData.secondComputerString);
1027 appData.secondComputerString = strdup(buf);
1030 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1033 if (chdir(chessDir) != 0) {
1034 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1040 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1041 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1042 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1043 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1046 setbuf(debugFP, NULL);
1049 /* [HGM,HR] make sure board size is acceptable */
1050 if(appData.NrFiles > BOARD_FILES ||
1051 appData.NrRanks > BOARD_RANKS )
1052 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1055 /* This feature does not work; animation needs a rewrite */
1056 appData.highlightDragging = FALSE;
1060 gameInfo.variant = StringToVariant(appData.variant);
1061 InitPosition(FALSE);
1064 XtAppInitialize(&appContext, "XBoard", shellOptions,
1065 XtNumber(shellOptions),
1066 &argc, argv, xboardResources, NULL, 0);
1068 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1069 clientResources, XtNumber(clientResources),
1072 xDisplay = XtDisplay(shellWidget);
1073 xScreen = DefaultScreen(xDisplay);
1074 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1077 * determine size, based on supplied or remembered -size, or screen size
1079 if (isdigit(appData.boardSize[0])) {
1080 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1081 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1082 &fontPxlSize, &smallLayout, &tinyLayout);
1084 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1085 programName, appData.boardSize);
1089 /* Find some defaults; use the nearest known size */
1090 SizeDefaults *szd, *nearest;
1091 int distance = 99999;
1092 nearest = szd = sizeDefaults;
1093 while (szd->name != NULL) {
1094 if (abs(szd->squareSize - squareSize) < distance) {
1096 distance = abs(szd->squareSize - squareSize);
1097 if (distance == 0) break;
1101 if (i < 2) lineGap = nearest->lineGap;
1102 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1103 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1104 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1105 if (i < 6) smallLayout = nearest->smallLayout;
1106 if (i < 7) tinyLayout = nearest->tinyLayout;
1109 SizeDefaults *szd = sizeDefaults;
1110 if (*appData.boardSize == NULLCHAR) {
1111 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1112 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1115 if (szd->name == NULL) szd--;
1116 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1118 while (szd->name != NULL &&
1119 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1120 if (szd->name == NULL) {
1121 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1122 programName, appData.boardSize);
1126 squareSize = szd->squareSize;
1127 lineGap = szd->lineGap;
1128 clockFontPxlSize = szd->clockFontPxlSize;
1129 coordFontPxlSize = szd->coordFontPxlSize;
1130 fontPxlSize = szd->fontPxlSize;
1131 smallLayout = szd->smallLayout;
1132 tinyLayout = szd->tinyLayout;
1133 // [HGM] font: use defaults from settings file if available and not overruled
1136 defaultLineGap = lineGap;
1137 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1139 /* [HR] height treated separately (hacked) */
1140 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1141 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1144 * Determine what fonts to use.
1146 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1149 * Detect if there are not enough colors available and adapt.
1151 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1152 appData.monoMode = True;
1155 forceMono = MakeColors();
1158 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1160 appData.monoMode = True;
1163 if (appData.monoMode && appData.debugMode) {
1164 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1165 (unsigned long) XWhitePixel(xDisplay, xScreen),
1166 (unsigned long) XBlackPixel(xDisplay, xScreen));
1169 ParseIcsTextColors();
1171 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1177 layoutName = "tinyLayout";
1178 } else if (smallLayout) {
1179 layoutName = "smallLayout";
1181 layoutName = "normalLayout";
1184 optList = BoardPopUp(squareSize, lineGap, (void*)
1190 InitDrawingHandle(optList + W_BOARD);
1191 currBoard = &optList[W_BOARD];
1192 boardWidget = optList[W_BOARD].handle;
1193 menuBarWidget = optList[W_MENU].handle;
1194 dropMenu = optList[W_DROP].handle;
1195 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1196 formWidget = XtParent(boardWidget);
1197 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1198 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1199 XtGetValues(optList[W_WHITE].handle, args, 2);
1200 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1201 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1202 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1203 XtGetValues(optList[W_PAUSE].handle, args, 2);
1206 xBoardWindow = XtWindow(boardWidget);
1208 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1209 // not need to go into InitDrawingSizes().
1212 * Create X checkmark bitmap and initialize option menu checks.
1214 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1215 checkmark_bits, checkmark_width, checkmark_height);
1221 ReadBitmap(&wIconPixmap, "icon_white.bm",
1222 icon_white_bits, icon_white_width, icon_white_height);
1223 ReadBitmap(&bIconPixmap, "icon_black.bm",
1224 icon_black_bits, icon_black_width, icon_black_height);
1225 iconPixmap = wIconPixmap;
1227 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1228 XtSetValues(shellWidget, args, i);
1231 * Create a cursor for the board widget.
1233 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1234 XChangeWindowAttributes(xDisplay, xBoardWindow,
1235 CWCursor, &window_attributes);
1238 * Inhibit shell resizing.
1240 shellArgs[0].value = (XtArgVal) &w;
1241 shellArgs[1].value = (XtArgVal) &h;
1242 XtGetValues(shellWidget, shellArgs, 2);
1243 shellArgs[4].value = shellArgs[2].value = w;
1244 shellArgs[5].value = shellArgs[3].value = h;
1245 // XtSetValues(shellWidget, &shellArgs[2], 4);
1246 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1247 marginH = h - boardHeight;
1249 CatchDeleteWindow(shellWidget, "QuitProc");
1254 if(appData.logoSize)
1255 { // locate and read user logo
1257 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1258 ASSIGN(userLogo, buf);
1261 if (appData.animate || appData.animateDragging)
1265 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1267 XtAugmentTranslations(formWidget,
1268 XtParseTranslationTable(globalTranslations));
1269 XtAugmentTranslations(formWidget,
1270 XtParseTranslationTable(TranslationsTableMenus));
1272 XtAddEventHandler(formWidget, KeyPressMask, False,
1273 (XtEventHandler) MoveTypeInProc, NULL);
1274 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1275 (XtEventHandler) EventProc, NULL);
1277 /* [AS] Restore layout */
1278 if( wpMoveHistory.visible ) {
1282 if( wpEvalGraph.visible )
1287 if( wpEngineOutput.visible ) {
1288 EngineOutputPopUp();
1293 if (errorExitStatus == -1) {
1294 if (appData.icsActive) {
1295 /* We now wait until we see "login:" from the ICS before
1296 sending the logon script (problems with timestamp otherwise) */
1297 /*ICSInitScript();*/
1298 if (appData.icsInputBox) ICSInputBoxPopUp();
1302 signal(SIGWINCH, TermSizeSigHandler);
1304 signal(SIGINT, IntSigHandler);
1305 signal(SIGTERM, IntSigHandler);
1306 if (*appData.cmailGameName != NULLCHAR) {
1307 signal(SIGUSR1, CmailSigHandler);
1311 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1314 // XtSetKeyboardFocus(shellWidget, formWidget);
1315 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1317 XtAppMainLoop(appContext);
1318 if (appData.debugMode) fclose(debugFP); // [DM] debug
1323 TermSizeSigHandler (int sig)
1329 IntSigHandler (int sig)
1335 CmailSigHandler (int sig)
1340 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1342 /* Activate call-back function CmailSigHandlerCallBack() */
1343 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1345 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1349 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1352 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1354 /**** end signal code ****/
1357 #define Abs(n) ((n)<0 ? -(n) : (n))
1361 InsertPxlSize (char *pattern, int targetPxlSize)
1363 char *base_fnt_lst, strInt[12], *p, *q;
1364 int alternatives, i, len, strIntLen;
1367 * Replace the "*" (if present) in the pixel-size slot of each
1368 * alternative with the targetPxlSize.
1372 while ((p = strchr(p, ',')) != NULL) {
1376 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1377 strIntLen = strlen(strInt);
1378 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1382 while (alternatives--) {
1383 char *comma = strchr(p, ',');
1384 for (i=0; i<14; i++) {
1385 char *hyphen = strchr(p, '-');
1387 if (comma && hyphen > comma) break;
1388 len = hyphen + 1 - p;
1389 if (i == 7 && *p == '*' && len == 2) {
1391 memcpy(q, strInt, strIntLen);
1401 len = comma + 1 - p;
1408 return base_fnt_lst;
1412 CreateFontSet (char *base_fnt_lst)
1415 char **missing_list;
1419 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1420 &missing_list, &missing_count, &def_string);
1421 if (appData.debugMode) {
1423 XFontStruct **font_struct_list;
1424 char **font_name_list;
1425 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1427 fprintf(debugFP, " got list %s, locale %s\n",
1428 XBaseFontNameListOfFontSet(fntSet),
1429 XLocaleOfFontSet(fntSet));
1430 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1431 for (i = 0; i < count; i++) {
1432 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1435 for (i = 0; i < missing_count; i++) {
1436 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1439 if (fntSet == NULL) {
1440 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1445 #else // not ENABLE_NLS
1447 * Find a font that matches "pattern" that is as close as
1448 * possible to the targetPxlSize. Prefer fonts that are k
1449 * pixels smaller to fonts that are k pixels larger. The
1450 * pattern must be in the X Consortium standard format,
1451 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1452 * The return value should be freed with XtFree when no
1456 FindFont (char *pattern, int targetPxlSize)
1458 char **fonts, *p, *best, *scalable, *scalableTail;
1459 int i, j, nfonts, minerr, err, pxlSize;
1461 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1463 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1464 programName, pattern);
1471 for (i=0; i<nfonts; i++) {
1474 if (*p != '-') continue;
1476 if (*p == NULLCHAR) break;
1477 if (*p++ == '-') j++;
1479 if (j < 7) continue;
1482 scalable = fonts[i];
1485 err = pxlSize - targetPxlSize;
1486 if (Abs(err) < Abs(minerr) ||
1487 (minerr > 0 && err < 0 && -err == minerr)) {
1493 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1494 /* If the error is too big and there is a scalable font,
1495 use the scalable font. */
1496 int headlen = scalableTail - scalable;
1497 p = (char *) XtMalloc(strlen(scalable) + 10);
1498 while (isdigit(*scalableTail)) scalableTail++;
1499 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1501 p = (char *) XtMalloc(strlen(best) + 2);
1502 safeStrCpy(p, best, strlen(best)+1 );
1504 if (appData.debugMode) {
1505 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1506 pattern, targetPxlSize, p);
1508 XFreeFontNames(fonts);
1514 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1517 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1523 MarkMenuItem (char *menuRef, int state)
1525 MenuItem *item = MenuNameToItem(menuRef);
1529 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1530 XtSetValues(item->handle, args, 1);
1535 EnableNamedMenuItem (char *menuRef, int state)
1537 MenuItem *item = MenuNameToItem(menuRef);
1539 if(item) XtSetSensitive(item->handle, state);
1543 EnableButtonBar (int state)
1545 XtSetSensitive(optList[W_BUTTON].handle, state);
1550 SetMenuEnables (Enables *enab)
1552 while (enab->name != NULL) {
1553 EnableNamedMenuItem(enab->name, enab->value);
1559 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1560 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1562 if(*nprms == 0) return;
1563 item = MenuNameToItem(prms[0]);
1564 if(item) ((MenuProc *) item->proc) ();
1576 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1577 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1578 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1579 dmEnables[i].piece);
1580 XtSetSensitive(entry, p != NULL || !appData.testLegality
1581 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1582 && !appData.icsActive));
1584 while (p && *p++ == dmEnables[i].piece) count++;
1585 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1587 XtSetArg(args[j], XtNlabel, label); j++;
1588 XtSetValues(entry, args, j);
1593 do_flash_delay (unsigned long msec)
1599 FlashDelay (int flash_delay)
1601 XSync(xDisplay, False);
1602 if(flash_delay) do_flash_delay(flash_delay);
1606 Fraction (int x, int start, int stop)
1608 double f = ((double) x - start)/(stop - start);
1609 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1613 static WindowPlacement wpNew;
1616 CoDrag (Widget sh, WindowPlacement *wp)
1619 int j=0, touch=0, fudge = 2;
1620 GetActualPlacement(sh, wp);
1621 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1622 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1623 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1624 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1625 if(!touch ) return; // only windows that touch co-move
1626 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1627 int heightInc = wpNew.height - wpMain.height;
1628 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1629 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1630 wp->y += fracTop * heightInc;
1631 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1632 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1633 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1634 int widthInc = wpNew.width - wpMain.width;
1635 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1636 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1637 wp->y += fracLeft * widthInc;
1638 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1639 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1641 wp->x += wpNew.x - wpMain.x;
1642 wp->y += wpNew.y - wpMain.y;
1643 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1644 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1645 XtSetArg(args[j], XtNx, wp->x); j++;
1646 XtSetArg(args[j], XtNy, wp->y); j++;
1647 XtSetValues(sh, args, j);
1651 ReSize (WindowPlacement *wp)
1654 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1655 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1656 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1657 if(sqy < sqx) sqx = sqy;
1658 if(sqx != squareSize) {
1659 squareSize = sqx; // adopt new square size
1660 CreatePNGPieces(); // make newly scaled pieces
1661 InitDrawingSizes(0, 0); // creates grid etc.
1662 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1663 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1664 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1665 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1666 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1669 static XtIntervalId delayedDragID = 0;
1678 GetActualPlacement(shellWidget, &wpNew);
1679 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1680 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1681 busy = 0; return; // false alarm
1684 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1685 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1686 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1687 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1689 DrawPosition(True, NULL);
1690 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1698 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1700 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1704 EventProc (Widget widget, caddr_t unused, XEvent *event)
1706 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1707 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1711 * event handler for redrawing the board
1714 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1716 DrawPosition(True, NULL);
1721 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1722 { // [HGM] pv: walk PV
1723 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1726 extern int savedIndex; /* gross that this is global */
1729 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1732 XawTextPosition index, dummy;
1735 XawTextGetSelectionPos(w, &index, &dummy);
1736 XtSetArg(arg, XtNstring, &val);
1737 XtGetValues(w, &arg, 1);
1738 ReplaceComment(savedIndex, val);
1739 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1740 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1744 /* Disable all user input other than deleting the window */
1745 static int frozen = 0;
1751 /* Grab by a widget that doesn't accept input */
1752 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1756 /* Undo a FreezeUI */
1760 if (!frozen) return;
1761 XtRemoveGrab(optList[W_MESSG].handle);
1769 static int oldPausing = FALSE;
1770 static GameMode oldmode = (GameMode) -1;
1773 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1775 if (pausing != oldPausing) {
1776 oldPausing = pausing;
1777 MarkMenuItem("Mode.Pause", pausing);
1779 if (appData.showButtonBar) {
1780 /* Always toggle, don't set. Previous code messes up when
1781 invoked while the button is pressed, as releasing it
1782 toggles the state again. */
1785 XtSetArg(args[0], XtNbackground, &oldbg);
1786 XtSetArg(args[1], XtNforeground, &oldfg);
1787 XtGetValues(optList[W_PAUSE].handle,
1789 XtSetArg(args[0], XtNbackground, oldfg);
1790 XtSetArg(args[1], XtNforeground, oldbg);
1792 XtSetValues(optList[W_PAUSE].handle, args, 2);
1796 wname = ModeToWidgetName(oldmode);
1797 if (wname != NULL) {
1798 MarkMenuItem(wname, False);
1800 wname = ModeToWidgetName(gameMode);
1801 if (wname != NULL) {
1802 MarkMenuItem(wname, True);
1805 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1807 /* Maybe all the enables should be handled here, not just this one */
1808 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1810 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1815 * Button/menu procedures
1818 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1819 char *selected_fen_position=NULL;
1822 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1823 Atom *type_return, XtPointer *value_return,
1824 unsigned long *length_return, int *format_return)
1826 char *selection_tmp;
1828 // if (!selected_fen_position) return False; /* should never happen */
1829 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1830 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1831 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1834 if (f == NULL) return False;
1838 selection_tmp = XtMalloc(len + 1);
1839 count = fread(selection_tmp, 1, len, f);
1842 XtFree(selection_tmp);
1845 selection_tmp[len] = NULLCHAR;
1847 /* note: since no XtSelectionDoneProc was registered, Xt will
1848 * automatically call XtFree on the value returned. So have to
1849 * make a copy of it allocated with XtMalloc */
1850 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1851 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1854 *value_return=selection_tmp;
1855 *length_return=strlen(selection_tmp);
1856 *type_return=*target;
1857 *format_return = 8; /* bits per byte */
1859 } else if (*target == XA_TARGETS(xDisplay)) {
1860 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1861 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1862 targets_tmp[1] = XA_STRING;
1863 *value_return = targets_tmp;
1864 *type_return = XA_ATOM;
1867 // This code leads to a read of value_return out of bounds on 64-bit systems.
1868 // Other code which I have seen always sets *format_return to 32 independent of
1869 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1870 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1871 *format_return = 8 * sizeof(Atom);
1872 if (*format_return > 32) {
1873 *length_return *= *format_return / 32;
1874 *format_return = 32;
1877 *format_return = 32;
1885 /* note: when called from menu all parameters are NULL, so no clue what the
1886 * Widget which was clicked on was, or what the click event was
1889 CopySomething (char *src)
1891 selected_fen_position = src;
1893 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1894 * have a notion of a position that is selected but not copied.
1895 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1897 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1899 SendPositionSelection,
1900 NULL/* lose_ownership_proc */ ,
1901 NULL/* transfer_done_proc */);
1902 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1904 SendPositionSelection,
1905 NULL/* lose_ownership_proc */ ,
1906 NULL/* transfer_done_proc */);
1909 /* function called when the data to Paste is ready */
1911 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1912 Atom *type, XtPointer value, unsigned long *len, int *format)
1915 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1916 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1917 EditPositionPasteFEN(fenstr);
1921 /* called when Paste Position button is pressed,
1922 * all parameters will be NULL */
1924 PastePositionProc ()
1926 XtGetSelectionValue(menuBarWidget,
1927 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1928 /* (XtSelectionCallbackProc) */ PastePositionCB,
1929 NULL, /* client_data passed to PastePositionCB */
1931 /* better to use the time field from the event that triggered the
1932 * call to this function, but that isn't trivial to get
1939 /* note: when called from menu all parameters are NULL, so no clue what the
1940 * Widget which was clicked on was, or what the click event was
1942 /* function called when the data to Paste is ready */
1944 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1945 Atom *type, XtPointer value, unsigned long *len, int *format)
1948 if (value == NULL || *len == 0) {
1949 return; /* nothing had been selected to copy */
1951 f = fopen(gamePasteFilename, "w");
1953 DisplayError(_("Can't open temp file"), errno);
1956 fwrite(value, 1, *len, f);
1959 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1962 /* called when Paste Game button is pressed,
1963 * all parameters will be NULL */
1967 XtGetSelectionValue(menuBarWidget,
1968 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1969 /* (XtSelectionCallbackProc) */ PasteGameCB,
1970 NULL, /* client_data passed to PasteGameCB */
1972 /* better to use the time field from the event that triggered the
1973 * call to this function, but that isn't trivial to get
1982 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1989 { // bassic primitive for determining if modifier keys are pressed
1990 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
1993 XQueryKeymap(xDisplay,keys);
1994 for(i=0; i<6; i++) {
1996 j = XKeysymToKeycode(xDisplay, codes[i]);
1997 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2003 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2007 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2008 if ( n == 1 && *buf >= 32 // printable
2009 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2010 ) BoxAutoPopUp (buf);
2014 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2015 { // [HGM] input: let up-arrow recall previous line from history
2020 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2021 { // [HGM] input: let down-arrow recall next line from history
2026 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2032 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2034 if (!TempBackwardActive) {
2035 TempBackwardActive = True;
2041 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2043 /* Check to see if triggered by a key release event for a repeating key.
2044 * If so the next queued event will be a key press of the same key at the same time */
2045 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2047 XPeekEvent(xDisplay, &next);
2048 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2049 next.xkey.keycode == event->xkey.keycode)
2053 TempBackwardActive = False;
2057 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2058 { // called as key binding
2061 if (nprms && *nprms > 0)
2065 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2071 { // called from menu
2072 ManInner(NULL, NULL, NULL, NULL);
2076 SetWindowTitle (char *text, char *title, char *icon)
2080 if (appData.titleInWindow) {
2082 XtSetArg(args[i], XtNlabel, text); i++;
2083 XtSetValues(titleWidget, args, i);
2086 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2087 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2088 XtSetValues(shellWidget, args, i);
2089 XSync(xDisplay, False);
2094 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2100 DisplayIcsInteractionTitle (String message)
2102 if (oldICSInteractionTitle == NULL) {
2103 /* Magic to find the old window title, adapted from vim */
2104 char *wina = getenv("WINDOWID");
2106 Window win = (Window) atoi(wina);
2107 Window root, parent, *children;
2108 unsigned int nchildren;
2109 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2111 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2112 if (!XQueryTree(xDisplay, win, &root, &parent,
2113 &children, &nchildren)) break;
2114 if (children) XFree((void *)children);
2115 if (parent == root || parent == 0) break;
2118 XSetErrorHandler(oldHandler);
2120 if (oldICSInteractionTitle == NULL) {
2121 oldICSInteractionTitle = "xterm";
2124 printf("\033]0;%s\007", message);
2129 XtIntervalId delayedEventTimerXID = 0;
2130 DelayedEventCallback delayedEventCallback = 0;
2135 delayedEventTimerXID = 0;
2136 delayedEventCallback();
2140 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2142 if(delayedEventTimerXID && delayedEventCallback == cb)
2143 // [HGM] alive: replace, rather than add or flush identical event
2144 XtRemoveTimeOut(delayedEventTimerXID);
2145 delayedEventCallback = cb;
2146 delayedEventTimerXID =
2147 XtAppAddTimeOut(appContext, millisec,
2148 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2151 DelayedEventCallback
2154 if (delayedEventTimerXID) {
2155 return delayedEventCallback;
2162 CancelDelayedEvent ()
2164 if (delayedEventTimerXID) {
2165 XtRemoveTimeOut(delayedEventTimerXID);
2166 delayedEventTimerXID = 0;
2170 XtIntervalId loadGameTimerXID = 0;
2173 LoadGameTimerRunning ()
2175 return loadGameTimerXID != 0;
2179 StopLoadGameTimer ()
2181 if (loadGameTimerXID != 0) {
2182 XtRemoveTimeOut(loadGameTimerXID);
2183 loadGameTimerXID = 0;
2191 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2193 loadGameTimerXID = 0;
2198 StartLoadGameTimer (long millisec)
2201 XtAppAddTimeOut(appContext, millisec,
2202 (XtTimerCallbackProc) LoadGameTimerCallback,
2206 XtIntervalId analysisClockXID = 0;
2209 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2211 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2212 || appData.icsEngineAnalyze) { // [DM]
2213 AnalysisPeriodicEvent(0);
2214 StartAnalysisClock();
2219 StartAnalysisClock ()
2222 XtAppAddTimeOut(appContext, 2000,
2223 (XtTimerCallbackProc) AnalysisClockCallback,
2227 XtIntervalId clockTimerXID = 0;
2230 ClockTimerRunning ()
2232 return clockTimerXID != 0;
2238 if (clockTimerXID != 0) {
2239 XtRemoveTimeOut(clockTimerXID);
2248 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2255 StartClockTimer (long millisec)
2258 XtAppAddTimeOut(appContext, millisec,
2259 (XtTimerCallbackProc) ClockTimerCallback,
2264 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2268 Widget w = (Widget) opt->handle;
2270 /* check for low time warning */
2271 Pixel foregroundOrWarningColor = timerForegroundPixel;
2274 appData.lowTimeWarning &&
2275 (timer / 1000) < appData.icsAlarmTime)
2276 foregroundOrWarningColor = lowTimeWarningColor;
2278 if (appData.clockMode) {
2279 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2280 XtSetArg(args[0], XtNlabel, buf);
2282 snprintf(buf, MSG_SIZ, "%s ", color);
2283 XtSetArg(args[0], XtNlabel, buf);
2288 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2289 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2291 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2292 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2295 XtSetValues(w, args, 3);
2298 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2301 SetClockIcon (int color)
2304 Pixmap pm = *clockIcons[color];
2305 if (iconPixmap != pm) {
2307 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2308 XtSetValues(shellWidget, args, 1);
2312 #define INPUT_SOURCE_BUF_SIZE 8192
2321 char buf[INPUT_SOURCE_BUF_SIZE];
2326 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2328 InputSource *is = (InputSource *) closure;
2333 if (is->lineByLine) {
2334 count = read(is->fd, is->unused,
2335 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2337 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2340 is->unused += count;
2342 while (p < is->unused) {
2343 q = memchr(p, '\n', is->unused - p);
2344 if (q == NULL) break;
2346 (is->func)(is, is->closure, p, q - p, 0);
2350 while (p < is->unused) {
2355 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2360 (is->func)(is, is->closure, is->buf, count, error);
2365 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2368 ChildProc *cp = (ChildProc *) pr;
2370 is = (InputSource *) calloc(1, sizeof(InputSource));
2371 is->lineByLine = lineByLine;
2375 is->fd = fileno(stdin);
2377 is->kind = cp->kind;
2378 is->fd = cp->fdFrom;
2381 is->unused = is->buf;
2384 is->xid = XtAppAddInput(appContext, is->fd,
2385 (XtPointer) (XtInputReadMask),
2386 (XtInputCallbackProc) DoInputCallback,
2388 is->closure = closure;
2389 return (InputSourceRef) is;
2393 RemoveInputSource (InputSourceRef isr)
2395 InputSource *is = (InputSource *) isr;
2397 if (is->xid == 0) return;
2398 XtRemoveInput(is->xid);
2404 static Boolean frameWaiting;
2407 FrameAlarm (int sig)
2409 frameWaiting = False;
2410 /* In case System-V style signals. Needed?? */
2411 signal(SIGALRM, FrameAlarm);
2415 FrameDelay (int time)
2417 struct itimerval delay;
2419 XSync(xDisplay, False);
2422 frameWaiting = True;
2423 signal(SIGALRM, FrameAlarm);
2424 delay.it_interval.tv_sec =
2425 delay.it_value.tv_sec = time / 1000;
2426 delay.it_interval.tv_usec =
2427 delay.it_value.tv_usec = (time % 1000) * 1000;
2428 setitimer(ITIMER_REAL, &delay, NULL);
2429 while (frameWaiting) pause();
2430 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2431 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2432 setitimer(ITIMER_REAL, &delay, NULL);
2439 FrameDelay (int time)
2441 XSync(xDisplay, False);
2443 usleep(time * 1000);
2449 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2451 char buf[MSG_SIZ], *logoName = buf;
2452 if(appData.logo[n][0]) {
2453 logoName = appData.logo[n];
2454 } else if(appData.autoLogo) {
2455 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2456 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2457 } else if(appData.directory[n] && appData.directory[n][0]) {
2458 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2462 { ASSIGN(cps->programLogo, logoName); }
2466 UpdateLogos (int displ)
2468 if(optList[W_WHITE-1].handle == NULL) return;
2469 LoadLogo(&first, 0, 0);
2470 LoadLogo(&second, 1, appData.icsActive);
2471 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);