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"
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
223 int main P((int argc, char **argv));
224 RETSIGTYPE CmailSigHandler P((int sig));
225 RETSIGTYPE IntSigHandler P((int sig));
226 RETSIGTYPE TermSizeSigHandler P((int sig));
227 Widget CreateMenuBar P((Menu *mb, int boardWidth));
229 char *InsertPxlSize P((char *pattern, int targetPxlSize));
230 XFontSet CreateFontSet P((char *base_fnt_lst));
232 char *FindFont P((char *pattern, int targetPxlSize));
234 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
235 u_int wreq, u_int hreq));
236 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
237 void DelayedDrag P((void));
238 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
239 void HandlePV P((Widget w, XEvent * event,
240 String * params, Cardinal * nParams));
241 void DrawPositionProc P((Widget w, XEvent *event,
242 String *prms, Cardinal *nprms));
243 void CommentClick P((Widget w, XEvent * event,
244 String * params, Cardinal * nParams));
245 void ICSInputBoxPopUp P((void));
246 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
247 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
248 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
249 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
250 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
251 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
252 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
253 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
254 Boolean TempBackwardActive = False;
255 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 void DisplayMove P((int moveNumber));
257 void update_ics_width P(());
258 int CopyMemoProc P(());
261 * XBoard depends on Xt R4 or higher
263 int xtVersion = XtSpecificationRelease;
268 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
269 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
270 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
271 Option *optList; // contains all widgets of main window
273 XFontSet fontSet, clockFontSet;
276 XFontStruct *clockFontStruct;
278 Font coordFontID, countFontID;
279 XFontStruct *coordFontStruct, *countFontStruct;
280 XtAppContext appContext;
283 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
285 Position commentX = -1, commentY = -1;
286 Dimension commentW, commentH;
287 typedef unsigned int BoardSize;
289 Boolean chessProgram;
291 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
292 int smallLayout = 0, tinyLayout = 0,
293 marginW, marginH, // [HGM] for run-time resizing
294 fromX = -1, fromY = -1, toX, toY, commentUp = False,
295 errorExitStatus = -1, defaultLineGap;
296 Dimension textHeight;
297 Pixel timerForegroundPixel, timerBackgroundPixel;
298 Pixel buttonForegroundPixel, buttonBackgroundPixel;
299 char *chessDir, *programName, *programVersion;
300 Boolean alwaysOnTop = False;
301 char *icsTextMenuString;
303 char *firstChessProgramNames;
304 char *secondChessProgramNames;
306 WindowPlacement wpMain;
307 WindowPlacement wpConsole;
308 WindowPlacement wpComment;
309 WindowPlacement wpMoveHistory;
310 WindowPlacement wpEvalGraph;
311 WindowPlacement wpEngineOutput;
312 WindowPlacement wpGameList;
313 WindowPlacement wpTags;
314 WindowPlacement wpDualBoard;
317 /* This magic number is the number of intermediate frames used
318 in each half of the animation. For short moves it's reduced
319 by 1. The total number of frames will be factor * 2 + 1. */
322 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
329 DropMenuEnables dmEnables[] = {
346 XtResource clientResources[] = {
347 { "flashCount", "flashCount", XtRInt, sizeof(int),
348 XtOffset(AppDataPtr, flashCount), XtRImmediate,
349 (XtPointer) FLASH_COUNT },
352 XrmOptionDescRec shellOptions[] = {
353 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
354 { "-flash", "flashCount", XrmoptionNoArg, "3" },
355 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
358 XtActionsRec boardActions[] = {
359 { "DrawPosition", DrawPositionProc },
360 { "HandlePV", HandlePV },
361 { "SelectPV", SelectPV },
362 { "StopPV", StopPV },
363 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
364 { "QuitProc", QuitWrapper },
365 { "ManProc", ManInner },
366 { "TempBackwardProc", TempBackwardProc },
367 { "TempForwardProc", TempForwardProc },
368 { "CommentClick", (XtActionProc) CommentClick },
369 { "GenericPopDown", (XtActionProc) GenericPopDown },
370 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
371 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
372 { "SelectMove", (XtActionProc) SelectMoveX },
373 { "LoadSelectedProc", LoadSelectedProc },
374 { "SetFilterProc", SetFilterProc },
375 { "TypeInProc", TypeInProc },
376 { "EnterKeyProc", EnterKeyProc },
377 { "UpKeyProc", UpKeyProc },
378 { "DownKeyProc", DownKeyProc },
379 { "WheelProc", WheelProc },
380 { "TabProc", TabProc },
383 char globalTranslations[] =
384 ":Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
385 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
386 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
387 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
388 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
389 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
390 :<Key>Pause: MenuItem(Mode.Pause) \n \
391 :Ctrl<Key>d: MenuItem(DebugProc) \n \
392 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
393 :<Key>Left: MenuItem(Edit.Backward) \n \
394 :<Key>Right: MenuItem(Edit.Forward) \n \
395 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
396 #ifndef OPTIONSDIALOG
398 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
399 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
400 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
401 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
402 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
405 :<KeyDown>Return: TempBackwardProc() \n \
406 :<KeyUp>Return: TempForwardProc() \n";
408 char ICSInputTranslations[] =
409 "<Key>Up: UpKeyProc() \n "
410 "<Key>Down: DownKeyProc() \n "
411 "<Key>Return: EnterKeyProc() \n";
413 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
414 // as the widget is destroyed before the up-click can call extend-end
415 char commentTranslations[] = "<Btn3Down>: extend-end(PRIMARY) select-start() CommentClick() \n";
417 String xboardResources[] = {
418 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
423 /* Max possible square size */
424 #define MAXSQSIZE 256
426 /* Arrange to catch delete-window events */
427 Atom wm_delete_window;
429 CatchDeleteWindow (Widget w, String procname)
432 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
433 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
434 XtAugmentTranslations(w, XtParseTranslationTable(buf));
441 XtSetArg(args[0], XtNiconic, False);
442 XtSetValues(shellWidget, args, 1);
444 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
447 //---------------------------------------------------------------------------------------------------------
448 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
451 #define CW_USEDEFAULT (1<<31)
452 #define ICS_TEXT_MENU_SIZE 90
453 #define DEBUG_FILE "xboard.debug"
454 #define SetCurrentDirectory chdir
455 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
459 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
462 // front-end part of option handling
464 // [HGM] This platform-dependent table provides the location for storing the color info
465 extern char *crWhite, * crBlack;
469 &appData.whitePieceColor,
470 &appData.blackPieceColor,
471 &appData.lightSquareColor,
472 &appData.darkSquareColor,
473 &appData.highlightSquareColor,
474 &appData.premoveHighlightColor,
475 &appData.lowTimeWarningColor,
486 // [HGM] font: keep a font for each square size, even non-stndard ones
489 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
490 char *fontTable[NUM_FONTS][MAX_SIZE];
493 ParseFont (char *name, int number)
494 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
496 if(sscanf(name, "size%d:", &size)) {
497 // [HGM] font: font is meant for specific boardSize (likely from settings file);
498 // defer processing it until we know if it matches our board size
499 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
500 fontTable[number][size] = strdup(strchr(name, ':')+1);
501 fontValid[number][size] = True;
506 case 0: // CLOCK_FONT
507 appData.clockFont = strdup(name);
509 case 1: // MESSAGE_FONT
510 appData.font = strdup(name);
512 case 2: // COORD_FONT
513 appData.coordFont = strdup(name);
518 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
523 { // only 2 fonts currently
524 appData.clockFont = CLOCK_FONT_NAME;
525 appData.coordFont = COORD_FONT_NAME;
526 appData.font = DEFAULT_FONT_NAME;
531 { // no-op, until we identify the code for this already in XBoard and move it here
535 ParseColor (int n, char *name)
536 { // in XBoard, just copy the color-name string
537 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
541 ParseTextAttribs (ColorClass cc, char *s)
543 (&appData.colorShout)[cc] = strdup(s);
547 ParseBoardSize (void *addr, char *name)
549 appData.boardSize = strdup(name);
554 { // In XBoard the sound-playing program takes care of obtaining the actual sound
558 SetCommPortDefaults ()
559 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
562 // [HGM] args: these three cases taken out to stay in front-end
564 SaveFontArg (FILE *f, ArgDescriptor *ad)
567 int i, n = (int)(intptr_t)ad->argLoc;
569 case 0: // CLOCK_FONT
570 name = appData.clockFont;
572 case 1: // MESSAGE_FONT
575 case 2: // COORD_FONT
576 name = appData.coordFont;
581 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
582 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
583 fontTable[n][squareSize] = strdup(name);
584 fontValid[n][squareSize] = True;
587 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
588 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
593 { // nothing to do, as the sounds are at all times represented by their text-string names already
597 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
598 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
599 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
603 SaveColor (FILE *f, ArgDescriptor *ad)
604 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
605 if(colorVariable[(int)(intptr_t)ad->argLoc])
606 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
610 SaveBoardSize (FILE *f, char *name, void *addr)
611 { // wrapper to shield back-end from BoardSize & sizeInfo
612 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
616 ParseCommPortSettings (char *s)
617 { // no such option in XBoard (yet)
623 GetActualPlacement (Widget wg, WindowPlacement *wp)
625 XWindowAttributes winAt;
632 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
633 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
634 wp->x = rx - winAt.x;
635 wp->y = ry - winAt.y;
636 wp->height = winAt.height;
637 wp->width = winAt.width;
638 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
643 { // wrapper to shield use of window handles from back-end (make addressible by number?)
644 // In XBoard this will have to wait until awareness of window parameters is implemented
645 GetActualPlacement(shellWidget, &wpMain);
646 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
647 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
648 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
649 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
650 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
651 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
655 PrintCommPortSettings (FILE *f, char *name)
656 { // This option does not exist in XBoard
660 EnsureOnScreen (int *x, int *y, int minX, int minY)
667 { // [HGM] args: allows testing if main window is realized from back-end
668 return xBoardWindow != 0;
672 PopUpStartupDialog ()
673 { // start menu not implemented in XBoard
677 ConvertToLine (int argc, char **argv)
679 static char line[128*1024], buf[1024];
683 for(i=1; i<argc; i++)
685 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
686 && argv[i][0] != '{' )
687 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
689 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
690 strncat(line, buf, 128*1024 - strlen(line) - 1 );
693 line[strlen(line)-1] = NULLCHAR;
697 //--------------------------------------------------------------------------------------------
700 ResizeBoardWindow (int w, int h, int inhibit)
702 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
704 shellArgs[0].value = w;
705 shellArgs[1].value = h;
706 shellArgs[4].value = shellArgs[2].value = w;
707 shellArgs[5].value = shellArgs[3].value = h;
708 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
710 XSync(xDisplay, False);
714 MakeOneColor (char *name, Pixel *color)
717 if (!appData.monoMode) {
718 vFrom.addr = (caddr_t) name;
719 vFrom.size = strlen(name);
720 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
721 if (vTo.addr == NULL) {
722 appData.monoMode = True;
725 *color = *(Pixel *) vTo.addr;
733 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
734 int forceMono = False;
736 if (appData.lowTimeWarning)
737 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
738 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
739 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
745 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
746 { // detervtomine what fonts to use, and create them
750 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
751 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
752 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
753 appData.font = fontTable[MESSAGE_FONT][squareSize];
754 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
755 appData.coordFont = fontTable[COORD_FONT][squareSize];
758 appData.font = InsertPxlSize(appData.font, fontPxlSize);
759 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
760 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
761 fontSet = CreateFontSet(appData.font);
762 clockFontSet = CreateFontSet(appData.clockFont);
764 /* For the coordFont, use the 0th font of the fontset. */
765 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
766 XFontStruct **font_struct_list;
767 XFontSetExtents *fontSize;
768 char **font_name_list;
769 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
770 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
771 coordFontStruct = XQueryFont(xDisplay, coordFontID);
772 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
773 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
776 appData.font = FindFont(appData.font, fontPxlSize);
777 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
778 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
779 clockFontID = XLoadFont(xDisplay, appData.clockFont);
780 clockFontStruct = XQueryFont(xDisplay, clockFontID);
781 coordFontID = XLoadFont(xDisplay, appData.coordFont);
782 coordFontStruct = XQueryFont(xDisplay, coordFontID);
783 // textHeight in !NLS mode!
785 countFontID = coordFontID; // [HGM] holdings
786 countFontStruct = coordFontStruct;
788 xdb = XtDatabase(xDisplay);
790 XrmPutLineResource(&xdb, "*international: True");
791 vTo.size = sizeof(XFontSet);
792 vTo.addr = (XtPointer) &fontSet;
793 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
795 XrmPutStringResource(&xdb, "*font", appData.font);
805 case ArgInt: p = " N"; break;
806 case ArgString: p = " STR"; break;
807 case ArgBoolean: p = " TF"; break;
808 case ArgSettingsFilename:
809 case ArgBackupSettingsFile:
810 case ArgFilename: p = " FILE"; break;
811 case ArgX: p = " Nx"; break;
812 case ArgY: p = " Ny"; break;
813 case ArgAttribs: p = " TEXTCOL"; break;
814 case ArgColor: p = " COL"; break;
815 case ArgFont: p = " FONT"; break;
816 case ArgBoardSize: p = " SIZE"; break;
817 case ArgFloat: p = " FLOAT"; break;
822 case ArgCommSettings:
831 GenerateGlobalTranslationTable (void)
833 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
841 /* loop over all menu entries */
842 for( i=0; menuBar[i].mi ; i++)
845 for(j=0; mi[j].proc; j++)
853 char *key,*test, *mods;
855 /* check for Ctrl/Alt */
856 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
857 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
858 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
860 /* remove all <...> */
861 test = strrchr(mi[j].accel, '>');
863 key = strdup(mi[j].accel);
865 key = strdup(++test); // remove ">"
867 /* instead of shift X11 uses the uppercase letter directly*/
868 if (shift && strlen(key)==1 )
870 *key = toupper(*key);
874 /* handle some special cases which have different names in X11 */
875 if ( strncmp(key, "Page_Down", 9) == 0 )
880 else if ( strncmp(key, "Page_Up", 7) == 0 )
886 /* create string of mods */
888 mods = strdup("Ctrl ");
894 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
895 strncat(mods, "Meta ", 5);
900 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
901 strncat(mods, "Shift ", 6);
904 // remove trailing space
905 if( isspace(mods[strlen(mods)-1]) )
906 mods[strlen(mods)-1]='\0';
908 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
909 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
910 char *name = malloc(namesize+1);
911 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
913 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
914 char *buffer = malloc(buffersize+1);
915 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
917 /* add string to the output */
918 output = realloc(output, strlen(output) + strlen(buffer)+1);
919 strncat(output, buffer, strlen(buffer));
938 ArgDescriptor *q, *p = argDescriptors+5;
939 printf("\nXBoard accepts the following options:\n"
940 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
941 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
942 " SIZE = board-size spec(s)\n"
943 " Within parentheses are short forms, or options to set to true or false.\n"
944 " Persistent options (saved in the settings file) are marked with *)\n\n");
946 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
947 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
948 if(p->save) strcat(buf+len, "*");
949 for(q=p+1; q->argLoc == p->argLoc; q++) {
950 if(q->argName[0] == '-') continue;
951 strcat(buf+len, q == p+1 ? " (" : " ");
952 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
954 if(q != p+1) strcat(buf+len, ")");
956 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
959 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
963 SlaveResize (Option *opt)
968 main (int argc, char **argv)
970 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
971 XSetWindowAttributes window_attributes;
973 Dimension boardWidth, boardHeight, w, h;
975 int forceMono = False;
977 srandom(time(0)); // [HGM] book: make random truly random
979 setbuf(stdout, NULL);
980 setbuf(stderr, NULL);
983 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
984 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
988 if(argc > 1 && !strcmp(argv[1], "--help" )) {
993 programName = strrchr(argv[0], '/');
994 if (programName == NULL)
995 programName = argv[0];
1000 XtSetLanguageProc(NULL, NULL, NULL);
1001 if (appData.debugMode) {
1002 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1005 bindtextdomain(PACKAGE, LOCALEDIR);
1006 textdomain(PACKAGE);
1009 appData.boardSize = "";
1010 InitAppData(ConvertToLine(argc, argv));
1012 if (p == NULL) p = "/tmp";
1013 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1014 gameCopyFilename = (char*) malloc(i);
1015 gamePasteFilename = (char*) malloc(i);
1016 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1017 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1019 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1020 static char buf[MSG_SIZ];
1021 EscapeExpand(buf, appData.firstInitString);
1022 appData.firstInitString = strdup(buf);
1023 EscapeExpand(buf, appData.secondInitString);
1024 appData.secondInitString = strdup(buf);
1025 EscapeExpand(buf, appData.firstComputerString);
1026 appData.firstComputerString = strdup(buf);
1027 EscapeExpand(buf, appData.secondComputerString);
1028 appData.secondComputerString = strdup(buf);
1031 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1034 if (chdir(chessDir) != 0) {
1035 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1041 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1042 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1043 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1044 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1047 setbuf(debugFP, NULL);
1050 /* [HGM,HR] make sure board size is acceptable */
1051 if(appData.NrFiles > BOARD_FILES ||
1052 appData.NrRanks > BOARD_RANKS )
1053 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1056 /* This feature does not work; animation needs a rewrite */
1057 appData.highlightDragging = FALSE;
1061 gameInfo.variant = StringToVariant(appData.variant);
1062 InitPosition(FALSE);
1065 XtAppInitialize(&appContext, "XBoard", shellOptions,
1066 XtNumber(shellOptions),
1067 &argc, argv, xboardResources, NULL, 0);
1069 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1070 clientResources, XtNumber(clientResources),
1073 xDisplay = XtDisplay(shellWidget);
1074 xScreen = DefaultScreen(xDisplay);
1075 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1078 * determine size, based on supplied or remembered -size, or screen size
1080 if (isdigit(appData.boardSize[0])) {
1081 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1082 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1083 &fontPxlSize, &smallLayout, &tinyLayout);
1085 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1086 programName, appData.boardSize);
1090 /* Find some defaults; use the nearest known size */
1091 SizeDefaults *szd, *nearest;
1092 int distance = 99999;
1093 nearest = szd = sizeDefaults;
1094 while (szd->name != NULL) {
1095 if (abs(szd->squareSize - squareSize) < distance) {
1097 distance = abs(szd->squareSize - squareSize);
1098 if (distance == 0) break;
1102 if (i < 2) lineGap = nearest->lineGap;
1103 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1104 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1105 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1106 if (i < 6) smallLayout = nearest->smallLayout;
1107 if (i < 7) tinyLayout = nearest->tinyLayout;
1110 SizeDefaults *szd = sizeDefaults;
1111 if (*appData.boardSize == NULLCHAR) {
1112 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1113 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1116 if (szd->name == NULL) szd--;
1117 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1119 while (szd->name != NULL &&
1120 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1121 if (szd->name == NULL) {
1122 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1123 programName, appData.boardSize);
1127 squareSize = szd->squareSize;
1128 lineGap = szd->lineGap;
1129 clockFontPxlSize = szd->clockFontPxlSize;
1130 coordFontPxlSize = szd->coordFontPxlSize;
1131 fontPxlSize = szd->fontPxlSize;
1132 smallLayout = szd->smallLayout;
1133 tinyLayout = szd->tinyLayout;
1134 // [HGM] font: use defaults from settings file if available and not overruled
1137 defaultLineGap = lineGap;
1138 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1140 /* [HR] height treated separately (hacked) */
1141 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1142 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1145 * Determine what fonts to use.
1147 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1150 * Detect if there are not enough colors available and adapt.
1152 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1153 appData.monoMode = True;
1156 forceMono = MakeColors();
1159 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1161 appData.monoMode = True;
1164 if (appData.monoMode && appData.debugMode) {
1165 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1166 (unsigned long) XWhitePixel(xDisplay, xScreen),
1167 (unsigned long) XBlackPixel(xDisplay, xScreen));
1170 ParseIcsTextColors();
1172 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1178 layoutName = "tinyLayout";
1179 } else if (smallLayout) {
1180 layoutName = "smallLayout";
1182 layoutName = "normalLayout";
1185 optList = BoardPopUp(squareSize, lineGap, (void*)
1191 InitDrawingHandle(optList + W_BOARD);
1192 currBoard = &optList[W_BOARD];
1193 boardWidget = optList[W_BOARD].handle;
1194 menuBarWidget = optList[W_MENU].handle;
1195 dropMenu = optList[W_DROP].handle;
1196 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1197 formWidget = XtParent(boardWidget);
1198 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1199 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1200 XtGetValues(optList[W_WHITE].handle, args, 2);
1201 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1202 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1203 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1204 XtGetValues(optList[W_PAUSE].handle, args, 2);
1207 xBoardWindow = XtWindow(boardWidget);
1209 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1210 // not need to go into InitDrawingSizes().
1213 * Create X checkmark bitmap and initialize option menu checks.
1215 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1216 checkmark_bits, checkmark_width, checkmark_height);
1222 ReadBitmap(&wIconPixmap, "icon_white.bm",
1223 icon_white_bits, icon_white_width, icon_white_height);
1224 ReadBitmap(&bIconPixmap, "icon_black.bm",
1225 icon_black_bits, icon_black_width, icon_black_height);
1226 iconPixmap = wIconPixmap;
1228 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1229 XtSetValues(shellWidget, args, i);
1232 * Create a cursor for the board widget.
1234 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1235 XChangeWindowAttributes(xDisplay, xBoardWindow,
1236 CWCursor, &window_attributes);
1239 * Inhibit shell resizing.
1241 shellArgs[0].value = (XtArgVal) &w;
1242 shellArgs[1].value = (XtArgVal) &h;
1243 XtGetValues(shellWidget, shellArgs, 2);
1244 shellArgs[4].value = shellArgs[2].value = w;
1245 shellArgs[5].value = shellArgs[3].value = h;
1246 // XtSetValues(shellWidget, &shellArgs[2], 4);
1247 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1248 marginH = h - boardHeight;
1250 CatchDeleteWindow(shellWidget, "QuitProc");
1255 if(appData.logoSize)
1256 { // locate and read user logo
1258 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1259 ASSIGN(userLogo, buf);
1262 if (appData.animate || appData.animateDragging)
1266 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1268 XtAugmentTranslations(formWidget,
1269 XtParseTranslationTable(globalTranslations));
1270 XtAugmentTranslations(formWidget,
1271 XtParseTranslationTable(TranslationsTableMenus));
1273 XtAddEventHandler(formWidget, KeyPressMask, False,
1274 (XtEventHandler) MoveTypeInProc, NULL);
1275 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1276 (XtEventHandler) EventProc, NULL);
1278 /* [AS] Restore layout */
1279 if( wpMoveHistory.visible ) {
1283 if( wpEvalGraph.visible )
1288 if( wpEngineOutput.visible ) {
1289 EngineOutputPopUp();
1294 if (errorExitStatus == -1) {
1295 if (appData.icsActive) {
1296 /* We now wait until we see "login:" from the ICS before
1297 sending the logon script (problems with timestamp otherwise) */
1298 /*ICSInitScript();*/
1299 if (appData.icsInputBox) ICSInputBoxPopUp();
1303 signal(SIGWINCH, TermSizeSigHandler);
1305 signal(SIGINT, IntSigHandler);
1306 signal(SIGTERM, IntSigHandler);
1307 if (*appData.cmailGameName != NULLCHAR) {
1308 signal(SIGUSR1, CmailSigHandler);
1312 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1315 // XtSetKeyboardFocus(shellWidget, formWidget);
1316 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1318 XtAppMainLoop(appContext);
1319 if (appData.debugMode) fclose(debugFP); // [DM] debug
1324 TermSizeSigHandler (int sig)
1330 IntSigHandler (int sig)
1336 CmailSigHandler (int sig)
1341 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1343 /* Activate call-back function CmailSigHandlerCallBack() */
1344 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1346 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1350 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1353 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1355 /**** end signal code ****/
1358 #define Abs(n) ((n)<0 ? -(n) : (n))
1362 InsertPxlSize (char *pattern, int targetPxlSize)
1364 char *base_fnt_lst, strInt[12], *p, *q;
1365 int alternatives, i, len, strIntLen;
1368 * Replace the "*" (if present) in the pixel-size slot of each
1369 * alternative with the targetPxlSize.
1373 while ((p = strchr(p, ',')) != NULL) {
1377 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1378 strIntLen = strlen(strInt);
1379 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1383 while (alternatives--) {
1384 char *comma = strchr(p, ',');
1385 for (i=0; i<14; i++) {
1386 char *hyphen = strchr(p, '-');
1388 if (comma && hyphen > comma) break;
1389 len = hyphen + 1 - p;
1390 if (i == 7 && *p == '*' && len == 2) {
1392 memcpy(q, strInt, strIntLen);
1402 len = comma + 1 - p;
1409 return base_fnt_lst;
1413 CreateFontSet (char *base_fnt_lst)
1416 char **missing_list;
1420 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1421 &missing_list, &missing_count, &def_string);
1422 if (appData.debugMode) {
1424 XFontStruct **font_struct_list;
1425 char **font_name_list;
1426 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1428 fprintf(debugFP, " got list %s, locale %s\n",
1429 XBaseFontNameListOfFontSet(fntSet),
1430 XLocaleOfFontSet(fntSet));
1431 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1432 for (i = 0; i < count; i++) {
1433 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1436 for (i = 0; i < missing_count; i++) {
1437 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1440 if (fntSet == NULL) {
1441 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1446 #else // not ENABLE_NLS
1448 * Find a font that matches "pattern" that is as close as
1449 * possible to the targetPxlSize. Prefer fonts that are k
1450 * pixels smaller to fonts that are k pixels larger. The
1451 * pattern must be in the X Consortium standard format,
1452 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1453 * The return value should be freed with XtFree when no
1457 FindFont (char *pattern, int targetPxlSize)
1459 char **fonts, *p, *best, *scalable, *scalableTail;
1460 int i, j, nfonts, minerr, err, pxlSize;
1462 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1464 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1465 programName, pattern);
1472 for (i=0; i<nfonts; i++) {
1475 if (*p != '-') continue;
1477 if (*p == NULLCHAR) break;
1478 if (*p++ == '-') j++;
1480 if (j < 7) continue;
1483 scalable = fonts[i];
1486 err = pxlSize - targetPxlSize;
1487 if (Abs(err) < Abs(minerr) ||
1488 (minerr > 0 && err < 0 && -err == minerr)) {
1494 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1495 /* If the error is too big and there is a scalable font,
1496 use the scalable font. */
1497 int headlen = scalableTail - scalable;
1498 p = (char *) XtMalloc(strlen(scalable) + 10);
1499 while (isdigit(*scalableTail)) scalableTail++;
1500 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1502 p = (char *) XtMalloc(strlen(best) + 2);
1503 safeStrCpy(p, best, strlen(best)+1 );
1505 if (appData.debugMode) {
1506 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1507 pattern, targetPxlSize, p);
1509 XFreeFontNames(fonts);
1515 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1518 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1524 MarkMenuItem (char *menuRef, int state)
1526 MenuItem *item = MenuNameToItem(menuRef);
1530 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1531 XtSetValues(item->handle, args, 1);
1536 EnableNamedMenuItem (char *menuRef, int state)
1538 MenuItem *item = MenuNameToItem(menuRef);
1540 if(item) XtSetSensitive(item->handle, state);
1544 EnableButtonBar (int state)
1546 XtSetSensitive(optList[W_BUTTON].handle, state);
1551 SetMenuEnables (Enables *enab)
1553 while (enab->name != NULL) {
1554 EnableNamedMenuItem(enab->name, enab->value);
1560 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1561 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1563 if(*nprms == 0) return;
1564 item = MenuNameToItem(prms[0]);
1565 if(item) ((MenuProc *) item->proc) ();
1577 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1578 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1579 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1580 dmEnables[i].piece);
1581 XtSetSensitive(entry, p != NULL || !appData.testLegality
1582 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1583 && !appData.icsActive));
1585 while (p && *p++ == dmEnables[i].piece) count++;
1586 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1588 XtSetArg(args[j], XtNlabel, label); j++;
1589 XtSetValues(entry, args, j);
1594 do_flash_delay (unsigned long msec)
1600 FlashDelay (int flash_delay)
1602 XSync(xDisplay, False);
1603 if(flash_delay) do_flash_delay(flash_delay);
1607 Fraction (int x, int start, int stop)
1609 double f = ((double) x - start)/(stop - start);
1610 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1614 static WindowPlacement wpNew;
1617 CoDrag (Widget sh, WindowPlacement *wp)
1620 int j=0, touch=0, fudge = 2;
1621 GetActualPlacement(sh, wp);
1622 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1623 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1624 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1625 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1626 if(!touch ) return; // only windows that touch co-move
1627 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1628 int heightInc = wpNew.height - wpMain.height;
1629 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1630 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1631 wp->y += fracTop * heightInc;
1632 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1633 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1634 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1635 int widthInc = wpNew.width - wpMain.width;
1636 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1637 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1638 wp->y += fracLeft * widthInc;
1639 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1640 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1642 wp->x += wpNew.x - wpMain.x;
1643 wp->y += wpNew.y - wpMain.y;
1644 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1645 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1646 XtSetArg(args[j], XtNx, wp->x); j++;
1647 XtSetArg(args[j], XtNy, wp->y); j++;
1648 XtSetValues(sh, args, j);
1652 ReSize (WindowPlacement *wp)
1655 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1656 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1657 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1658 if(sqy < sqx) sqx = sqy;
1659 if(sqx != squareSize) {
1660 squareSize = sqx; // adopt new square size
1661 CreatePNGPieces(); // make newly scaled pieces
1662 InitDrawingSizes(0, 0); // creates grid etc.
1663 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1664 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1665 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1666 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1667 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1670 static XtIntervalId delayedDragID = 0;
1679 GetActualPlacement(shellWidget, &wpNew);
1680 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1681 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1682 busy = 0; return; // false alarm
1685 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1686 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1687 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1688 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1690 DrawPosition(True, NULL);
1691 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1699 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1701 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1705 EventProc (Widget widget, caddr_t unused, XEvent *event)
1707 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1708 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1712 * event handler for redrawing the board
1715 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1717 DrawPosition(True, NULL);
1722 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1723 { // [HGM] pv: walk PV
1724 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1727 extern int savedIndex; /* gross that this is global */
1730 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1733 XawTextPosition index, dummy;
1736 XawTextGetSelectionPos(w, &index, &dummy);
1737 XtSetArg(arg, XtNstring, &val);
1738 XtGetValues(w, &arg, 1);
1739 ReplaceComment(savedIndex, val);
1740 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1741 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1745 /* Disable all user input other than deleting the window */
1746 static int frozen = 0;
1752 /* Grab by a widget that doesn't accept input */
1753 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1757 /* Undo a FreezeUI */
1761 if (!frozen) return;
1762 XtRemoveGrab(optList[W_MESSG].handle);
1770 static int oldPausing = FALSE;
1771 static GameMode oldmode = (GameMode) -1;
1774 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1776 if (pausing != oldPausing) {
1777 oldPausing = pausing;
1778 MarkMenuItem("Mode.Pause", pausing);
1780 if (appData.showButtonBar) {
1781 /* Always toggle, don't set. Previous code messes up when
1782 invoked while the button is pressed, as releasing it
1783 toggles the state again. */
1786 XtSetArg(args[0], XtNbackground, &oldbg);
1787 XtSetArg(args[1], XtNforeground, &oldfg);
1788 XtGetValues(optList[W_PAUSE].handle,
1790 XtSetArg(args[0], XtNbackground, oldfg);
1791 XtSetArg(args[1], XtNforeground, oldbg);
1793 XtSetValues(optList[W_PAUSE].handle, args, 2);
1797 wname = ModeToWidgetName(oldmode);
1798 if (wname != NULL) {
1799 MarkMenuItem(wname, False);
1801 wname = ModeToWidgetName(gameMode);
1802 if (wname != NULL) {
1803 MarkMenuItem(wname, True);
1806 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1808 /* Maybe all the enables should be handled here, not just this one */
1809 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1811 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1816 * Button/menu procedures
1819 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1820 char *selected_fen_position=NULL;
1823 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1824 Atom *type_return, XtPointer *value_return,
1825 unsigned long *length_return, int *format_return)
1827 char *selection_tmp;
1829 // if (!selected_fen_position) return False; /* should never happen */
1830 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1831 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1832 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1835 if (f == NULL) return False;
1839 selection_tmp = XtMalloc(len + 1);
1840 count = fread(selection_tmp, 1, len, f);
1843 XtFree(selection_tmp);
1846 selection_tmp[len] = NULLCHAR;
1848 /* note: since no XtSelectionDoneProc was registered, Xt will
1849 * automatically call XtFree on the value returned. So have to
1850 * make a copy of it allocated with XtMalloc */
1851 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1852 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1855 *value_return=selection_tmp;
1856 *length_return=strlen(selection_tmp);
1857 *type_return=*target;
1858 *format_return = 8; /* bits per byte */
1860 } else if (*target == XA_TARGETS(xDisplay)) {
1861 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1862 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1863 targets_tmp[1] = XA_STRING;
1864 *value_return = targets_tmp;
1865 *type_return = XA_ATOM;
1868 // This code leads to a read of value_return out of bounds on 64-bit systems.
1869 // Other code which I have seen always sets *format_return to 32 independent of
1870 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1871 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1872 *format_return = 8 * sizeof(Atom);
1873 if (*format_return > 32) {
1874 *length_return *= *format_return / 32;
1875 *format_return = 32;
1878 *format_return = 32;
1886 /* note: when called from menu all parameters are NULL, so no clue what the
1887 * Widget which was clicked on was, or what the click event was
1890 CopySomething (char *src)
1892 selected_fen_position = src;
1894 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1895 * have a notion of a position that is selected but not copied.
1896 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1898 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1900 SendPositionSelection,
1901 NULL/* lose_ownership_proc */ ,
1902 NULL/* transfer_done_proc */);
1903 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1905 SendPositionSelection,
1906 NULL/* lose_ownership_proc */ ,
1907 NULL/* transfer_done_proc */);
1910 /* function called when the data to Paste is ready */
1912 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1913 Atom *type, XtPointer value, unsigned long *len, int *format)
1916 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1917 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1918 EditPositionPasteFEN(fenstr);
1922 /* called when Paste Position button is pressed,
1923 * all parameters will be NULL */
1925 PastePositionProc ()
1927 XtGetSelectionValue(menuBarWidget,
1928 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1929 /* (XtSelectionCallbackProc) */ PastePositionCB,
1930 NULL, /* client_data passed to PastePositionCB */
1932 /* better to use the time field from the event that triggered the
1933 * call to this function, but that isn't trivial to get
1940 /* note: when called from menu all parameters are NULL, so no clue what the
1941 * Widget which was clicked on was, or what the click event was
1943 /* function called when the data to Paste is ready */
1945 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1946 Atom *type, XtPointer value, unsigned long *len, int *format)
1949 if (value == NULL || *len == 0) {
1950 return; /* nothing had been selected to copy */
1952 f = fopen(gamePasteFilename, "w");
1954 DisplayError(_("Can't open temp file"), errno);
1957 fwrite(value, 1, *len, f);
1960 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1963 /* called when Paste Game button is pressed,
1964 * all parameters will be NULL */
1968 XtGetSelectionValue(menuBarWidget,
1969 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1970 /* (XtSelectionCallbackProc) */ PasteGameCB,
1971 NULL, /* client_data passed to PasteGameCB */
1973 /* better to use the time field from the event that triggered the
1974 * call to this function, but that isn't trivial to get
1983 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1990 { // bassic primitive for determining if modifier keys are pressed
1991 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
1994 XQueryKeymap(xDisplay,keys);
1995 for(i=0; i<6; i++) {
1997 j = XKeysymToKeycode(xDisplay, codes[i]);
1998 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2004 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2008 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2009 if ( n == 1 && *buf >= 32 // printable
2010 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2011 ) BoxAutoPopUp (buf);
2015 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2016 { // [HGM] input: let up-arrow recall previous line from history
2021 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2022 { // [HGM] input: let down-arrow recall next line from history
2027 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2033 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2035 if (!TempBackwardActive) {
2036 TempBackwardActive = True;
2042 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2044 /* Check to see if triggered by a key release event for a repeating key.
2045 * If so the next queued event will be a key press of the same key at the same time */
2046 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2048 XPeekEvent(xDisplay, &next);
2049 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2050 next.xkey.keycode == event->xkey.keycode)
2054 TempBackwardActive = False;
2058 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2059 { // called as key binding
2062 if (nprms && *nprms > 0)
2066 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2072 { // called from menu
2073 ManInner(NULL, NULL, NULL, NULL);
2077 SetWindowTitle (char *text, char *title, char *icon)
2081 if (appData.titleInWindow) {
2083 XtSetArg(args[i], XtNlabel, text); i++;
2084 XtSetValues(titleWidget, args, i);
2087 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2088 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2089 XtSetValues(shellWidget, args, i);
2090 XSync(xDisplay, False);
2095 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2101 DisplayIcsInteractionTitle (String message)
2103 if (oldICSInteractionTitle == NULL) {
2104 /* Magic to find the old window title, adapted from vim */
2105 char *wina = getenv("WINDOWID");
2107 Window win = (Window) atoi(wina);
2108 Window root, parent, *children;
2109 unsigned int nchildren;
2110 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2112 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2113 if (!XQueryTree(xDisplay, win, &root, &parent,
2114 &children, &nchildren)) break;
2115 if (children) XFree((void *)children);
2116 if (parent == root || parent == 0) break;
2119 XSetErrorHandler(oldHandler);
2121 if (oldICSInteractionTitle == NULL) {
2122 oldICSInteractionTitle = "xterm";
2125 printf("\033]0;%s\007", message);
2130 XtIntervalId delayedEventTimerXID = 0;
2131 DelayedEventCallback delayedEventCallback = 0;
2136 delayedEventTimerXID = 0;
2137 delayedEventCallback();
2141 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2143 if(delayedEventTimerXID && delayedEventCallback == cb)
2144 // [HGM] alive: replace, rather than add or flush identical event
2145 XtRemoveTimeOut(delayedEventTimerXID);
2146 delayedEventCallback = cb;
2147 delayedEventTimerXID =
2148 XtAppAddTimeOut(appContext, millisec,
2149 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2152 DelayedEventCallback
2155 if (delayedEventTimerXID) {
2156 return delayedEventCallback;
2163 CancelDelayedEvent ()
2165 if (delayedEventTimerXID) {
2166 XtRemoveTimeOut(delayedEventTimerXID);
2167 delayedEventTimerXID = 0;
2171 XtIntervalId loadGameTimerXID = 0;
2174 LoadGameTimerRunning ()
2176 return loadGameTimerXID != 0;
2180 StopLoadGameTimer ()
2182 if (loadGameTimerXID != 0) {
2183 XtRemoveTimeOut(loadGameTimerXID);
2184 loadGameTimerXID = 0;
2192 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2194 loadGameTimerXID = 0;
2199 StartLoadGameTimer (long millisec)
2202 XtAppAddTimeOut(appContext, millisec,
2203 (XtTimerCallbackProc) LoadGameTimerCallback,
2207 XtIntervalId analysisClockXID = 0;
2210 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2212 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2213 || appData.icsEngineAnalyze) { // [DM]
2214 AnalysisPeriodicEvent(0);
2215 StartAnalysisClock();
2220 StartAnalysisClock ()
2223 XtAppAddTimeOut(appContext, 2000,
2224 (XtTimerCallbackProc) AnalysisClockCallback,
2228 XtIntervalId clockTimerXID = 0;
2231 ClockTimerRunning ()
2233 return clockTimerXID != 0;
2239 if (clockTimerXID != 0) {
2240 XtRemoveTimeOut(clockTimerXID);
2249 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2256 StartClockTimer (long millisec)
2259 XtAppAddTimeOut(appContext, millisec,
2260 (XtTimerCallbackProc) ClockTimerCallback,
2265 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2269 Widget w = (Widget) opt->handle;
2271 /* check for low time warning */
2272 Pixel foregroundOrWarningColor = timerForegroundPixel;
2275 appData.lowTimeWarning &&
2276 (timer / 1000) < appData.icsAlarmTime)
2277 foregroundOrWarningColor = lowTimeWarningColor;
2279 if (appData.clockMode) {
2280 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2281 XtSetArg(args[0], XtNlabel, buf);
2283 snprintf(buf, MSG_SIZ, "%s ", color);
2284 XtSetArg(args[0], XtNlabel, buf);
2289 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2290 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2292 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2293 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2296 XtSetValues(w, args, 3);
2299 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2302 SetClockIcon (int color)
2305 Pixmap pm = *clockIcons[color];
2306 if (iconPixmap != pm) {
2308 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2309 XtSetValues(shellWidget, args, 1);
2313 #define INPUT_SOURCE_BUF_SIZE 8192
2322 char buf[INPUT_SOURCE_BUF_SIZE];
2327 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2329 InputSource *is = (InputSource *) closure;
2334 if (is->lineByLine) {
2335 count = read(is->fd, is->unused,
2336 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2338 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2341 is->unused += count;
2343 while (p < is->unused) {
2344 q = memchr(p, '\n', is->unused - p);
2345 if (q == NULL) break;
2347 (is->func)(is, is->closure, p, q - p, 0);
2351 while (p < is->unused) {
2356 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2361 (is->func)(is, is->closure, is->buf, count, error);
2366 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2369 ChildProc *cp = (ChildProc *) pr;
2371 is = (InputSource *) calloc(1, sizeof(InputSource));
2372 is->lineByLine = lineByLine;
2376 is->fd = fileno(stdin);
2378 is->kind = cp->kind;
2379 is->fd = cp->fdFrom;
2382 is->unused = is->buf;
2385 is->xid = XtAppAddInput(appContext, is->fd,
2386 (XtPointer) (XtInputReadMask),
2387 (XtInputCallbackProc) DoInputCallback,
2389 is->closure = closure;
2390 return (InputSourceRef) is;
2394 RemoveInputSource (InputSourceRef isr)
2396 InputSource *is = (InputSource *) isr;
2398 if (is->xid == 0) return;
2399 XtRemoveInput(is->xid);
2405 static Boolean frameWaiting;
2408 FrameAlarm (int sig)
2410 frameWaiting = False;
2411 /* In case System-V style signals. Needed?? */
2412 signal(SIGALRM, FrameAlarm);
2416 FrameDelay (int time)
2418 struct itimerval delay;
2420 XSync(xDisplay, False);
2423 frameWaiting = True;
2424 signal(SIGALRM, FrameAlarm);
2425 delay.it_interval.tv_sec =
2426 delay.it_value.tv_sec = time / 1000;
2427 delay.it_interval.tv_usec =
2428 delay.it_value.tv_usec = (time % 1000) * 1000;
2429 setitimer(ITIMER_REAL, &delay, NULL);
2430 while (frameWaiting) pause();
2431 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2432 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2433 setitimer(ITIMER_REAL, &delay, NULL);
2440 FrameDelay (int time)
2442 XSync(xDisplay, False);
2444 usleep(time * 1000);
2450 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2452 char buf[MSG_SIZ], *logoName = buf;
2453 if(appData.logo[n][0]) {
2454 logoName = appData.logo[n];
2455 } else if(appData.autoLogo) {
2456 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2457 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2458 } else if(appData.directory[n] && appData.directory[n][0]) {
2459 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2463 { ASSIGN(cps->programLogo, logoName); }
2467 UpdateLogos (int displ)
2469 if(optList[W_WHITE-1].handle == NULL) return;
2470 LoadLogo(&first, 0, 0);
2471 LoadLogo(&second, 1, appData.icsActive);
2472 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);