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);
543 return *(char**)colorVariable[n];
547 ParseTextAttribs (ColorClass cc, char *s)
549 (&appData.colorShout)[cc] = strdup(s);
553 ParseBoardSize (void *addr, char *name)
555 appData.boardSize = strdup(name);
560 { // In XBoard the sound-playing program takes care of obtaining the actual sound
564 SetCommPortDefaults ()
565 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
568 // [HGM] args: these three cases taken out to stay in front-end
570 SaveFontArg (FILE *f, ArgDescriptor *ad)
573 int i, n = (int)(intptr_t)ad->argLoc;
575 case 0: // CLOCK_FONT
576 name = appData.clockFont;
578 case 1: // MESSAGE_FONT
581 case 2: // COORD_FONT
582 name = appData.coordFont;
587 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
588 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
589 fontTable[n][squareSize] = strdup(name);
590 fontValid[n][squareSize] = True;
593 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
594 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
599 { // nothing to do, as the sounds are at all times represented by their text-string names already
603 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
604 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
605 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
609 SaveColor (FILE *f, ArgDescriptor *ad)
610 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
611 if(colorVariable[(int)(intptr_t)ad->argLoc])
612 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
616 SaveBoardSize (FILE *f, char *name, void *addr)
617 { // wrapper to shield back-end from BoardSize & sizeInfo
618 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
622 ParseCommPortSettings (char *s)
623 { // no such option in XBoard (yet)
629 GetActualPlacement (Widget wg, WindowPlacement *wp)
631 XWindowAttributes winAt;
638 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
639 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
640 wp->x = rx - winAt.x;
641 wp->y = ry - winAt.y;
642 wp->height = winAt.height;
643 wp->width = winAt.width;
644 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
648 GetPlacement (DialogClass dlg, WindowPlacement *wp)
649 { // wrapper to shield back-end from widget type
650 if(shellUp[dlg]) GetActualPlacement(shells[dlg], wp);
655 { // wrapper to shield use of window handles from back-end (make addressible by number?)
656 // In XBoard this will have to wait until awareness of window parameters is implemented
657 GetActualPlacement(shellWidget, &wpMain);
658 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
659 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
660 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
661 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
662 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
663 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
667 PrintCommPortSettings (FILE *f, char *name)
668 { // This option does not exist in XBoard
672 EnsureOnScreen (int *x, int *y, int minX, int minY)
679 { // [HGM] args: allows testing if main window is realized from back-end
680 return xBoardWindow != 0;
684 PopUpStartupDialog ()
685 { // start menu not implemented in XBoard
689 ConvertToLine (int argc, char **argv)
691 static char line[128*1024], buf[1024];
695 for(i=1; i<argc; i++)
697 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
698 && argv[i][0] != '{' )
699 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
701 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
702 strncat(line, buf, 128*1024 - strlen(line) - 1 );
705 line[strlen(line)-1] = NULLCHAR;
709 //--------------------------------------------------------------------------------------------
712 ResizeBoardWindow (int w, int h, int inhibit)
714 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
716 shellArgs[0].value = w;
717 shellArgs[1].value = h;
718 shellArgs[4].value = shellArgs[2].value = w;
719 shellArgs[5].value = shellArgs[3].value = h;
720 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
722 XSync(xDisplay, False);
726 MakeOneColor (char *name, Pixel *color)
729 if (!appData.monoMode) {
730 vFrom.addr = (caddr_t) name;
731 vFrom.size = strlen(name);
732 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
733 if (vTo.addr == NULL) {
734 appData.monoMode = True;
737 *color = *(Pixel *) vTo.addr;
745 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
746 int forceMono = False;
748 if (appData.lowTimeWarning)
749 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
750 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
751 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
757 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
758 { // detervtomine what fonts to use, and create them
762 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
763 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
764 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
765 appData.font = fontTable[MESSAGE_FONT][squareSize];
766 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
767 appData.coordFont = fontTable[COORD_FONT][squareSize];
770 appData.font = InsertPxlSize(appData.font, fontPxlSize);
771 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
772 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
773 fontSet = CreateFontSet(appData.font);
774 clockFontSet = CreateFontSet(appData.clockFont);
776 /* For the coordFont, use the 0th font of the fontset. */
777 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
778 XFontStruct **font_struct_list;
779 XFontSetExtents *fontSize;
780 char **font_name_list;
781 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
782 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
783 coordFontStruct = XQueryFont(xDisplay, coordFontID);
784 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
785 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
788 appData.font = FindFont(appData.font, fontPxlSize);
789 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
790 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
791 clockFontID = XLoadFont(xDisplay, appData.clockFont);
792 clockFontStruct = XQueryFont(xDisplay, clockFontID);
793 coordFontID = XLoadFont(xDisplay, appData.coordFont);
794 coordFontStruct = XQueryFont(xDisplay, coordFontID);
795 // textHeight in !NLS mode!
797 countFontID = coordFontID; // [HGM] holdings
798 countFontStruct = coordFontStruct;
800 xdb = XtDatabase(xDisplay);
802 XrmPutLineResource(&xdb, "*international: True");
803 vTo.size = sizeof(XFontSet);
804 vTo.addr = (XtPointer) &fontSet;
805 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
807 XrmPutStringResource(&xdb, "*font", appData.font);
817 case ArgInt: p = " N"; break;
818 case ArgString: p = " STR"; break;
819 case ArgBoolean: p = " TF"; break;
820 case ArgSettingsFilename:
821 case ArgBackupSettingsFile:
822 case ArgFilename: p = " FILE"; break;
823 case ArgX: p = " Nx"; break;
824 case ArgY: p = " Ny"; break;
825 case ArgAttribs: p = " TEXTCOL"; break;
826 case ArgColor: p = " COL"; break;
827 case ArgFont: p = " FONT"; break;
828 case ArgBoardSize: p = " SIZE"; break;
829 case ArgFloat: p = " FLOAT"; break;
834 case ArgCommSettings:
843 GenerateGlobalTranslationTable (void)
845 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
853 /* loop over all menu entries */
854 for( i=0; menuBar[i].mi ; i++)
857 for(j=0; mi[j].proc; j++)
865 char *key,*test, *mods;
867 /* check for Ctrl/Alt */
868 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
869 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
870 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
872 /* remove all <...> */
873 test = strrchr(mi[j].accel, '>');
875 key = strdup(mi[j].accel);
877 key = strdup(++test); // remove ">"
879 /* instead of shift X11 uses the uppercase letter directly*/
880 if (shift && strlen(key)==1 )
882 *key = toupper(*key);
886 /* handle some special cases which have different names in X11 */
887 if ( strncmp(key, "Page_Down", 9) == 0 )
892 else if ( strncmp(key, "Page_Up", 7) == 0 )
898 /* create string of mods */
900 mods = strdup("Ctrl ");
906 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
907 strncat(mods, "Meta ", 5);
912 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
913 strncat(mods, "Shift ", 6);
916 // remove trailing space
917 if( isspace(mods[strlen(mods)-1]) )
918 mods[strlen(mods)-1]='\0';
920 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
921 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
922 char *name = malloc(namesize+1);
923 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
925 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
926 char *buffer = malloc(buffersize+1);
927 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
929 /* add string to the output */
930 output = realloc(output, strlen(output) + strlen(buffer)+1);
931 strncat(output, buffer, strlen(buffer));
950 ArgDescriptor *q, *p = argDescriptors+5;
951 printf("\nXBoard accepts the following options:\n"
952 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
953 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
954 " SIZE = board-size spec(s)\n"
955 " Within parentheses are short forms, or options to set to true or false.\n"
956 " Persistent options (saved in the settings file) are marked with *)\n\n");
958 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
959 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
960 if(p->save) strcat(buf+len, "*");
961 for(q=p+1; q->argLoc == p->argLoc; q++) {
962 if(q->argName[0] == '-') continue;
963 strcat(buf+len, q == p+1 ? " (" : " ");
964 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
966 if(q != p+1) strcat(buf+len, ")");
968 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
971 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
975 SlaveResize (Option *opt)
980 main (int argc, char **argv)
982 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
983 XSetWindowAttributes window_attributes;
985 Dimension boardWidth, boardHeight, w, h;
987 int forceMono = False;
989 srandom(time(0)); // [HGM] book: make random truly random
991 setbuf(stdout, NULL);
992 setbuf(stderr, NULL);
995 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
996 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1000 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1005 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1006 typedef struct {char *name, *value; } Config;
1007 static Config configList[] = {
1008 { "Datadir", DATADIR },
1009 { "Sysconfdir", SYSCONFDIR },
1014 for(i=0; configList[i].name; i++) {
1015 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1016 if(argc > 2) printf("%s", configList[i].value);
1017 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1022 programName = strrchr(argv[0], '/');
1023 if (programName == NULL)
1024 programName = argv[0];
1029 XtSetLanguageProc(NULL, NULL, NULL);
1030 if (appData.debugMode) {
1031 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1034 bindtextdomain(PACKAGE, LOCALEDIR);
1035 textdomain(PACKAGE);
1038 appData.boardSize = "";
1039 InitAppData(ConvertToLine(argc, argv));
1041 if (p == NULL) p = "/tmp";
1042 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1043 gameCopyFilename = (char*) malloc(i);
1044 gamePasteFilename = (char*) malloc(i);
1045 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1046 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1048 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1049 static char buf[MSG_SIZ];
1050 EscapeExpand(buf, appData.firstInitString);
1051 appData.firstInitString = strdup(buf);
1052 EscapeExpand(buf, appData.secondInitString);
1053 appData.secondInitString = strdup(buf);
1054 EscapeExpand(buf, appData.firstComputerString);
1055 appData.firstComputerString = strdup(buf);
1056 EscapeExpand(buf, appData.secondComputerString);
1057 appData.secondComputerString = strdup(buf);
1060 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1063 if (chdir(chessDir) != 0) {
1064 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1070 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1071 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1072 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1073 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1076 setbuf(debugFP, NULL);
1079 /* [HGM,HR] make sure board size is acceptable */
1080 if(appData.NrFiles > BOARD_FILES ||
1081 appData.NrRanks > BOARD_RANKS )
1082 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1085 /* This feature does not work; animation needs a rewrite */
1086 appData.highlightDragging = FALSE;
1090 gameInfo.variant = StringToVariant(appData.variant);
1091 InitPosition(FALSE);
1094 XtAppInitialize(&appContext, "XBoard", shellOptions,
1095 XtNumber(shellOptions),
1096 &argc, argv, xboardResources, NULL, 0);
1098 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1099 clientResources, XtNumber(clientResources),
1102 xDisplay = XtDisplay(shellWidget);
1103 xScreen = DefaultScreen(xDisplay);
1104 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1107 * determine size, based on supplied or remembered -size, or screen size
1109 if (isdigit(appData.boardSize[0])) {
1110 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1111 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1112 &fontPxlSize, &smallLayout, &tinyLayout);
1114 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1115 programName, appData.boardSize);
1119 /* Find some defaults; use the nearest known size */
1120 SizeDefaults *szd, *nearest;
1121 int distance = 99999;
1122 nearest = szd = sizeDefaults;
1123 while (szd->name != NULL) {
1124 if (abs(szd->squareSize - squareSize) < distance) {
1126 distance = abs(szd->squareSize - squareSize);
1127 if (distance == 0) break;
1131 if (i < 2) lineGap = nearest->lineGap;
1132 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1133 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1134 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1135 if (i < 6) smallLayout = nearest->smallLayout;
1136 if (i < 7) tinyLayout = nearest->tinyLayout;
1139 SizeDefaults *szd = sizeDefaults;
1140 if (*appData.boardSize == NULLCHAR) {
1141 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1142 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1145 if (szd->name == NULL) szd--;
1146 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1148 while (szd->name != NULL &&
1149 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1150 if (szd->name == NULL) {
1151 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1152 programName, appData.boardSize);
1156 squareSize = szd->squareSize;
1157 lineGap = szd->lineGap;
1158 clockFontPxlSize = szd->clockFontPxlSize;
1159 coordFontPxlSize = szd->coordFontPxlSize;
1160 fontPxlSize = szd->fontPxlSize;
1161 smallLayout = szd->smallLayout;
1162 tinyLayout = szd->tinyLayout;
1163 // [HGM] font: use defaults from settings file if available and not overruled
1166 defaultLineGap = lineGap;
1167 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1169 /* [HR] height treated separately (hacked) */
1170 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1171 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1174 * Determine what fonts to use.
1176 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1179 * Detect if there are not enough colors available and adapt.
1181 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1182 appData.monoMode = True;
1185 forceMono = MakeColors();
1188 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1190 appData.monoMode = True;
1193 if (appData.monoMode && appData.debugMode) {
1194 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1195 (unsigned long) XWhitePixel(xDisplay, xScreen),
1196 (unsigned long) XBlackPixel(xDisplay, xScreen));
1199 ParseIcsTextColors();
1201 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1207 layoutName = "tinyLayout";
1208 } else if (smallLayout) {
1209 layoutName = "smallLayout";
1211 layoutName = "normalLayout";
1214 optList = BoardPopUp(squareSize, lineGap, (void*)
1220 InitDrawingHandle(optList + W_BOARD);
1221 currBoard = &optList[W_BOARD];
1222 boardWidget = optList[W_BOARD].handle;
1223 menuBarWidget = optList[W_MENU].handle;
1224 dropMenu = optList[W_DROP].handle;
1225 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1226 formWidget = XtParent(boardWidget);
1227 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1228 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1229 XtGetValues(optList[W_WHITE].handle, args, 2);
1230 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1231 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1232 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1233 XtGetValues(optList[W_PAUSE].handle, args, 2);
1236 xBoardWindow = XtWindow(boardWidget);
1238 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1239 // not need to go into InitDrawingSizes().
1242 * Create X checkmark bitmap and initialize option menu checks.
1244 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1245 checkmark_bits, checkmark_width, checkmark_height);
1251 ReadBitmap(&wIconPixmap, "icon_white.bm",
1252 icon_white_bits, icon_white_width, icon_white_height);
1253 ReadBitmap(&bIconPixmap, "icon_black.bm",
1254 icon_black_bits, icon_black_width, icon_black_height);
1255 iconPixmap = wIconPixmap;
1257 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1258 XtSetValues(shellWidget, args, i);
1261 * Create a cursor for the board widget.
1263 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1264 XChangeWindowAttributes(xDisplay, xBoardWindow,
1265 CWCursor, &window_attributes);
1268 * Inhibit shell resizing.
1270 shellArgs[0].value = (XtArgVal) &w;
1271 shellArgs[1].value = (XtArgVal) &h;
1272 XtGetValues(shellWidget, shellArgs, 2);
1273 shellArgs[4].value = shellArgs[2].value = w;
1274 shellArgs[5].value = shellArgs[3].value = h;
1275 // XtSetValues(shellWidget, &shellArgs[2], 4);
1276 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1277 marginH = h - boardHeight;
1279 CatchDeleteWindow(shellWidget, "QuitProc");
1284 if(appData.logoSize)
1285 { // locate and read user logo
1287 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1288 ASSIGN(userLogo, buf);
1291 if (appData.animate || appData.animateDragging)
1295 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1297 XtAugmentTranslations(formWidget,
1298 XtParseTranslationTable(globalTranslations));
1299 XtAugmentTranslations(formWidget,
1300 XtParseTranslationTable(TranslationsTableMenus));
1302 XtAddEventHandler(formWidget, KeyPressMask, False,
1303 (XtEventHandler) MoveTypeInProc, NULL);
1304 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1305 (XtEventHandler) EventProc, NULL);
1307 /* [AS] Restore layout */
1308 if( wpMoveHistory.visible ) {
1312 if( wpEvalGraph.visible )
1317 if( wpEngineOutput.visible ) {
1318 EngineOutputPopUp();
1323 if (errorExitStatus == -1) {
1324 if (appData.icsActive) {
1325 /* We now wait until we see "login:" from the ICS before
1326 sending the logon script (problems with timestamp otherwise) */
1327 /*ICSInitScript();*/
1328 if (appData.icsInputBox) ICSInputBoxPopUp();
1332 signal(SIGWINCH, TermSizeSigHandler);
1334 signal(SIGINT, IntSigHandler);
1335 signal(SIGTERM, IntSigHandler);
1336 if (*appData.cmailGameName != NULLCHAR) {
1337 signal(SIGUSR1, CmailSigHandler);
1341 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1344 // XtSetKeyboardFocus(shellWidget, formWidget);
1345 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1347 XtAppMainLoop(appContext);
1348 if (appData.debugMode) fclose(debugFP); // [DM] debug
1353 TermSizeSigHandler (int sig)
1359 IntSigHandler (int sig)
1365 CmailSigHandler (int sig)
1370 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1372 /* Activate call-back function CmailSigHandlerCallBack() */
1373 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1375 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1379 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1382 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1384 /**** end signal code ****/
1387 #define Abs(n) ((n)<0 ? -(n) : (n))
1391 InsertPxlSize (char *pattern, int targetPxlSize)
1393 char *base_fnt_lst, strInt[12], *p, *q;
1394 int alternatives, i, len, strIntLen;
1397 * Replace the "*" (if present) in the pixel-size slot of each
1398 * alternative with the targetPxlSize.
1402 while ((p = strchr(p, ',')) != NULL) {
1406 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1407 strIntLen = strlen(strInt);
1408 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1412 while (alternatives--) {
1413 char *comma = strchr(p, ',');
1414 for (i=0; i<14; i++) {
1415 char *hyphen = strchr(p, '-');
1417 if (comma && hyphen > comma) break;
1418 len = hyphen + 1 - p;
1419 if (i == 7 && *p == '*' && len == 2) {
1421 memcpy(q, strInt, strIntLen);
1431 len = comma + 1 - p;
1438 return base_fnt_lst;
1442 CreateFontSet (char *base_fnt_lst)
1445 char **missing_list;
1449 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1450 &missing_list, &missing_count, &def_string);
1451 if (appData.debugMode) {
1453 XFontStruct **font_struct_list;
1454 char **font_name_list;
1455 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1457 fprintf(debugFP, " got list %s, locale %s\n",
1458 XBaseFontNameListOfFontSet(fntSet),
1459 XLocaleOfFontSet(fntSet));
1460 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1461 for (i = 0; i < count; i++) {
1462 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1465 for (i = 0; i < missing_count; i++) {
1466 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1469 if (fntSet == NULL) {
1470 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1475 #else // not ENABLE_NLS
1477 * Find a font that matches "pattern" that is as close as
1478 * possible to the targetPxlSize. Prefer fonts that are k
1479 * pixels smaller to fonts that are k pixels larger. The
1480 * pattern must be in the X Consortium standard format,
1481 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1482 * The return value should be freed with XtFree when no
1486 FindFont (char *pattern, int targetPxlSize)
1488 char **fonts, *p, *best, *scalable, *scalableTail;
1489 int i, j, nfonts, minerr, err, pxlSize;
1491 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1493 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1494 programName, pattern);
1501 for (i=0; i<nfonts; i++) {
1504 if (*p != '-') continue;
1506 if (*p == NULLCHAR) break;
1507 if (*p++ == '-') j++;
1509 if (j < 7) continue;
1512 scalable = fonts[i];
1515 err = pxlSize - targetPxlSize;
1516 if (Abs(err) < Abs(minerr) ||
1517 (minerr > 0 && err < 0 && -err == minerr)) {
1523 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1524 /* If the error is too big and there is a scalable font,
1525 use the scalable font. */
1526 int headlen = scalableTail - scalable;
1527 p = (char *) XtMalloc(strlen(scalable) + 10);
1528 while (isdigit(*scalableTail)) scalableTail++;
1529 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1531 p = (char *) XtMalloc(strlen(best) + 2);
1532 safeStrCpy(p, best, strlen(best)+1 );
1534 if (appData.debugMode) {
1535 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1536 pattern, targetPxlSize, p);
1538 XFreeFontNames(fonts);
1544 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1547 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1553 MarkMenuItem (char *menuRef, int state)
1555 MenuItem *item = MenuNameToItem(menuRef);
1559 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1560 XtSetValues(item->handle, args, 1);
1565 EnableNamedMenuItem (char *menuRef, int state)
1567 MenuItem *item = MenuNameToItem(menuRef);
1569 if(item) XtSetSensitive(item->handle, state);
1573 EnableButtonBar (int state)
1575 XtSetSensitive(optList[W_BUTTON].handle, state);
1580 SetMenuEnables (Enables *enab)
1582 while (enab->name != NULL) {
1583 EnableNamedMenuItem(enab->name, enab->value);
1589 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1590 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1592 if(*nprms == 0) return;
1593 item = MenuNameToItem(prms[0]);
1594 if(item) ((MenuProc *) item->proc) ();
1606 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1607 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1608 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1609 dmEnables[i].piece);
1610 XtSetSensitive(entry, p != NULL || !appData.testLegality
1611 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1612 && !appData.icsActive));
1614 while (p && *p++ == dmEnables[i].piece) count++;
1615 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1617 XtSetArg(args[j], XtNlabel, label); j++;
1618 XtSetValues(entry, args, j);
1623 do_flash_delay (unsigned long msec)
1629 FlashDelay (int flash_delay)
1631 XSync(xDisplay, False);
1632 if(flash_delay) do_flash_delay(flash_delay);
1636 Fraction (int x, int start, int stop)
1638 double f = ((double) x - start)/(stop - start);
1639 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1643 static WindowPlacement wpNew;
1646 CoDrag (Widget sh, WindowPlacement *wp)
1649 int j=0, touch=0, fudge = 2;
1650 GetActualPlacement(sh, wp);
1651 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1652 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1653 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1654 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1655 if(!touch ) return; // only windows that touch co-move
1656 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1657 int heightInc = wpNew.height - wpMain.height;
1658 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1659 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1660 wp->y += fracTop * heightInc;
1661 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1662 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1663 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1664 int widthInc = wpNew.width - wpMain.width;
1665 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1666 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1667 wp->y += fracLeft * widthInc;
1668 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1669 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1671 wp->x += wpNew.x - wpMain.x;
1672 wp->y += wpNew.y - wpMain.y;
1673 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1674 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1675 XtSetArg(args[j], XtNx, wp->x); j++;
1676 XtSetArg(args[j], XtNy, wp->y); j++;
1677 XtSetValues(sh, args, j);
1681 ReSize (WindowPlacement *wp)
1684 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1685 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1686 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1687 if(sqy < sqx) sqx = sqy;
1688 if(sqx != squareSize) {
1689 squareSize = sqx; // adopt new square size
1690 CreatePNGPieces(); // make newly scaled pieces
1691 InitDrawingSizes(0, 0); // creates grid etc.
1692 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1693 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1694 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1695 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1696 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1699 static XtIntervalId delayedDragID = 0;
1708 GetActualPlacement(shellWidget, &wpNew);
1709 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1710 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1711 busy = 0; return; // false alarm
1714 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1715 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1716 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1717 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1719 DrawPosition(True, NULL);
1720 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1728 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1730 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1734 EventProc (Widget widget, caddr_t unused, XEvent *event)
1736 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1737 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1741 * event handler for redrawing the board
1744 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1746 DrawPosition(True, NULL);
1751 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1752 { // [HGM] pv: walk PV
1753 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1756 extern int savedIndex; /* gross that this is global */
1759 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1762 XawTextPosition index, dummy;
1765 XawTextGetSelectionPos(w, &index, &dummy);
1766 XtSetArg(arg, XtNstring, &val);
1767 XtGetValues(w, &arg, 1);
1768 ReplaceComment(savedIndex, val);
1769 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1770 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1774 /* Disable all user input other than deleting the window */
1775 static int frozen = 0;
1781 /* Grab by a widget that doesn't accept input */
1782 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1786 /* Undo a FreezeUI */
1790 if (!frozen) return;
1791 XtRemoveGrab(optList[W_MESSG].handle);
1799 static int oldPausing = FALSE;
1800 static GameMode oldmode = (GameMode) -1;
1803 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1805 if (pausing != oldPausing) {
1806 oldPausing = pausing;
1807 MarkMenuItem("Mode.Pause", pausing);
1809 if (appData.showButtonBar) {
1810 /* Always toggle, don't set. Previous code messes up when
1811 invoked while the button is pressed, as releasing it
1812 toggles the state again. */
1815 XtSetArg(args[0], XtNbackground, &oldbg);
1816 XtSetArg(args[1], XtNforeground, &oldfg);
1817 XtGetValues(optList[W_PAUSE].handle,
1819 XtSetArg(args[0], XtNbackground, oldfg);
1820 XtSetArg(args[1], XtNforeground, oldbg);
1822 XtSetValues(optList[W_PAUSE].handle, args, 2);
1826 wname = ModeToWidgetName(oldmode);
1827 if (wname != NULL) {
1828 MarkMenuItem(wname, False);
1830 wname = ModeToWidgetName(gameMode);
1831 if (wname != NULL) {
1832 MarkMenuItem(wname, True);
1835 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1837 /* Maybe all the enables should be handled here, not just this one */
1838 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1840 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1845 * Button/menu procedures
1848 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1849 char *selected_fen_position=NULL;
1852 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1853 Atom *type_return, XtPointer *value_return,
1854 unsigned long *length_return, int *format_return)
1856 char *selection_tmp;
1858 // if (!selected_fen_position) return False; /* should never happen */
1859 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1860 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1861 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1864 if (f == NULL) return False;
1868 selection_tmp = XtMalloc(len + 1);
1869 count = fread(selection_tmp, 1, len, f);
1872 XtFree(selection_tmp);
1875 selection_tmp[len] = NULLCHAR;
1877 /* note: since no XtSelectionDoneProc was registered, Xt will
1878 * automatically call XtFree on the value returned. So have to
1879 * make a copy of it allocated with XtMalloc */
1880 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1881 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1884 *value_return=selection_tmp;
1885 *length_return=strlen(selection_tmp);
1886 *type_return=*target;
1887 *format_return = 8; /* bits per byte */
1889 } else if (*target == XA_TARGETS(xDisplay)) {
1890 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1891 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1892 targets_tmp[1] = XA_STRING;
1893 *value_return = targets_tmp;
1894 *type_return = XA_ATOM;
1897 // This code leads to a read of value_return out of bounds on 64-bit systems.
1898 // Other code which I have seen always sets *format_return to 32 independent of
1899 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1900 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1901 *format_return = 8 * sizeof(Atom);
1902 if (*format_return > 32) {
1903 *length_return *= *format_return / 32;
1904 *format_return = 32;
1907 *format_return = 32;
1915 /* note: when called from menu all parameters are NULL, so no clue what the
1916 * Widget which was clicked on was, or what the click event was
1919 CopySomething (char *src)
1921 selected_fen_position = src;
1923 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1924 * have a notion of a position that is selected but not copied.
1925 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1927 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1929 SendPositionSelection,
1930 NULL/* lose_ownership_proc */ ,
1931 NULL/* transfer_done_proc */);
1932 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1934 SendPositionSelection,
1935 NULL/* lose_ownership_proc */ ,
1936 NULL/* transfer_done_proc */);
1939 /* function called when the data to Paste is ready */
1941 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1942 Atom *type, XtPointer value, unsigned long *len, int *format)
1945 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1946 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1947 EditPositionPasteFEN(fenstr);
1951 /* called when Paste Position button is pressed,
1952 * all parameters will be NULL */
1954 PastePositionProc ()
1956 XtGetSelectionValue(menuBarWidget,
1957 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1958 /* (XtSelectionCallbackProc) */ PastePositionCB,
1959 NULL, /* client_data passed to PastePositionCB */
1961 /* better to use the time field from the event that triggered the
1962 * call to this function, but that isn't trivial to get
1969 /* note: when called from menu all parameters are NULL, so no clue what the
1970 * Widget which was clicked on was, or what the click event was
1972 /* function called when the data to Paste is ready */
1974 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1975 Atom *type, XtPointer value, unsigned long *len, int *format)
1978 if (value == NULL || *len == 0) {
1979 return; /* nothing had been selected to copy */
1981 f = fopen(gamePasteFilename, "w");
1983 DisplayError(_("Can't open temp file"), errno);
1986 fwrite(value, 1, *len, f);
1989 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1992 /* called when Paste Game button is pressed,
1993 * all parameters will be NULL */
1997 XtGetSelectionValue(menuBarWidget,
1998 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1999 /* (XtSelectionCallbackProc) */ PasteGameCB,
2000 NULL, /* client_data passed to PasteGameCB */
2002 /* better to use the time field from the event that triggered the
2003 * call to this function, but that isn't trivial to get
2012 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2019 { // bassic primitive for determining if modifier keys are pressed
2020 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2023 XQueryKeymap(xDisplay,keys);
2024 for(i=0; i<6; i++) {
2026 j = XKeysymToKeycode(xDisplay, codes[i]);
2027 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2033 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2037 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2038 if ( n == 1 && *buf >= 32 // printable
2039 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2040 ) BoxAutoPopUp (buf);
2044 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2045 { // [HGM] input: let up-arrow recall previous line from history
2050 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2051 { // [HGM] input: let down-arrow recall next line from history
2056 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2062 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2064 if (!TempBackwardActive) {
2065 TempBackwardActive = True;
2071 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2073 /* Check to see if triggered by a key release event for a repeating key.
2074 * If so the next queued event will be a key press of the same key at the same time */
2075 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2077 XPeekEvent(xDisplay, &next);
2078 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2079 next.xkey.keycode == event->xkey.keycode)
2083 TempBackwardActive = False;
2087 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2088 { // called as key binding
2091 if (nprms && *nprms > 0)
2095 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2101 { // called from menu
2102 ManInner(NULL, NULL, NULL, NULL);
2106 SetWindowTitle (char *text, char *title, char *icon)
2110 if (appData.titleInWindow) {
2112 XtSetArg(args[i], XtNlabel, text); i++;
2113 XtSetValues(titleWidget, args, i);
2116 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2117 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2118 XtSetValues(shellWidget, args, i);
2119 XSync(xDisplay, False);
2124 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2130 DisplayIcsInteractionTitle (String message)
2132 if (oldICSInteractionTitle == NULL) {
2133 /* Magic to find the old window title, adapted from vim */
2134 char *wina = getenv("WINDOWID");
2136 Window win = (Window) atoi(wina);
2137 Window root, parent, *children;
2138 unsigned int nchildren;
2139 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2141 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2142 if (!XQueryTree(xDisplay, win, &root, &parent,
2143 &children, &nchildren)) break;
2144 if (children) XFree((void *)children);
2145 if (parent == root || parent == 0) break;
2148 XSetErrorHandler(oldHandler);
2150 if (oldICSInteractionTitle == NULL) {
2151 oldICSInteractionTitle = "xterm";
2154 printf("\033]0;%s\007", message);
2159 XtIntervalId delayedEventTimerXID = 0;
2160 DelayedEventCallback delayedEventCallback = 0;
2165 delayedEventTimerXID = 0;
2166 delayedEventCallback();
2170 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2172 if(delayedEventTimerXID && delayedEventCallback == cb)
2173 // [HGM] alive: replace, rather than add or flush identical event
2174 XtRemoveTimeOut(delayedEventTimerXID);
2175 delayedEventCallback = cb;
2176 delayedEventTimerXID =
2177 XtAppAddTimeOut(appContext, millisec,
2178 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2181 DelayedEventCallback
2184 if (delayedEventTimerXID) {
2185 return delayedEventCallback;
2192 CancelDelayedEvent ()
2194 if (delayedEventTimerXID) {
2195 XtRemoveTimeOut(delayedEventTimerXID);
2196 delayedEventTimerXID = 0;
2200 XtIntervalId loadGameTimerXID = 0;
2203 LoadGameTimerRunning ()
2205 return loadGameTimerXID != 0;
2209 StopLoadGameTimer ()
2211 if (loadGameTimerXID != 0) {
2212 XtRemoveTimeOut(loadGameTimerXID);
2213 loadGameTimerXID = 0;
2221 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2223 loadGameTimerXID = 0;
2228 StartLoadGameTimer (long millisec)
2231 XtAppAddTimeOut(appContext, millisec,
2232 (XtTimerCallbackProc) LoadGameTimerCallback,
2236 XtIntervalId analysisClockXID = 0;
2239 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2241 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2242 || appData.icsEngineAnalyze) { // [DM]
2243 AnalysisPeriodicEvent(0);
2244 StartAnalysisClock();
2249 StartAnalysisClock ()
2252 XtAppAddTimeOut(appContext, 2000,
2253 (XtTimerCallbackProc) AnalysisClockCallback,
2257 XtIntervalId clockTimerXID = 0;
2260 ClockTimerRunning ()
2262 return clockTimerXID != 0;
2268 if (clockTimerXID != 0) {
2269 XtRemoveTimeOut(clockTimerXID);
2278 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2285 StartClockTimer (long millisec)
2288 XtAppAddTimeOut(appContext, millisec,
2289 (XtTimerCallbackProc) ClockTimerCallback,
2294 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2298 Widget w = (Widget) opt->handle;
2300 /* check for low time warning */
2301 Pixel foregroundOrWarningColor = timerForegroundPixel;
2304 appData.lowTimeWarning &&
2305 (timer / 1000) < appData.icsAlarmTime)
2306 foregroundOrWarningColor = lowTimeWarningColor;
2308 if (appData.clockMode) {
2309 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2310 XtSetArg(args[0], XtNlabel, buf);
2312 snprintf(buf, MSG_SIZ, "%s ", color);
2313 XtSetArg(args[0], XtNlabel, buf);
2318 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2319 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2321 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2322 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2325 XtSetValues(w, args, 3);
2328 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2331 SetClockIcon (int color)
2334 Pixmap pm = *clockIcons[color];
2335 if (iconPixmap != pm) {
2337 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2338 XtSetValues(shellWidget, args, 1);
2342 #define INPUT_SOURCE_BUF_SIZE 8192
2351 char buf[INPUT_SOURCE_BUF_SIZE];
2356 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2358 InputSource *is = (InputSource *) closure;
2363 if (is->lineByLine) {
2364 count = read(is->fd, is->unused,
2365 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2367 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2370 is->unused += count;
2372 while (p < is->unused) {
2373 q = memchr(p, '\n', is->unused - p);
2374 if (q == NULL) break;
2376 (is->func)(is, is->closure, p, q - p, 0);
2380 while (p < is->unused) {
2385 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2390 (is->func)(is, is->closure, is->buf, count, error);
2395 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2398 ChildProc *cp = (ChildProc *) pr;
2400 is = (InputSource *) calloc(1, sizeof(InputSource));
2401 is->lineByLine = lineByLine;
2405 is->fd = fileno(stdin);
2407 is->kind = cp->kind;
2408 is->fd = cp->fdFrom;
2411 is->unused = is->buf;
2414 is->xid = XtAppAddInput(appContext, is->fd,
2415 (XtPointer) (XtInputReadMask),
2416 (XtInputCallbackProc) DoInputCallback,
2418 is->closure = closure;
2419 return (InputSourceRef) is;
2423 RemoveInputSource (InputSourceRef isr)
2425 InputSource *is = (InputSource *) isr;
2427 if (is->xid == 0) return;
2428 XtRemoveInput(is->xid);
2434 static Boolean frameWaiting;
2437 FrameAlarm (int sig)
2439 frameWaiting = False;
2440 /* In case System-V style signals. Needed?? */
2441 signal(SIGALRM, FrameAlarm);
2445 FrameDelay (int time)
2447 struct itimerval delay;
2449 XSync(xDisplay, False);
2452 frameWaiting = True;
2453 signal(SIGALRM, FrameAlarm);
2454 delay.it_interval.tv_sec =
2455 delay.it_value.tv_sec = time / 1000;
2456 delay.it_interval.tv_usec =
2457 delay.it_value.tv_usec = (time % 1000) * 1000;
2458 setitimer(ITIMER_REAL, &delay, NULL);
2459 while (frameWaiting) pause();
2460 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2461 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2462 setitimer(ITIMER_REAL, &delay, NULL);
2469 FrameDelay (int time)
2471 XSync(xDisplay, False);
2473 usleep(time * 1000);
2479 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2481 char buf[MSG_SIZ], *logoName = buf;
2482 if(appData.logo[n][0]) {
2483 logoName = appData.logo[n];
2484 } else if(appData.autoLogo) {
2485 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2486 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2487 } else if(appData.directory[n] && appData.directory[n][0]) {
2488 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2492 { ASSIGN(cps->programLogo, logoName); }
2496 UpdateLogos (int displ)
2498 if(optList[W_WHITE-1].handle == NULL) return;
2499 LoadLogo(&first, 0, 0);
2500 LoadLogo(&second, 1, appData.icsActive);
2501 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);