2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
64 #include <cairo/cairo.h>
65 #include <cairo/cairo-xlib.h>
68 # if HAVE_SYS_SOCKET_H
69 # include <sys/socket.h>
70 # include <netinet/in.h>
72 # else /* not HAVE_SYS_SOCKET_H */
73 # if HAVE_LAN_SOCKET_H
74 # include <lan/socket.h>
76 # include <lan/netdb.h>
77 # else /* not HAVE_LAN_SOCKET_H */
78 # define OMIT_SOCKETS 1
79 # endif /* not HAVE_LAN_SOCKET_H */
80 # endif /* not HAVE_SYS_SOCKET_H */
81 #endif /* !OMIT_SOCKETS */
86 #else /* not STDC_HEADERS */
87 extern char *getenv();
90 # else /* not HAVE_STRING_H */
92 # endif /* not HAVE_STRING_H */
93 #endif /* not STDC_HEADERS */
96 # include <sys/fcntl.h>
97 #else /* not HAVE_SYS_FCNTL_H */
100 # endif /* HAVE_FCNTL_H */
101 #endif /* not HAVE_SYS_FCNTL_H */
103 #if HAVE_SYS_SYSTEMINFO_H
104 # include <sys/systeminfo.h>
105 #endif /* HAVE_SYS_SYSTEMINFO_H */
107 #if TIME_WITH_SYS_TIME
108 # include <sys/time.h>
112 # include <sys/time.h>
123 # include <sys/wait.h>
128 # define NAMLEN(dirent) strlen((dirent)->d_name)
129 # define HAVE_DIR_STRUCT
131 # define dirent direct
132 # define NAMLEN(dirent) (dirent)->d_namlen
134 # include <sys/ndir.h>
135 # define HAVE_DIR_STRUCT
138 # include <sys/dir.h>
139 # define HAVE_DIR_STRUCT
143 # define HAVE_DIR_STRUCT
151 #include <X11/Intrinsic.h>
152 #include <X11/StringDefs.h>
153 #include <X11/Shell.h>
154 #include <X11/cursorfont.h>
155 #include <X11/Xatom.h>
156 #include <X11/Xmu/Atoms.h>
158 #include <X11/Xaw3d/Dialog.h>
159 #include <X11/Xaw3d/Form.h>
160 #include <X11/Xaw3d/List.h>
161 #include <X11/Xaw3d/Label.h>
162 #include <X11/Xaw3d/SimpleMenu.h>
163 #include <X11/Xaw3d/SmeBSB.h>
164 #include <X11/Xaw3d/SmeLine.h>
165 #include <X11/Xaw3d/Box.h>
166 #include <X11/Xaw3d/MenuButton.h>
167 #include <X11/Xaw3d/Text.h>
168 #include <X11/Xaw3d/AsciiText.h>
170 #include <X11/Xaw/Dialog.h>
171 #include <X11/Xaw/Form.h>
172 #include <X11/Xaw/List.h>
173 #include <X11/Xaw/Label.h>
174 #include <X11/Xaw/SimpleMenu.h>
175 #include <X11/Xaw/SmeBSB.h>
176 #include <X11/Xaw/SmeLine.h>
177 #include <X11/Xaw/Box.h>
178 #include <X11/Xaw/MenuButton.h>
179 #include <X11/Xaw/Text.h>
180 #include <X11/Xaw/AsciiText.h>
183 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
192 #include "backendz.h"
196 #include "xgamelist.h"
197 #include "xhistory.h"
201 #include "engineoutput.h"
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 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
994 typedef struct {char *name, *value; } Config;
995 static Config configList[] = {
996 { "Datadir", DATADIR },
997 { "Sysconfdir", SYSCONFDIR },
1002 for(i=0; configList[i].name; i++) {
1003 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1004 if(argc > 2) printf("%s", configList[i].value);
1005 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1010 programName = strrchr(argv[0], '/');
1011 if (programName == NULL)
1012 programName = argv[0];
1017 XtSetLanguageProc(NULL, NULL, NULL);
1018 if (appData.debugMode) {
1019 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1022 bindtextdomain(PACKAGE, LOCALEDIR);
1023 textdomain(PACKAGE);
1026 appData.boardSize = "";
1027 InitAppData(ConvertToLine(argc, argv));
1029 if (p == NULL) p = "/tmp";
1030 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1031 gameCopyFilename = (char*) malloc(i);
1032 gamePasteFilename = (char*) malloc(i);
1033 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1034 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1036 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1037 static char buf[MSG_SIZ];
1038 EscapeExpand(buf, appData.firstInitString);
1039 appData.firstInitString = strdup(buf);
1040 EscapeExpand(buf, appData.secondInitString);
1041 appData.secondInitString = strdup(buf);
1042 EscapeExpand(buf, appData.firstComputerString);
1043 appData.firstComputerString = strdup(buf);
1044 EscapeExpand(buf, appData.secondComputerString);
1045 appData.secondComputerString = strdup(buf);
1048 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1051 if (chdir(chessDir) != 0) {
1052 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1058 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1059 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1060 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1061 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1064 setbuf(debugFP, NULL);
1067 /* [HGM,HR] make sure board size is acceptable */
1068 if(appData.NrFiles > BOARD_FILES ||
1069 appData.NrRanks > BOARD_RANKS )
1070 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1073 /* This feature does not work; animation needs a rewrite */
1074 appData.highlightDragging = FALSE;
1078 gameInfo.variant = StringToVariant(appData.variant);
1079 InitPosition(FALSE);
1082 XtAppInitialize(&appContext, "XBoard", shellOptions,
1083 XtNumber(shellOptions),
1084 &argc, argv, xboardResources, NULL, 0);
1086 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1087 clientResources, XtNumber(clientResources),
1090 xDisplay = XtDisplay(shellWidget);
1091 xScreen = DefaultScreen(xDisplay);
1092 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1095 * determine size, based on supplied or remembered -size, or screen size
1097 if (isdigit(appData.boardSize[0])) {
1098 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1099 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1100 &fontPxlSize, &smallLayout, &tinyLayout);
1102 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1103 programName, appData.boardSize);
1107 /* Find some defaults; use the nearest known size */
1108 SizeDefaults *szd, *nearest;
1109 int distance = 99999;
1110 nearest = szd = sizeDefaults;
1111 while (szd->name != NULL) {
1112 if (abs(szd->squareSize - squareSize) < distance) {
1114 distance = abs(szd->squareSize - squareSize);
1115 if (distance == 0) break;
1119 if (i < 2) lineGap = nearest->lineGap;
1120 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1121 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1122 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1123 if (i < 6) smallLayout = nearest->smallLayout;
1124 if (i < 7) tinyLayout = nearest->tinyLayout;
1127 SizeDefaults *szd = sizeDefaults;
1128 if (*appData.boardSize == NULLCHAR) {
1129 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1130 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1133 if (szd->name == NULL) szd--;
1134 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1136 while (szd->name != NULL &&
1137 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1138 if (szd->name == NULL) {
1139 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1140 programName, appData.boardSize);
1144 squareSize = szd->squareSize;
1145 lineGap = szd->lineGap;
1146 clockFontPxlSize = szd->clockFontPxlSize;
1147 coordFontPxlSize = szd->coordFontPxlSize;
1148 fontPxlSize = szd->fontPxlSize;
1149 smallLayout = szd->smallLayout;
1150 tinyLayout = szd->tinyLayout;
1151 // [HGM] font: use defaults from settings file if available and not overruled
1154 defaultLineGap = lineGap;
1155 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1157 /* [HR] height treated separately (hacked) */
1158 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1159 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1162 * Determine what fonts to use.
1164 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1167 * Detect if there are not enough colors available and adapt.
1169 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1170 appData.monoMode = True;
1173 forceMono = MakeColors();
1176 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1178 appData.monoMode = True;
1181 if (appData.monoMode && appData.debugMode) {
1182 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1183 (unsigned long) XWhitePixel(xDisplay, xScreen),
1184 (unsigned long) XBlackPixel(xDisplay, xScreen));
1187 ParseIcsTextColors();
1189 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1195 layoutName = "tinyLayout";
1196 } else if (smallLayout) {
1197 layoutName = "smallLayout";
1199 layoutName = "normalLayout";
1202 optList = BoardPopUp(squareSize, lineGap, (void*)
1208 InitDrawingHandle(optList + W_BOARD);
1209 currBoard = &optList[W_BOARD];
1210 boardWidget = optList[W_BOARD].handle;
1211 menuBarWidget = optList[W_MENU].handle;
1212 dropMenu = optList[W_DROP].handle;
1213 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1214 formWidget = XtParent(boardWidget);
1215 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1216 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1217 XtGetValues(optList[W_WHITE].handle, args, 2);
1218 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1219 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1220 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1221 XtGetValues(optList[W_PAUSE].handle, args, 2);
1224 xBoardWindow = XtWindow(boardWidget);
1226 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1227 // not need to go into InitDrawingSizes().
1230 * Create X checkmark bitmap and initialize option menu checks.
1232 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1233 checkmark_bits, checkmark_width, checkmark_height);
1239 ReadBitmap(&wIconPixmap, "icon_white.bm",
1240 icon_white_bits, icon_white_width, icon_white_height);
1241 ReadBitmap(&bIconPixmap, "icon_black.bm",
1242 icon_black_bits, icon_black_width, icon_black_height);
1243 iconPixmap = wIconPixmap;
1245 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1246 XtSetValues(shellWidget, args, i);
1249 * Create a cursor for the board widget.
1251 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1252 XChangeWindowAttributes(xDisplay, xBoardWindow,
1253 CWCursor, &window_attributes);
1256 * Inhibit shell resizing.
1258 shellArgs[0].value = (XtArgVal) &w;
1259 shellArgs[1].value = (XtArgVal) &h;
1260 XtGetValues(shellWidget, shellArgs, 2);
1261 shellArgs[4].value = shellArgs[2].value = w;
1262 shellArgs[5].value = shellArgs[3].value = h;
1263 // XtSetValues(shellWidget, &shellArgs[2], 4);
1264 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1265 marginH = h - boardHeight;
1267 CatchDeleteWindow(shellWidget, "QuitProc");
1272 if(appData.logoSize)
1273 { // locate and read user logo
1275 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1276 ASSIGN(userLogo, buf);
1279 if (appData.animate || appData.animateDragging)
1283 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1285 XtAugmentTranslations(formWidget,
1286 XtParseTranslationTable(globalTranslations));
1287 XtAugmentTranslations(formWidget,
1288 XtParseTranslationTable(TranslationsTableMenus));
1290 XtAddEventHandler(formWidget, KeyPressMask, False,
1291 (XtEventHandler) MoveTypeInProc, NULL);
1292 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1293 (XtEventHandler) EventProc, NULL);
1295 /* [AS] Restore layout */
1296 if( wpMoveHistory.visible ) {
1300 if( wpEvalGraph.visible )
1305 if( wpEngineOutput.visible ) {
1306 EngineOutputPopUp();
1311 if (errorExitStatus == -1) {
1312 if (appData.icsActive) {
1313 /* We now wait until we see "login:" from the ICS before
1314 sending the logon script (problems with timestamp otherwise) */
1315 /*ICSInitScript();*/
1316 if (appData.icsInputBox) ICSInputBoxPopUp();
1320 signal(SIGWINCH, TermSizeSigHandler);
1322 signal(SIGINT, IntSigHandler);
1323 signal(SIGTERM, IntSigHandler);
1324 if (*appData.cmailGameName != NULLCHAR) {
1325 signal(SIGUSR1, CmailSigHandler);
1329 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1332 // XtSetKeyboardFocus(shellWidget, formWidget);
1333 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1335 XtAppMainLoop(appContext);
1336 if (appData.debugMode) fclose(debugFP); // [DM] debug
1341 TermSizeSigHandler (int sig)
1347 IntSigHandler (int sig)
1353 CmailSigHandler (int sig)
1358 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1360 /* Activate call-back function CmailSigHandlerCallBack() */
1361 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1363 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1367 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1370 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1372 /**** end signal code ****/
1375 #define Abs(n) ((n)<0 ? -(n) : (n))
1379 InsertPxlSize (char *pattern, int targetPxlSize)
1381 char *base_fnt_lst, strInt[12], *p, *q;
1382 int alternatives, i, len, strIntLen;
1385 * Replace the "*" (if present) in the pixel-size slot of each
1386 * alternative with the targetPxlSize.
1390 while ((p = strchr(p, ',')) != NULL) {
1394 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1395 strIntLen = strlen(strInt);
1396 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1400 while (alternatives--) {
1401 char *comma = strchr(p, ',');
1402 for (i=0; i<14; i++) {
1403 char *hyphen = strchr(p, '-');
1405 if (comma && hyphen > comma) break;
1406 len = hyphen + 1 - p;
1407 if (i == 7 && *p == '*' && len == 2) {
1409 memcpy(q, strInt, strIntLen);
1419 len = comma + 1 - p;
1426 return base_fnt_lst;
1430 CreateFontSet (char *base_fnt_lst)
1433 char **missing_list;
1437 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1438 &missing_list, &missing_count, &def_string);
1439 if (appData.debugMode) {
1441 XFontStruct **font_struct_list;
1442 char **font_name_list;
1443 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1445 fprintf(debugFP, " got list %s, locale %s\n",
1446 XBaseFontNameListOfFontSet(fntSet),
1447 XLocaleOfFontSet(fntSet));
1448 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1449 for (i = 0; i < count; i++) {
1450 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1453 for (i = 0; i < missing_count; i++) {
1454 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1457 if (fntSet == NULL) {
1458 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1463 #else // not ENABLE_NLS
1465 * Find a font that matches "pattern" that is as close as
1466 * possible to the targetPxlSize. Prefer fonts that are k
1467 * pixels smaller to fonts that are k pixels larger. The
1468 * pattern must be in the X Consortium standard format,
1469 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1470 * The return value should be freed with XtFree when no
1474 FindFont (char *pattern, int targetPxlSize)
1476 char **fonts, *p, *best, *scalable, *scalableTail;
1477 int i, j, nfonts, minerr, err, pxlSize;
1479 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1481 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1482 programName, pattern);
1489 for (i=0; i<nfonts; i++) {
1492 if (*p != '-') continue;
1494 if (*p == NULLCHAR) break;
1495 if (*p++ == '-') j++;
1497 if (j < 7) continue;
1500 scalable = fonts[i];
1503 err = pxlSize - targetPxlSize;
1504 if (Abs(err) < Abs(minerr) ||
1505 (minerr > 0 && err < 0 && -err == minerr)) {
1511 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1512 /* If the error is too big and there is a scalable font,
1513 use the scalable font. */
1514 int headlen = scalableTail - scalable;
1515 p = (char *) XtMalloc(strlen(scalable) + 10);
1516 while (isdigit(*scalableTail)) scalableTail++;
1517 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1519 p = (char *) XtMalloc(strlen(best) + 2);
1520 safeStrCpy(p, best, strlen(best)+1 );
1522 if (appData.debugMode) {
1523 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1524 pattern, targetPxlSize, p);
1526 XFreeFontNames(fonts);
1532 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1535 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1541 MarkMenuItem (char *menuRef, int state)
1543 MenuItem *item = MenuNameToItem(menuRef);
1547 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1548 XtSetValues(item->handle, args, 1);
1553 EnableNamedMenuItem (char *menuRef, int state)
1555 MenuItem *item = MenuNameToItem(menuRef);
1557 if(item) XtSetSensitive(item->handle, state);
1561 EnableButtonBar (int state)
1563 XtSetSensitive(optList[W_BUTTON].handle, state);
1568 SetMenuEnables (Enables *enab)
1570 while (enab->name != NULL) {
1571 EnableNamedMenuItem(enab->name, enab->value);
1577 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1578 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1580 if(*nprms == 0) return;
1581 item = MenuNameToItem(prms[0]);
1582 if(item) ((MenuProc *) item->proc) ();
1594 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1595 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1596 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1597 dmEnables[i].piece);
1598 XtSetSensitive(entry, p != NULL || !appData.testLegality
1599 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1600 && !appData.icsActive));
1602 while (p && *p++ == dmEnables[i].piece) count++;
1603 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1605 XtSetArg(args[j], XtNlabel, label); j++;
1606 XtSetValues(entry, args, j);
1611 do_flash_delay (unsigned long msec)
1617 FlashDelay (int flash_delay)
1619 XSync(xDisplay, False);
1620 if(flash_delay) do_flash_delay(flash_delay);
1624 Fraction (int x, int start, int stop)
1626 double f = ((double) x - start)/(stop - start);
1627 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1631 static WindowPlacement wpNew;
1634 CoDrag (Widget sh, WindowPlacement *wp)
1637 int j=0, touch=0, fudge = 2;
1638 GetActualPlacement(sh, wp);
1639 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1640 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1641 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1642 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1643 if(!touch ) return; // only windows that touch co-move
1644 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1645 int heightInc = wpNew.height - wpMain.height;
1646 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1647 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1648 wp->y += fracTop * heightInc;
1649 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1650 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1651 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1652 int widthInc = wpNew.width - wpMain.width;
1653 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1654 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1655 wp->y += fracLeft * widthInc;
1656 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1657 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1659 wp->x += wpNew.x - wpMain.x;
1660 wp->y += wpNew.y - wpMain.y;
1661 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1662 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1663 XtSetArg(args[j], XtNx, wp->x); j++;
1664 XtSetArg(args[j], XtNy, wp->y); j++;
1665 XtSetValues(sh, args, j);
1669 ReSize (WindowPlacement *wp)
1672 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1673 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1674 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1675 if(sqy < sqx) sqx = sqy;
1676 if(sqx != squareSize) {
1677 squareSize = sqx; // adopt new square size
1678 CreatePNGPieces(); // make newly scaled pieces
1679 InitDrawingSizes(0, 0); // creates grid etc.
1680 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1681 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1682 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1683 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1684 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1687 static XtIntervalId delayedDragID = 0;
1696 GetActualPlacement(shellWidget, &wpNew);
1697 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1698 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1699 busy = 0; return; // false alarm
1702 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1703 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1704 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1705 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1707 DrawPosition(True, NULL);
1708 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1716 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1718 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1722 EventProc (Widget widget, caddr_t unused, XEvent *event)
1724 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1725 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1729 * event handler for redrawing the board
1732 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1734 DrawPosition(True, NULL);
1739 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1740 { // [HGM] pv: walk PV
1741 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1744 extern int savedIndex; /* gross that this is global */
1747 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1750 XawTextPosition index, dummy;
1753 XawTextGetSelectionPos(w, &index, &dummy);
1754 XtSetArg(arg, XtNstring, &val);
1755 XtGetValues(w, &arg, 1);
1756 ReplaceComment(savedIndex, val);
1757 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1758 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1762 /* Disable all user input other than deleting the window */
1763 static int frozen = 0;
1769 /* Grab by a widget that doesn't accept input */
1770 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1774 /* Undo a FreezeUI */
1778 if (!frozen) return;
1779 XtRemoveGrab(optList[W_MESSG].handle);
1787 static int oldPausing = FALSE;
1788 static GameMode oldmode = (GameMode) -1;
1791 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1793 if (pausing != oldPausing) {
1794 oldPausing = pausing;
1795 MarkMenuItem("Mode.Pause", pausing);
1797 if (appData.showButtonBar) {
1798 /* Always toggle, don't set. Previous code messes up when
1799 invoked while the button is pressed, as releasing it
1800 toggles the state again. */
1803 XtSetArg(args[0], XtNbackground, &oldbg);
1804 XtSetArg(args[1], XtNforeground, &oldfg);
1805 XtGetValues(optList[W_PAUSE].handle,
1807 XtSetArg(args[0], XtNbackground, oldfg);
1808 XtSetArg(args[1], XtNforeground, oldbg);
1810 XtSetValues(optList[W_PAUSE].handle, args, 2);
1814 wname = ModeToWidgetName(oldmode);
1815 if (wname != NULL) {
1816 MarkMenuItem(wname, False);
1818 wname = ModeToWidgetName(gameMode);
1819 if (wname != NULL) {
1820 MarkMenuItem(wname, True);
1823 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1825 /* Maybe all the enables should be handled here, not just this one */
1826 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1828 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1833 * Button/menu procedures
1836 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1837 char *selected_fen_position=NULL;
1840 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1841 Atom *type_return, XtPointer *value_return,
1842 unsigned long *length_return, int *format_return)
1844 char *selection_tmp;
1846 // if (!selected_fen_position) return False; /* should never happen */
1847 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1848 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1849 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1852 if (f == NULL) return False;
1856 selection_tmp = XtMalloc(len + 1);
1857 count = fread(selection_tmp, 1, len, f);
1860 XtFree(selection_tmp);
1863 selection_tmp[len] = NULLCHAR;
1865 /* note: since no XtSelectionDoneProc was registered, Xt will
1866 * automatically call XtFree on the value returned. So have to
1867 * make a copy of it allocated with XtMalloc */
1868 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1869 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1872 *value_return=selection_tmp;
1873 *length_return=strlen(selection_tmp);
1874 *type_return=*target;
1875 *format_return = 8; /* bits per byte */
1877 } else if (*target == XA_TARGETS(xDisplay)) {
1878 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1879 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1880 targets_tmp[1] = XA_STRING;
1881 *value_return = targets_tmp;
1882 *type_return = XA_ATOM;
1885 // This code leads to a read of value_return out of bounds on 64-bit systems.
1886 // Other code which I have seen always sets *format_return to 32 independent of
1887 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1888 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1889 *format_return = 8 * sizeof(Atom);
1890 if (*format_return > 32) {
1891 *length_return *= *format_return / 32;
1892 *format_return = 32;
1895 *format_return = 32;
1903 /* note: when called from menu all parameters are NULL, so no clue what the
1904 * Widget which was clicked on was, or what the click event was
1907 CopySomething (char *src)
1909 selected_fen_position = src;
1911 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1912 * have a notion of a position that is selected but not copied.
1913 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1915 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1917 SendPositionSelection,
1918 NULL/* lose_ownership_proc */ ,
1919 NULL/* transfer_done_proc */);
1920 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1922 SendPositionSelection,
1923 NULL/* lose_ownership_proc */ ,
1924 NULL/* transfer_done_proc */);
1927 /* function called when the data to Paste is ready */
1929 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1930 Atom *type, XtPointer value, unsigned long *len, int *format)
1933 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1934 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1935 EditPositionPasteFEN(fenstr);
1939 /* called when Paste Position button is pressed,
1940 * all parameters will be NULL */
1942 PastePositionProc ()
1944 XtGetSelectionValue(menuBarWidget,
1945 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1946 /* (XtSelectionCallbackProc) */ PastePositionCB,
1947 NULL, /* client_data passed to PastePositionCB */
1949 /* better to use the time field from the event that triggered the
1950 * call to this function, but that isn't trivial to get
1957 /* note: when called from menu all parameters are NULL, so no clue what the
1958 * Widget which was clicked on was, or what the click event was
1960 /* function called when the data to Paste is ready */
1962 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1963 Atom *type, XtPointer value, unsigned long *len, int *format)
1966 if (value == NULL || *len == 0) {
1967 return; /* nothing had been selected to copy */
1969 f = fopen(gamePasteFilename, "w");
1971 DisplayError(_("Can't open temp file"), errno);
1974 fwrite(value, 1, *len, f);
1977 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1980 /* called when Paste Game button is pressed,
1981 * all parameters will be NULL */
1985 XtGetSelectionValue(menuBarWidget,
1986 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1987 /* (XtSelectionCallbackProc) */ PasteGameCB,
1988 NULL, /* client_data passed to PasteGameCB */
1990 /* better to use the time field from the event that triggered the
1991 * call to this function, but that isn't trivial to get
2000 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2007 { // bassic primitive for determining if modifier keys are pressed
2008 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2011 XQueryKeymap(xDisplay,keys);
2012 for(i=0; i<6; i++) {
2014 j = XKeysymToKeycode(xDisplay, codes[i]);
2015 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2021 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2025 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2026 if ( n == 1 && *buf >= 32 // printable
2027 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2028 ) BoxAutoPopUp (buf);
2032 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2033 { // [HGM] input: let up-arrow recall previous line from history
2038 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2039 { // [HGM] input: let down-arrow recall next line from history
2044 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2050 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2052 if (!TempBackwardActive) {
2053 TempBackwardActive = True;
2059 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2061 /* Check to see if triggered by a key release event for a repeating key.
2062 * If so the next queued event will be a key press of the same key at the same time */
2063 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2065 XPeekEvent(xDisplay, &next);
2066 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2067 next.xkey.keycode == event->xkey.keycode)
2071 TempBackwardActive = False;
2075 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2076 { // called as key binding
2079 if (nprms && *nprms > 0)
2083 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2089 { // called from menu
2090 ManInner(NULL, NULL, NULL, NULL);
2094 SetWindowTitle (char *text, char *title, char *icon)
2098 if (appData.titleInWindow) {
2100 XtSetArg(args[i], XtNlabel, text); i++;
2101 XtSetValues(titleWidget, args, i);
2104 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2105 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2106 XtSetValues(shellWidget, args, i);
2107 XSync(xDisplay, False);
2112 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2118 DisplayIcsInteractionTitle (String message)
2120 if (oldICSInteractionTitle == NULL) {
2121 /* Magic to find the old window title, adapted from vim */
2122 char *wina = getenv("WINDOWID");
2124 Window win = (Window) atoi(wina);
2125 Window root, parent, *children;
2126 unsigned int nchildren;
2127 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2129 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2130 if (!XQueryTree(xDisplay, win, &root, &parent,
2131 &children, &nchildren)) break;
2132 if (children) XFree((void *)children);
2133 if (parent == root || parent == 0) break;
2136 XSetErrorHandler(oldHandler);
2138 if (oldICSInteractionTitle == NULL) {
2139 oldICSInteractionTitle = "xterm";
2142 printf("\033]0;%s\007", message);
2147 XtIntervalId delayedEventTimerXID = 0;
2148 DelayedEventCallback delayedEventCallback = 0;
2153 delayedEventTimerXID = 0;
2154 delayedEventCallback();
2158 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2160 if(delayedEventTimerXID && delayedEventCallback == cb)
2161 // [HGM] alive: replace, rather than add or flush identical event
2162 XtRemoveTimeOut(delayedEventTimerXID);
2163 delayedEventCallback = cb;
2164 delayedEventTimerXID =
2165 XtAppAddTimeOut(appContext, millisec,
2166 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2169 DelayedEventCallback
2172 if (delayedEventTimerXID) {
2173 return delayedEventCallback;
2180 CancelDelayedEvent ()
2182 if (delayedEventTimerXID) {
2183 XtRemoveTimeOut(delayedEventTimerXID);
2184 delayedEventTimerXID = 0;
2188 XtIntervalId loadGameTimerXID = 0;
2191 LoadGameTimerRunning ()
2193 return loadGameTimerXID != 0;
2197 StopLoadGameTimer ()
2199 if (loadGameTimerXID != 0) {
2200 XtRemoveTimeOut(loadGameTimerXID);
2201 loadGameTimerXID = 0;
2209 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2211 loadGameTimerXID = 0;
2216 StartLoadGameTimer (long millisec)
2219 XtAppAddTimeOut(appContext, millisec,
2220 (XtTimerCallbackProc) LoadGameTimerCallback,
2224 XtIntervalId analysisClockXID = 0;
2227 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2229 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2230 || appData.icsEngineAnalyze) { // [DM]
2231 AnalysisPeriodicEvent(0);
2232 StartAnalysisClock();
2237 StartAnalysisClock ()
2240 XtAppAddTimeOut(appContext, 2000,
2241 (XtTimerCallbackProc) AnalysisClockCallback,
2245 XtIntervalId clockTimerXID = 0;
2248 ClockTimerRunning ()
2250 return clockTimerXID != 0;
2256 if (clockTimerXID != 0) {
2257 XtRemoveTimeOut(clockTimerXID);
2266 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2273 StartClockTimer (long millisec)
2276 XtAppAddTimeOut(appContext, millisec,
2277 (XtTimerCallbackProc) ClockTimerCallback,
2282 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2286 Widget w = (Widget) opt->handle;
2288 /* check for low time warning */
2289 Pixel foregroundOrWarningColor = timerForegroundPixel;
2292 appData.lowTimeWarning &&
2293 (timer / 1000) < appData.icsAlarmTime)
2294 foregroundOrWarningColor = lowTimeWarningColor;
2296 if (appData.clockMode) {
2297 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2298 XtSetArg(args[0], XtNlabel, buf);
2300 snprintf(buf, MSG_SIZ, "%s ", color);
2301 XtSetArg(args[0], XtNlabel, buf);
2306 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2307 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2309 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2310 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2313 XtSetValues(w, args, 3);
2316 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2319 SetClockIcon (int color)
2322 Pixmap pm = *clockIcons[color];
2323 if (iconPixmap != pm) {
2325 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2326 XtSetValues(shellWidget, args, 1);
2330 #define INPUT_SOURCE_BUF_SIZE 8192
2339 char buf[INPUT_SOURCE_BUF_SIZE];
2344 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2346 InputSource *is = (InputSource *) closure;
2351 if (is->lineByLine) {
2352 count = read(is->fd, is->unused,
2353 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2355 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2358 is->unused += count;
2360 while (p < is->unused) {
2361 q = memchr(p, '\n', is->unused - p);
2362 if (q == NULL) break;
2364 (is->func)(is, is->closure, p, q - p, 0);
2368 while (p < is->unused) {
2373 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2378 (is->func)(is, is->closure, is->buf, count, error);
2383 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2386 ChildProc *cp = (ChildProc *) pr;
2388 is = (InputSource *) calloc(1, sizeof(InputSource));
2389 is->lineByLine = lineByLine;
2393 is->fd = fileno(stdin);
2395 is->kind = cp->kind;
2396 is->fd = cp->fdFrom;
2399 is->unused = is->buf;
2402 is->xid = XtAppAddInput(appContext, is->fd,
2403 (XtPointer) (XtInputReadMask),
2404 (XtInputCallbackProc) DoInputCallback,
2406 is->closure = closure;
2407 return (InputSourceRef) is;
2411 RemoveInputSource (InputSourceRef isr)
2413 InputSource *is = (InputSource *) isr;
2415 if (is->xid == 0) return;
2416 XtRemoveInput(is->xid);
2422 static Boolean frameWaiting;
2425 FrameAlarm (int sig)
2427 frameWaiting = False;
2428 /* In case System-V style signals. Needed?? */
2429 signal(SIGALRM, FrameAlarm);
2433 FrameDelay (int time)
2435 struct itimerval delay;
2437 XSync(xDisplay, False);
2440 frameWaiting = True;
2441 signal(SIGALRM, FrameAlarm);
2442 delay.it_interval.tv_sec =
2443 delay.it_value.tv_sec = time / 1000;
2444 delay.it_interval.tv_usec =
2445 delay.it_value.tv_usec = (time % 1000) * 1000;
2446 setitimer(ITIMER_REAL, &delay, NULL);
2447 while (frameWaiting) pause();
2448 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2449 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2450 setitimer(ITIMER_REAL, &delay, NULL);
2457 FrameDelay (int time)
2459 XSync(xDisplay, False);
2461 usleep(time * 1000);
2467 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2469 char buf[MSG_SIZ], *logoName = buf;
2470 if(appData.logo[n][0]) {
2471 logoName = appData.logo[n];
2472 } else if(appData.autoLogo) {
2473 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2474 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2475 } else if(appData.directory[n] && appData.directory[n][0]) {
2476 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2480 { ASSIGN(cps->programLogo, logoName); }
2484 UpdateLogos (int displ)
2486 if(optList[W_WHITE-1].handle == NULL) return;
2487 LoadLogo(&first, 0, 0);
2488 LoadLogo(&second, 1, appData.icsActive);
2489 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);