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:
828 GenerateGlobalTranslationTable (void)
830 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
838 /* loop over all menu entries */
839 for( i=0; menuBar[i].mi ; i++)
842 for(j=0; mi[j].proc; j++)
850 char *key,*test, *mods;
852 /* check for Ctrl/Alt */
853 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
854 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
855 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
857 /* remove all <...> */
858 test = strrchr(mi[j].accel, '>');
860 key = strdup(mi[j].accel);
862 key = strdup(++test); // remove ">"
864 /* instead of shift X11 uses the uppercase letter directly*/
865 if (shift && strlen(key)==1 )
867 *key = toupper(*key);
871 /* handle some special cases which have different names in X11 */
872 if ( strncmp(key, "Page_Down", 9) == 0 )
877 else if ( strncmp(key, "Page_Up", 7) == 0 )
883 /* create string of mods */
885 mods = strdup("Ctrl ");
891 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
892 strncat(mods, "Meta ", 5);
897 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
898 strncat(mods, "Shift ", 6);
901 // remove trailing space
902 if( isspace(mods[strlen(mods)-1]) )
903 mods[strlen(mods)-1]='\0';
905 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
906 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
907 char *name = malloc(namesize+1);
908 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
910 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
911 char *buffer = malloc(buffersize+1);
912 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
914 /* add string to the output */
915 output = realloc(output, strlen(output) + strlen(buffer)+1);
916 strncat(output, buffer, strlen(buffer));
935 ArgDescriptor *q, *p = argDescriptors+5;
936 printf("\nXBoard accepts the following options:\n"
937 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
938 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
939 " SIZE = board-size spec(s)\n"
940 " Within parentheses are short forms, or options to set to true or false.\n"
941 " Persistent options (saved in the settings file) are marked with *)\n\n");
943 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
944 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
945 if(p->save) strcat(buf+len, "*");
946 for(q=p+1; q->argLoc == p->argLoc; q++) {
947 if(q->argName[0] == '-') continue;
948 strcat(buf+len, q == p+1 ? " (" : " ");
949 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
951 if(q != p+1) strcat(buf+len, ")");
953 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
956 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
960 SlaveResize (Option *opt)
965 main (int argc, char **argv)
967 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
968 XSetWindowAttributes window_attributes;
970 Dimension boardWidth, boardHeight, w, h;
972 int forceMono = False;
974 srandom(time(0)); // [HGM] book: make random truly random
976 setbuf(stdout, NULL);
977 setbuf(stderr, NULL);
980 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
981 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
985 if(argc > 1 && !strcmp(argv[1], "--help" )) {
990 programName = strrchr(argv[0], '/');
991 if (programName == NULL)
992 programName = argv[0];
997 XtSetLanguageProc(NULL, NULL, NULL);
998 if (appData.debugMode) {
999 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1002 bindtextdomain(PACKAGE, LOCALEDIR);
1003 textdomain(PACKAGE);
1006 appData.boardSize = "";
1007 InitAppData(ConvertToLine(argc, argv));
1009 if (p == NULL) p = "/tmp";
1010 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1011 gameCopyFilename = (char*) malloc(i);
1012 gamePasteFilename = (char*) malloc(i);
1013 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1014 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1016 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1017 static char buf[MSG_SIZ];
1018 EscapeExpand(buf, appData.firstInitString);
1019 appData.firstInitString = strdup(buf);
1020 EscapeExpand(buf, appData.secondInitString);
1021 appData.secondInitString = strdup(buf);
1022 EscapeExpand(buf, appData.firstComputerString);
1023 appData.firstComputerString = strdup(buf);
1024 EscapeExpand(buf, appData.secondComputerString);
1025 appData.secondComputerString = strdup(buf);
1028 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1031 if (chdir(chessDir) != 0) {
1032 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1038 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1039 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1040 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1041 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1044 setbuf(debugFP, NULL);
1047 /* [HGM,HR] make sure board size is acceptable */
1048 if(appData.NrFiles > BOARD_FILES ||
1049 appData.NrRanks > BOARD_RANKS )
1050 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1053 /* This feature does not work; animation needs a rewrite */
1054 appData.highlightDragging = FALSE;
1058 gameInfo.variant = StringToVariant(appData.variant);
1059 InitPosition(FALSE);
1062 XtAppInitialize(&appContext, "XBoard", shellOptions,
1063 XtNumber(shellOptions),
1064 &argc, argv, xboardResources, NULL, 0);
1066 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1067 clientResources, XtNumber(clientResources),
1070 xDisplay = XtDisplay(shellWidget);
1071 xScreen = DefaultScreen(xDisplay);
1072 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1075 * determine size, based on supplied or remembered -size, or screen size
1077 if (isdigit(appData.boardSize[0])) {
1078 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1079 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1080 &fontPxlSize, &smallLayout, &tinyLayout);
1082 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1083 programName, appData.boardSize);
1087 /* Find some defaults; use the nearest known size */
1088 SizeDefaults *szd, *nearest;
1089 int distance = 99999;
1090 nearest = szd = sizeDefaults;
1091 while (szd->name != NULL) {
1092 if (abs(szd->squareSize - squareSize) < distance) {
1094 distance = abs(szd->squareSize - squareSize);
1095 if (distance == 0) break;
1099 if (i < 2) lineGap = nearest->lineGap;
1100 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1101 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1102 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1103 if (i < 6) smallLayout = nearest->smallLayout;
1104 if (i < 7) tinyLayout = nearest->tinyLayout;
1107 SizeDefaults *szd = sizeDefaults;
1108 if (*appData.boardSize == NULLCHAR) {
1109 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1110 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1113 if (szd->name == NULL) szd--;
1114 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1116 while (szd->name != NULL &&
1117 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1118 if (szd->name == NULL) {
1119 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1120 programName, appData.boardSize);
1124 squareSize = szd->squareSize;
1125 lineGap = szd->lineGap;
1126 clockFontPxlSize = szd->clockFontPxlSize;
1127 coordFontPxlSize = szd->coordFontPxlSize;
1128 fontPxlSize = szd->fontPxlSize;
1129 smallLayout = szd->smallLayout;
1130 tinyLayout = szd->tinyLayout;
1131 // [HGM] font: use defaults from settings file if available and not overruled
1134 defaultLineGap = lineGap;
1135 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1137 /* [HR] height treated separately (hacked) */
1138 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1139 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1142 * Determine what fonts to use.
1144 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1147 * Detect if there are not enough colors available and adapt.
1149 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1150 appData.monoMode = True;
1153 forceMono = MakeColors();
1156 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1158 appData.monoMode = True;
1161 if (appData.monoMode && appData.debugMode) {
1162 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1163 (unsigned long) XWhitePixel(xDisplay, xScreen),
1164 (unsigned long) XBlackPixel(xDisplay, xScreen));
1167 ParseIcsTextColors();
1169 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1175 layoutName = "tinyLayout";
1176 } else if (smallLayout) {
1177 layoutName = "smallLayout";
1179 layoutName = "normalLayout";
1182 optList = BoardPopUp(squareSize, lineGap, (void*)
1188 InitDrawingHandle(optList + W_BOARD);
1189 currBoard = &optList[W_BOARD];
1190 boardWidget = optList[W_BOARD].handle;
1191 menuBarWidget = optList[W_MENU].handle;
1192 dropMenu = optList[W_DROP].handle;
1193 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1194 formWidget = XtParent(boardWidget);
1195 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1196 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1197 XtGetValues(optList[W_WHITE].handle, args, 2);
1198 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1199 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1200 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1201 XtGetValues(optList[W_PAUSE].handle, args, 2);
1204 xBoardWindow = XtWindow(boardWidget);
1206 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1207 // not need to go into InitDrawingSizes().
1210 * Create X checkmark bitmap and initialize option menu checks.
1212 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1213 checkmark_bits, checkmark_width, checkmark_height);
1219 ReadBitmap(&wIconPixmap, "icon_white.bm",
1220 icon_white_bits, icon_white_width, icon_white_height);
1221 ReadBitmap(&bIconPixmap, "icon_black.bm",
1222 icon_black_bits, icon_black_width, icon_black_height);
1223 iconPixmap = wIconPixmap;
1225 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1226 XtSetValues(shellWidget, args, i);
1229 * Create a cursor for the board widget.
1231 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1232 XChangeWindowAttributes(xDisplay, xBoardWindow,
1233 CWCursor, &window_attributes);
1236 * Inhibit shell resizing.
1238 shellArgs[0].value = (XtArgVal) &w;
1239 shellArgs[1].value = (XtArgVal) &h;
1240 XtGetValues(shellWidget, shellArgs, 2);
1241 shellArgs[4].value = shellArgs[2].value = w;
1242 shellArgs[5].value = shellArgs[3].value = h;
1243 // XtSetValues(shellWidget, &shellArgs[2], 4);
1244 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1245 marginH = h - boardHeight;
1247 CatchDeleteWindow(shellWidget, "QuitProc");
1252 if(appData.logoSize)
1253 { // locate and read user logo
1255 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1256 ASSIGN(userLogo, buf);
1259 if (appData.animate || appData.animateDragging)
1263 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1265 XtAugmentTranslations(formWidget,
1266 XtParseTranslationTable(globalTranslations));
1267 XtAugmentTranslations(formWidget,
1268 XtParseTranslationTable(TranslationsTableMenus));
1270 XtAddEventHandler(formWidget, KeyPressMask, False,
1271 (XtEventHandler) MoveTypeInProc, NULL);
1272 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1273 (XtEventHandler) EventProc, NULL);
1275 /* [AS] Restore layout */
1276 if( wpMoveHistory.visible ) {
1280 if( wpEvalGraph.visible )
1285 if( wpEngineOutput.visible ) {
1286 EngineOutputPopUp();
1291 if (errorExitStatus == -1) {
1292 if (appData.icsActive) {
1293 /* We now wait until we see "login:" from the ICS before
1294 sending the logon script (problems with timestamp otherwise) */
1295 /*ICSInitScript();*/
1296 if (appData.icsInputBox) ICSInputBoxPopUp();
1300 signal(SIGWINCH, TermSizeSigHandler);
1302 signal(SIGINT, IntSigHandler);
1303 signal(SIGTERM, IntSigHandler);
1304 if (*appData.cmailGameName != NULLCHAR) {
1305 signal(SIGUSR1, CmailSigHandler);
1309 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1312 // XtSetKeyboardFocus(shellWidget, formWidget);
1313 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1315 XtAppMainLoop(appContext);
1316 if (appData.debugMode) fclose(debugFP); // [DM] debug
1321 TermSizeSigHandler (int sig)
1327 IntSigHandler (int sig)
1333 CmailSigHandler (int sig)
1338 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1340 /* Activate call-back function CmailSigHandlerCallBack() */
1341 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1343 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1347 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1350 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1352 /**** end signal code ****/
1355 #define Abs(n) ((n)<0 ? -(n) : (n))
1359 InsertPxlSize (char *pattern, int targetPxlSize)
1361 char *base_fnt_lst, strInt[12], *p, *q;
1362 int alternatives, i, len, strIntLen;
1365 * Replace the "*" (if present) in the pixel-size slot of each
1366 * alternative with the targetPxlSize.
1370 while ((p = strchr(p, ',')) != NULL) {
1374 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1375 strIntLen = strlen(strInt);
1376 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1380 while (alternatives--) {
1381 char *comma = strchr(p, ',');
1382 for (i=0; i<14; i++) {
1383 char *hyphen = strchr(p, '-');
1385 if (comma && hyphen > comma) break;
1386 len = hyphen + 1 - p;
1387 if (i == 7 && *p == '*' && len == 2) {
1389 memcpy(q, strInt, strIntLen);
1399 len = comma + 1 - p;
1406 return base_fnt_lst;
1410 CreateFontSet (char *base_fnt_lst)
1413 char **missing_list;
1417 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1418 &missing_list, &missing_count, &def_string);
1419 if (appData.debugMode) {
1421 XFontStruct **font_struct_list;
1422 char **font_name_list;
1423 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1425 fprintf(debugFP, " got list %s, locale %s\n",
1426 XBaseFontNameListOfFontSet(fntSet),
1427 XLocaleOfFontSet(fntSet));
1428 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1429 for (i = 0; i < count; i++) {
1430 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1433 for (i = 0; i < missing_count; i++) {
1434 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1437 if (fntSet == NULL) {
1438 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1443 #else // not ENABLE_NLS
1445 * Find a font that matches "pattern" that is as close as
1446 * possible to the targetPxlSize. Prefer fonts that are k
1447 * pixels smaller to fonts that are k pixels larger. The
1448 * pattern must be in the X Consortium standard format,
1449 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1450 * The return value should be freed with XtFree when no
1454 FindFont (char *pattern, int targetPxlSize)
1456 char **fonts, *p, *best, *scalable, *scalableTail;
1457 int i, j, nfonts, minerr, err, pxlSize;
1459 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1461 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1462 programName, pattern);
1469 for (i=0; i<nfonts; i++) {
1472 if (*p != '-') continue;
1474 if (*p == NULLCHAR) break;
1475 if (*p++ == '-') j++;
1477 if (j < 7) continue;
1480 scalable = fonts[i];
1483 err = pxlSize - targetPxlSize;
1484 if (Abs(err) < Abs(minerr) ||
1485 (minerr > 0 && err < 0 && -err == minerr)) {
1491 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1492 /* If the error is too big and there is a scalable font,
1493 use the scalable font. */
1494 int headlen = scalableTail - scalable;
1495 p = (char *) XtMalloc(strlen(scalable) + 10);
1496 while (isdigit(*scalableTail)) scalableTail++;
1497 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1499 p = (char *) XtMalloc(strlen(best) + 2);
1500 safeStrCpy(p, best, strlen(best)+1 );
1502 if (appData.debugMode) {
1503 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1504 pattern, targetPxlSize, p);
1506 XFreeFontNames(fonts);
1512 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1515 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1521 MarkMenuItem (char *menuRef, int state)
1523 MenuItem *item = MenuNameToItem(menuRef);
1527 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1528 XtSetValues(item->handle, args, 1);
1533 EnableNamedMenuItem (char *menuRef, int state)
1535 MenuItem *item = MenuNameToItem(menuRef);
1537 if(item) XtSetSensitive(item->handle, state);
1541 EnableButtonBar (int state)
1543 XtSetSensitive(optList[W_BUTTON].handle, state);
1548 SetMenuEnables (Enables *enab)
1550 while (enab->name != NULL) {
1551 EnableNamedMenuItem(enab->name, enab->value);
1557 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1558 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1560 if(*nprms == 0) return;
1561 item = MenuNameToItem(prms[0]);
1562 if(item) ((MenuProc *) item->proc) ();
1574 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1575 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1576 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1577 dmEnables[i].piece);
1578 XtSetSensitive(entry, p != NULL || !appData.testLegality
1579 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1580 && !appData.icsActive));
1582 while (p && *p++ == dmEnables[i].piece) count++;
1583 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1585 XtSetArg(args[j], XtNlabel, label); j++;
1586 XtSetValues(entry, args, j);
1591 do_flash_delay (unsigned long msec)
1597 FlashDelay (int flash_delay)
1599 XSync(xDisplay, False);
1600 if(flash_delay) do_flash_delay(flash_delay);
1604 Fraction (int x, int start, int stop)
1606 double f = ((double) x - start)/(stop - start);
1607 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1611 static WindowPlacement wpNew;
1614 CoDrag (Widget sh, WindowPlacement *wp)
1617 int j=0, touch=0, fudge = 2;
1618 GetActualPlacement(sh, wp);
1619 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1620 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1621 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1622 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1623 if(!touch ) return; // only windows that touch co-move
1624 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1625 int heightInc = wpNew.height - wpMain.height;
1626 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1627 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1628 wp->y += fracTop * heightInc;
1629 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1630 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1631 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1632 int widthInc = wpNew.width - wpMain.width;
1633 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1634 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1635 wp->y += fracLeft * widthInc;
1636 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1637 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1639 wp->x += wpNew.x - wpMain.x;
1640 wp->y += wpNew.y - wpMain.y;
1641 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1642 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1643 XtSetArg(args[j], XtNx, wp->x); j++;
1644 XtSetArg(args[j], XtNy, wp->y); j++;
1645 XtSetValues(sh, args, j);
1649 ReSize (WindowPlacement *wp)
1652 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1653 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1654 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1655 if(sqy < sqx) sqx = sqy;
1656 if(sqx != squareSize) {
1657 squareSize = sqx; // adopt new square size
1658 CreatePNGPieces(); // make newly scaled pieces
1659 InitDrawingSizes(0, 0); // creates grid etc.
1660 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1661 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1662 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1663 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1664 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1667 static XtIntervalId delayedDragID = 0;
1676 GetActualPlacement(shellWidget, &wpNew);
1677 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1678 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1679 busy = 0; return; // false alarm
1682 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1683 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1684 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1685 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1687 DrawPosition(True, NULL);
1688 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1696 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1698 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1702 EventProc (Widget widget, caddr_t unused, XEvent *event)
1704 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1705 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1709 * event handler for redrawing the board
1712 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1714 DrawPosition(True, NULL);
1719 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1720 { // [HGM] pv: walk PV
1721 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1724 extern int savedIndex; /* gross that this is global */
1727 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1730 XawTextPosition index, dummy;
1733 XawTextGetSelectionPos(w, &index, &dummy);
1734 XtSetArg(arg, XtNstring, &val);
1735 XtGetValues(w, &arg, 1);
1736 ReplaceComment(savedIndex, val);
1737 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1738 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1742 /* Disable all user input other than deleting the window */
1743 static int frozen = 0;
1749 /* Grab by a widget that doesn't accept input */
1750 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1754 /* Undo a FreezeUI */
1758 if (!frozen) return;
1759 XtRemoveGrab(optList[W_MESSG].handle);
1767 static int oldPausing = FALSE;
1768 static GameMode oldmode = (GameMode) -1;
1771 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1773 if (pausing != oldPausing) {
1774 oldPausing = pausing;
1775 MarkMenuItem("Mode.Pause", pausing);
1777 if (appData.showButtonBar) {
1778 /* Always toggle, don't set. Previous code messes up when
1779 invoked while the button is pressed, as releasing it
1780 toggles the state again. */
1783 XtSetArg(args[0], XtNbackground, &oldbg);
1784 XtSetArg(args[1], XtNforeground, &oldfg);
1785 XtGetValues(optList[W_PAUSE].handle,
1787 XtSetArg(args[0], XtNbackground, oldfg);
1788 XtSetArg(args[1], XtNforeground, oldbg);
1790 XtSetValues(optList[W_PAUSE].handle, args, 2);
1794 wname = ModeToWidgetName(oldmode);
1795 if (wname != NULL) {
1796 MarkMenuItem(wname, False);
1798 wname = ModeToWidgetName(gameMode);
1799 if (wname != NULL) {
1800 MarkMenuItem(wname, True);
1803 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1805 /* Maybe all the enables should be handled here, not just this one */
1806 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1808 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1813 * Button/menu procedures
1816 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1817 char *selected_fen_position=NULL;
1820 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1821 Atom *type_return, XtPointer *value_return,
1822 unsigned long *length_return, int *format_return)
1824 char *selection_tmp;
1826 // if (!selected_fen_position) return False; /* should never happen */
1827 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1828 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1829 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1832 if (f == NULL) return False;
1836 selection_tmp = XtMalloc(len + 1);
1837 count = fread(selection_tmp, 1, len, f);
1840 XtFree(selection_tmp);
1843 selection_tmp[len] = NULLCHAR;
1845 /* note: since no XtSelectionDoneProc was registered, Xt will
1846 * automatically call XtFree on the value returned. So have to
1847 * make a copy of it allocated with XtMalloc */
1848 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1849 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1852 *value_return=selection_tmp;
1853 *length_return=strlen(selection_tmp);
1854 *type_return=*target;
1855 *format_return = 8; /* bits per byte */
1857 } else if (*target == XA_TARGETS(xDisplay)) {
1858 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1859 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1860 targets_tmp[1] = XA_STRING;
1861 *value_return = targets_tmp;
1862 *type_return = XA_ATOM;
1865 // This code leads to a read of value_return out of bounds on 64-bit systems.
1866 // Other code which I have seen always sets *format_return to 32 independent of
1867 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1868 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1869 *format_return = 8 * sizeof(Atom);
1870 if (*format_return > 32) {
1871 *length_return *= *format_return / 32;
1872 *format_return = 32;
1875 *format_return = 32;
1883 /* note: when called from menu all parameters are NULL, so no clue what the
1884 * Widget which was clicked on was, or what the click event was
1887 CopySomething (char *src)
1889 selected_fen_position = src;
1891 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1892 * have a notion of a position that is selected but not copied.
1893 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1895 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1897 SendPositionSelection,
1898 NULL/* lose_ownership_proc */ ,
1899 NULL/* transfer_done_proc */);
1900 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1902 SendPositionSelection,
1903 NULL/* lose_ownership_proc */ ,
1904 NULL/* transfer_done_proc */);
1907 /* function called when the data to Paste is ready */
1909 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1910 Atom *type, XtPointer value, unsigned long *len, int *format)
1913 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1914 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1915 EditPositionPasteFEN(fenstr);
1919 /* called when Paste Position button is pressed,
1920 * all parameters will be NULL */
1922 PastePositionProc ()
1924 XtGetSelectionValue(menuBarWidget,
1925 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1926 /* (XtSelectionCallbackProc) */ PastePositionCB,
1927 NULL, /* client_data passed to PastePositionCB */
1929 /* better to use the time field from the event that triggered the
1930 * call to this function, but that isn't trivial to get
1937 /* note: when called from menu all parameters are NULL, so no clue what the
1938 * Widget which was clicked on was, or what the click event was
1940 /* function called when the data to Paste is ready */
1942 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1943 Atom *type, XtPointer value, unsigned long *len, int *format)
1946 if (value == NULL || *len == 0) {
1947 return; /* nothing had been selected to copy */
1949 f = fopen(gamePasteFilename, "w");
1951 DisplayError(_("Can't open temp file"), errno);
1954 fwrite(value, 1, *len, f);
1957 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1960 /* called when Paste Game button is pressed,
1961 * all parameters will be NULL */
1965 XtGetSelectionValue(menuBarWidget,
1966 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1967 /* (XtSelectionCallbackProc) */ PasteGameCB,
1968 NULL, /* client_data passed to PasteGameCB */
1970 /* better to use the time field from the event that triggered the
1971 * call to this function, but that isn't trivial to get
1980 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1987 { // bassic primitive for determining if modifier keys are pressed
1988 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
1991 XQueryKeymap(xDisplay,keys);
1992 for(i=0; i<6; i++) {
1994 j = XKeysymToKeycode(xDisplay, codes[i]);
1995 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2001 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2005 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2006 if ( n == 1 && *buf >= 32 // printable
2007 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2008 ) BoxAutoPopUp (buf);
2012 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2013 { // [HGM] input: let up-arrow recall previous line from history
2018 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2019 { // [HGM] input: let down-arrow recall next line from history
2024 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2030 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2032 if (!TempBackwardActive) {
2033 TempBackwardActive = True;
2039 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2041 /* Check to see if triggered by a key release event for a repeating key.
2042 * If so the next queued event will be a key press of the same key at the same time */
2043 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2045 XPeekEvent(xDisplay, &next);
2046 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2047 next.xkey.keycode == event->xkey.keycode)
2051 TempBackwardActive = False;
2055 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2056 { // called as key binding
2059 if (nprms && *nprms > 0)
2063 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2069 { // called from menu
2070 ManInner(NULL, NULL, NULL, NULL);
2074 SetWindowTitle (char *text, char *title, char *icon)
2078 if (appData.titleInWindow) {
2080 XtSetArg(args[i], XtNlabel, text); i++;
2081 XtSetValues(titleWidget, args, i);
2084 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2085 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2086 XtSetValues(shellWidget, args, i);
2087 XSync(xDisplay, False);
2092 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2098 DisplayIcsInteractionTitle (String message)
2100 if (oldICSInteractionTitle == NULL) {
2101 /* Magic to find the old window title, adapted from vim */
2102 char *wina = getenv("WINDOWID");
2104 Window win = (Window) atoi(wina);
2105 Window root, parent, *children;
2106 unsigned int nchildren;
2107 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2109 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2110 if (!XQueryTree(xDisplay, win, &root, &parent,
2111 &children, &nchildren)) break;
2112 if (children) XFree((void *)children);
2113 if (parent == root || parent == 0) break;
2116 XSetErrorHandler(oldHandler);
2118 if (oldICSInteractionTitle == NULL) {
2119 oldICSInteractionTitle = "xterm";
2122 printf("\033]0;%s\007", message);
2127 XtIntervalId delayedEventTimerXID = 0;
2128 DelayedEventCallback delayedEventCallback = 0;
2133 delayedEventTimerXID = 0;
2134 delayedEventCallback();
2138 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2140 if(delayedEventTimerXID && delayedEventCallback == cb)
2141 // [HGM] alive: replace, rather than add or flush identical event
2142 XtRemoveTimeOut(delayedEventTimerXID);
2143 delayedEventCallback = cb;
2144 delayedEventTimerXID =
2145 XtAppAddTimeOut(appContext, millisec,
2146 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2149 DelayedEventCallback
2152 if (delayedEventTimerXID) {
2153 return delayedEventCallback;
2160 CancelDelayedEvent ()
2162 if (delayedEventTimerXID) {
2163 XtRemoveTimeOut(delayedEventTimerXID);
2164 delayedEventTimerXID = 0;
2168 XtIntervalId loadGameTimerXID = 0;
2171 LoadGameTimerRunning ()
2173 return loadGameTimerXID != 0;
2177 StopLoadGameTimer ()
2179 if (loadGameTimerXID != 0) {
2180 XtRemoveTimeOut(loadGameTimerXID);
2181 loadGameTimerXID = 0;
2189 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2191 loadGameTimerXID = 0;
2196 StartLoadGameTimer (long millisec)
2199 XtAppAddTimeOut(appContext, millisec,
2200 (XtTimerCallbackProc) LoadGameTimerCallback,
2204 XtIntervalId analysisClockXID = 0;
2207 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2209 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2210 || appData.icsEngineAnalyze) { // [DM]
2211 AnalysisPeriodicEvent(0);
2212 StartAnalysisClock();
2217 StartAnalysisClock ()
2220 XtAppAddTimeOut(appContext, 2000,
2221 (XtTimerCallbackProc) AnalysisClockCallback,
2225 XtIntervalId clockTimerXID = 0;
2228 ClockTimerRunning ()
2230 return clockTimerXID != 0;
2236 if (clockTimerXID != 0) {
2237 XtRemoveTimeOut(clockTimerXID);
2246 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2253 StartClockTimer (long millisec)
2256 XtAppAddTimeOut(appContext, millisec,
2257 (XtTimerCallbackProc) ClockTimerCallback,
2262 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2266 Widget w = (Widget) opt->handle;
2268 /* check for low time warning */
2269 Pixel foregroundOrWarningColor = timerForegroundPixel;
2272 appData.lowTimeWarning &&
2273 (timer / 1000) < appData.icsAlarmTime)
2274 foregroundOrWarningColor = lowTimeWarningColor;
2276 if (appData.clockMode) {
2277 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2278 XtSetArg(args[0], XtNlabel, buf);
2280 snprintf(buf, MSG_SIZ, "%s ", color);
2281 XtSetArg(args[0], XtNlabel, buf);
2286 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2287 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2289 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2290 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2293 XtSetValues(w, args, 3);
2296 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2299 SetClockIcon (int color)
2302 Pixmap pm = *clockIcons[color];
2303 if (iconPixmap != pm) {
2305 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2306 XtSetValues(shellWidget, args, 1);
2310 #define INPUT_SOURCE_BUF_SIZE 8192
2319 char buf[INPUT_SOURCE_BUF_SIZE];
2324 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2326 InputSource *is = (InputSource *) closure;
2331 if (is->lineByLine) {
2332 count = read(is->fd, is->unused,
2333 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2335 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2338 is->unused += count;
2340 while (p < is->unused) {
2341 q = memchr(p, '\n', is->unused - p);
2342 if (q == NULL) break;
2344 (is->func)(is, is->closure, p, q - p, 0);
2348 while (p < is->unused) {
2353 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2358 (is->func)(is, is->closure, is->buf, count, error);
2363 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2366 ChildProc *cp = (ChildProc *) pr;
2368 is = (InputSource *) calloc(1, sizeof(InputSource));
2369 is->lineByLine = lineByLine;
2373 is->fd = fileno(stdin);
2375 is->kind = cp->kind;
2376 is->fd = cp->fdFrom;
2379 is->unused = is->buf;
2382 is->xid = XtAppAddInput(appContext, is->fd,
2383 (XtPointer) (XtInputReadMask),
2384 (XtInputCallbackProc) DoInputCallback,
2386 is->closure = closure;
2387 return (InputSourceRef) is;
2391 RemoveInputSource (InputSourceRef isr)
2393 InputSource *is = (InputSource *) isr;
2395 if (is->xid == 0) return;
2396 XtRemoveInput(is->xid);
2402 static Boolean frameWaiting;
2405 FrameAlarm (int sig)
2407 frameWaiting = False;
2408 /* In case System-V style signals. Needed?? */
2409 signal(SIGALRM, FrameAlarm);
2413 FrameDelay (int time)
2415 struct itimerval delay;
2417 XSync(xDisplay, False);
2420 frameWaiting = True;
2421 signal(SIGALRM, FrameAlarm);
2422 delay.it_interval.tv_sec =
2423 delay.it_value.tv_sec = time / 1000;
2424 delay.it_interval.tv_usec =
2425 delay.it_value.tv_usec = (time % 1000) * 1000;
2426 setitimer(ITIMER_REAL, &delay, NULL);
2427 while (frameWaiting) pause();
2428 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2429 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2430 setitimer(ITIMER_REAL, &delay, NULL);
2437 FrameDelay (int time)
2439 XSync(xDisplay, False);
2441 usleep(time * 1000);
2447 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2449 char buf[MSG_SIZ], *logoName = buf;
2450 if(appData.logo[n][0]) {
2451 logoName = appData.logo[n];
2452 } else if(appData.autoLogo) {
2453 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2454 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2455 } else if(appData.directory[n] && appData.directory[n][0]) {
2456 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2460 { ASSIGN(cps->programLogo, logoName); }
2464 UpdateLogos (int displ)
2466 if(optList[W_WHITE-1].handle == NULL) return;
2467 LoadLogo(&first, 0, 0);
2468 LoadLogo(&second, 1, appData.icsActive);
2469 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);