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
642 GetPlacement (DialogClass dlg, WindowPlacement *wp)
643 { // wrapper to shield back-end from widget type
644 if(shellUp[dlg]) GetActualPlacement(shells[dlg], wp);
649 { // wrapper to shield use of window handles from back-end (make addressible by number?)
650 // In XBoard this will have to wait until awareness of window parameters is implemented
651 GetActualPlacement(shellWidget, &wpMain);
652 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
653 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
654 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
655 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
656 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
657 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
661 PrintCommPortSettings (FILE *f, char *name)
662 { // This option does not exist in XBoard
666 EnsureOnScreen (int *x, int *y, int minX, int minY)
673 { // [HGM] args: allows testing if main window is realized from back-end
674 return xBoardWindow != 0;
678 PopUpStartupDialog ()
679 { // start menu not implemented in XBoard
683 ConvertToLine (int argc, char **argv)
685 static char line[128*1024], buf[1024];
689 for(i=1; i<argc; i++)
691 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
692 && argv[i][0] != '{' )
693 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
695 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
696 strncat(line, buf, 128*1024 - strlen(line) - 1 );
699 line[strlen(line)-1] = NULLCHAR;
703 //--------------------------------------------------------------------------------------------
706 ResizeBoardWindow (int w, int h, int inhibit)
708 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
710 shellArgs[0].value = w;
711 shellArgs[1].value = h;
712 shellArgs[4].value = shellArgs[2].value = w;
713 shellArgs[5].value = shellArgs[3].value = h;
714 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
716 XSync(xDisplay, False);
720 MakeOneColor (char *name, Pixel *color)
723 if (!appData.monoMode) {
724 vFrom.addr = (caddr_t) name;
725 vFrom.size = strlen(name);
726 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
727 if (vTo.addr == NULL) {
728 appData.monoMode = True;
731 *color = *(Pixel *) vTo.addr;
739 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
740 int forceMono = False;
742 if (appData.lowTimeWarning)
743 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
744 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
745 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
751 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
752 { // detervtomine what fonts to use, and create them
756 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
757 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
758 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
759 appData.font = fontTable[MESSAGE_FONT][squareSize];
760 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
761 appData.coordFont = fontTable[COORD_FONT][squareSize];
764 appData.font = InsertPxlSize(appData.font, fontPxlSize);
765 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
766 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
767 fontSet = CreateFontSet(appData.font);
768 clockFontSet = CreateFontSet(appData.clockFont);
770 /* For the coordFont, use the 0th font of the fontset. */
771 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
772 XFontStruct **font_struct_list;
773 XFontSetExtents *fontSize;
774 char **font_name_list;
775 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
776 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
777 coordFontStruct = XQueryFont(xDisplay, coordFontID);
778 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
779 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
782 appData.font = FindFont(appData.font, fontPxlSize);
783 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
784 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
785 clockFontID = XLoadFont(xDisplay, appData.clockFont);
786 clockFontStruct = XQueryFont(xDisplay, clockFontID);
787 coordFontID = XLoadFont(xDisplay, appData.coordFont);
788 coordFontStruct = XQueryFont(xDisplay, coordFontID);
789 // textHeight in !NLS mode!
791 countFontID = coordFontID; // [HGM] holdings
792 countFontStruct = coordFontStruct;
794 xdb = XtDatabase(xDisplay);
796 XrmPutLineResource(&xdb, "*international: True");
797 vTo.size = sizeof(XFontSet);
798 vTo.addr = (XtPointer) &fontSet;
799 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
801 XrmPutStringResource(&xdb, "*font", appData.font);
811 case ArgInt: p = " N"; break;
812 case ArgString: p = " STR"; break;
813 case ArgBoolean: p = " TF"; break;
814 case ArgSettingsFilename:
815 case ArgBackupSettingsFile:
816 case ArgFilename: p = " FILE"; break;
817 case ArgX: p = " Nx"; break;
818 case ArgY: p = " Ny"; break;
819 case ArgAttribs: p = " TEXTCOL"; break;
820 case ArgColor: p = " COL"; break;
821 case ArgFont: p = " FONT"; break;
822 case ArgBoardSize: p = " SIZE"; break;
823 case ArgFloat: p = " FLOAT"; break;
828 case ArgCommSettings:
837 GenerateGlobalTranslationTable (void)
839 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
847 /* loop over all menu entries */
848 for( i=0; menuBar[i].mi ; i++)
851 for(j=0; mi[j].proc; j++)
859 char *key,*test, *mods;
861 /* check for Ctrl/Alt */
862 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
863 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
864 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
866 /* remove all <...> */
867 test = strrchr(mi[j].accel, '>');
869 key = strdup(mi[j].accel);
871 key = strdup(++test); // remove ">"
873 /* instead of shift X11 uses the uppercase letter directly*/
874 if (shift && strlen(key)==1 )
876 *key = toupper(*key);
880 /* handle some special cases which have different names in X11 */
881 if ( strncmp(key, "Page_Down", 9) == 0 )
886 else if ( strncmp(key, "Page_Up", 7) == 0 )
892 /* create string of mods */
894 mods = strdup("Ctrl ");
900 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
901 strncat(mods, "Meta ", 5);
906 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
907 strncat(mods, "Shift ", 6);
910 // remove trailing space
911 if( isspace(mods[strlen(mods)-1]) )
912 mods[strlen(mods)-1]='\0';
914 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
915 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
916 char *name = malloc(namesize+1);
917 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
919 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
920 char *buffer = malloc(buffersize+1);
921 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
923 /* add string to the output */
924 output = realloc(output, strlen(output) + strlen(buffer)+1);
925 strncat(output, buffer, strlen(buffer));
944 ArgDescriptor *q, *p = argDescriptors+5;
945 printf("\nXBoard accepts the following options:\n"
946 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
947 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
948 " SIZE = board-size spec(s)\n"
949 " Within parentheses are short forms, or options to set to true or false.\n"
950 " Persistent options (saved in the settings file) are marked with *)\n\n");
952 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
953 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
954 if(p->save) strcat(buf+len, "*");
955 for(q=p+1; q->argLoc == p->argLoc; q++) {
956 if(q->argName[0] == '-') continue;
957 strcat(buf+len, q == p+1 ? " (" : " ");
958 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
960 if(q != p+1) strcat(buf+len, ")");
962 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
965 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
969 SlaveResize (Option *opt)
974 main (int argc, char **argv)
976 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
977 XSetWindowAttributes window_attributes;
979 Dimension boardWidth, boardHeight, w, h;
981 int forceMono = False;
983 srandom(time(0)); // [HGM] book: make random truly random
985 setbuf(stdout, NULL);
986 setbuf(stderr, NULL);
989 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
990 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
994 if(argc > 1 && !strcmp(argv[1], "--help" )) {
999 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1000 typedef struct {char *name, *value; } Config;
1001 static Config configList[] = {
1002 { "Datadir", DATADIR },
1003 { "Sysconfdir", SYSCONFDIR },
1008 for(i=0; configList[i].name; i++) {
1009 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1010 if(argc > 2) printf("%s", configList[i].value);
1011 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1016 programName = strrchr(argv[0], '/');
1017 if (programName == NULL)
1018 programName = argv[0];
1023 XtSetLanguageProc(NULL, NULL, NULL);
1024 if (appData.debugMode) {
1025 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1028 bindtextdomain(PACKAGE, LOCALEDIR);
1029 textdomain(PACKAGE);
1032 appData.boardSize = "";
1033 InitAppData(ConvertToLine(argc, argv));
1035 if (p == NULL) p = "/tmp";
1036 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1037 gameCopyFilename = (char*) malloc(i);
1038 gamePasteFilename = (char*) malloc(i);
1039 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1040 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1042 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1043 static char buf[MSG_SIZ];
1044 EscapeExpand(buf, appData.firstInitString);
1045 appData.firstInitString = strdup(buf);
1046 EscapeExpand(buf, appData.secondInitString);
1047 appData.secondInitString = strdup(buf);
1048 EscapeExpand(buf, appData.firstComputerString);
1049 appData.firstComputerString = strdup(buf);
1050 EscapeExpand(buf, appData.secondComputerString);
1051 appData.secondComputerString = strdup(buf);
1054 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1057 if (chdir(chessDir) != 0) {
1058 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1064 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1065 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1066 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1067 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1070 setbuf(debugFP, NULL);
1073 /* [HGM,HR] make sure board size is acceptable */
1074 if(appData.NrFiles > BOARD_FILES ||
1075 appData.NrRanks > BOARD_RANKS )
1076 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1079 /* This feature does not work; animation needs a rewrite */
1080 appData.highlightDragging = FALSE;
1084 gameInfo.variant = StringToVariant(appData.variant);
1085 InitPosition(FALSE);
1088 XtAppInitialize(&appContext, "XBoard", shellOptions,
1089 XtNumber(shellOptions),
1090 &argc, argv, xboardResources, NULL, 0);
1092 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1093 clientResources, XtNumber(clientResources),
1096 xDisplay = XtDisplay(shellWidget);
1097 xScreen = DefaultScreen(xDisplay);
1098 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1101 * determine size, based on supplied or remembered -size, or screen size
1103 if (isdigit(appData.boardSize[0])) {
1104 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1105 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1106 &fontPxlSize, &smallLayout, &tinyLayout);
1108 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1109 programName, appData.boardSize);
1113 /* Find some defaults; use the nearest known size */
1114 SizeDefaults *szd, *nearest;
1115 int distance = 99999;
1116 nearest = szd = sizeDefaults;
1117 while (szd->name != NULL) {
1118 if (abs(szd->squareSize - squareSize) < distance) {
1120 distance = abs(szd->squareSize - squareSize);
1121 if (distance == 0) break;
1125 if (i < 2) lineGap = nearest->lineGap;
1126 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1127 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1128 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1129 if (i < 6) smallLayout = nearest->smallLayout;
1130 if (i < 7) tinyLayout = nearest->tinyLayout;
1133 SizeDefaults *szd = sizeDefaults;
1134 if (*appData.boardSize == NULLCHAR) {
1135 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1136 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1139 if (szd->name == NULL) szd--;
1140 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1142 while (szd->name != NULL &&
1143 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1144 if (szd->name == NULL) {
1145 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1146 programName, appData.boardSize);
1150 squareSize = szd->squareSize;
1151 lineGap = szd->lineGap;
1152 clockFontPxlSize = szd->clockFontPxlSize;
1153 coordFontPxlSize = szd->coordFontPxlSize;
1154 fontPxlSize = szd->fontPxlSize;
1155 smallLayout = szd->smallLayout;
1156 tinyLayout = szd->tinyLayout;
1157 // [HGM] font: use defaults from settings file if available and not overruled
1160 defaultLineGap = lineGap;
1161 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1163 /* [HR] height treated separately (hacked) */
1164 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1165 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1168 * Determine what fonts to use.
1170 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1173 * Detect if there are not enough colors available and adapt.
1175 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1176 appData.monoMode = True;
1179 forceMono = MakeColors();
1182 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1184 appData.monoMode = True;
1187 if (appData.monoMode && appData.debugMode) {
1188 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1189 (unsigned long) XWhitePixel(xDisplay, xScreen),
1190 (unsigned long) XBlackPixel(xDisplay, xScreen));
1193 ParseIcsTextColors();
1195 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1201 layoutName = "tinyLayout";
1202 } else if (smallLayout) {
1203 layoutName = "smallLayout";
1205 layoutName = "normalLayout";
1208 optList = BoardPopUp(squareSize, lineGap, (void*)
1214 InitDrawingHandle(optList + W_BOARD);
1215 currBoard = &optList[W_BOARD];
1216 boardWidget = optList[W_BOARD].handle;
1217 menuBarWidget = optList[W_MENU].handle;
1218 dropMenu = optList[W_DROP].handle;
1219 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1220 formWidget = XtParent(boardWidget);
1221 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1222 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1223 XtGetValues(optList[W_WHITE].handle, args, 2);
1224 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1225 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1226 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1227 XtGetValues(optList[W_PAUSE].handle, args, 2);
1230 xBoardWindow = XtWindow(boardWidget);
1232 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1233 // not need to go into InitDrawingSizes().
1236 * Create X checkmark bitmap and initialize option menu checks.
1238 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1239 checkmark_bits, checkmark_width, checkmark_height);
1245 ReadBitmap(&wIconPixmap, "icon_white.bm",
1246 icon_white_bits, icon_white_width, icon_white_height);
1247 ReadBitmap(&bIconPixmap, "icon_black.bm",
1248 icon_black_bits, icon_black_width, icon_black_height);
1249 iconPixmap = wIconPixmap;
1251 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1252 XtSetValues(shellWidget, args, i);
1255 * Create a cursor for the board widget.
1257 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1258 XChangeWindowAttributes(xDisplay, xBoardWindow,
1259 CWCursor, &window_attributes);
1262 * Inhibit shell resizing.
1264 shellArgs[0].value = (XtArgVal) &w;
1265 shellArgs[1].value = (XtArgVal) &h;
1266 XtGetValues(shellWidget, shellArgs, 2);
1267 shellArgs[4].value = shellArgs[2].value = w;
1268 shellArgs[5].value = shellArgs[3].value = h;
1269 // XtSetValues(shellWidget, &shellArgs[2], 4);
1270 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1271 marginH = h - boardHeight;
1273 CatchDeleteWindow(shellWidget, "QuitProc");
1278 if(appData.logoSize)
1279 { // locate and read user logo
1281 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1282 ASSIGN(userLogo, buf);
1285 if (appData.animate || appData.animateDragging)
1289 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1291 XtAugmentTranslations(formWidget,
1292 XtParseTranslationTable(globalTranslations));
1293 XtAugmentTranslations(formWidget,
1294 XtParseTranslationTable(TranslationsTableMenus));
1296 XtAddEventHandler(formWidget, KeyPressMask, False,
1297 (XtEventHandler) MoveTypeInProc, NULL);
1298 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1299 (XtEventHandler) EventProc, NULL);
1301 /* [AS] Restore layout */
1302 if( wpMoveHistory.visible ) {
1306 if( wpEvalGraph.visible )
1311 if( wpEngineOutput.visible ) {
1312 EngineOutputPopUp();
1317 if (errorExitStatus == -1) {
1318 if (appData.icsActive) {
1319 /* We now wait until we see "login:" from the ICS before
1320 sending the logon script (problems with timestamp otherwise) */
1321 /*ICSInitScript();*/
1322 if (appData.icsInputBox) ICSInputBoxPopUp();
1326 signal(SIGWINCH, TermSizeSigHandler);
1328 signal(SIGINT, IntSigHandler);
1329 signal(SIGTERM, IntSigHandler);
1330 if (*appData.cmailGameName != NULLCHAR) {
1331 signal(SIGUSR1, CmailSigHandler);
1335 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1338 // XtSetKeyboardFocus(shellWidget, formWidget);
1339 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1341 XtAppMainLoop(appContext);
1342 if (appData.debugMode) fclose(debugFP); // [DM] debug
1347 TermSizeSigHandler (int sig)
1353 IntSigHandler (int sig)
1359 CmailSigHandler (int sig)
1364 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1366 /* Activate call-back function CmailSigHandlerCallBack() */
1367 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1369 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1373 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1376 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1378 /**** end signal code ****/
1381 #define Abs(n) ((n)<0 ? -(n) : (n))
1385 InsertPxlSize (char *pattern, int targetPxlSize)
1387 char *base_fnt_lst, strInt[12], *p, *q;
1388 int alternatives, i, len, strIntLen;
1391 * Replace the "*" (if present) in the pixel-size slot of each
1392 * alternative with the targetPxlSize.
1396 while ((p = strchr(p, ',')) != NULL) {
1400 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1401 strIntLen = strlen(strInt);
1402 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1406 while (alternatives--) {
1407 char *comma = strchr(p, ',');
1408 for (i=0; i<14; i++) {
1409 char *hyphen = strchr(p, '-');
1411 if (comma && hyphen > comma) break;
1412 len = hyphen + 1 - p;
1413 if (i == 7 && *p == '*' && len == 2) {
1415 memcpy(q, strInt, strIntLen);
1425 len = comma + 1 - p;
1432 return base_fnt_lst;
1436 CreateFontSet (char *base_fnt_lst)
1439 char **missing_list;
1443 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1444 &missing_list, &missing_count, &def_string);
1445 if (appData.debugMode) {
1447 XFontStruct **font_struct_list;
1448 char **font_name_list;
1449 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1451 fprintf(debugFP, " got list %s, locale %s\n",
1452 XBaseFontNameListOfFontSet(fntSet),
1453 XLocaleOfFontSet(fntSet));
1454 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1455 for (i = 0; i < count; i++) {
1456 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1459 for (i = 0; i < missing_count; i++) {
1460 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1463 if (fntSet == NULL) {
1464 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1469 #else // not ENABLE_NLS
1471 * Find a font that matches "pattern" that is as close as
1472 * possible to the targetPxlSize. Prefer fonts that are k
1473 * pixels smaller to fonts that are k pixels larger. The
1474 * pattern must be in the X Consortium standard format,
1475 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1476 * The return value should be freed with XtFree when no
1480 FindFont (char *pattern, int targetPxlSize)
1482 char **fonts, *p, *best, *scalable, *scalableTail;
1483 int i, j, nfonts, minerr, err, pxlSize;
1485 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1487 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1488 programName, pattern);
1495 for (i=0; i<nfonts; i++) {
1498 if (*p != '-') continue;
1500 if (*p == NULLCHAR) break;
1501 if (*p++ == '-') j++;
1503 if (j < 7) continue;
1506 scalable = fonts[i];
1509 err = pxlSize - targetPxlSize;
1510 if (Abs(err) < Abs(minerr) ||
1511 (minerr > 0 && err < 0 && -err == minerr)) {
1517 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1518 /* If the error is too big and there is a scalable font,
1519 use the scalable font. */
1520 int headlen = scalableTail - scalable;
1521 p = (char *) XtMalloc(strlen(scalable) + 10);
1522 while (isdigit(*scalableTail)) scalableTail++;
1523 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1525 p = (char *) XtMalloc(strlen(best) + 2);
1526 safeStrCpy(p, best, strlen(best)+1 );
1528 if (appData.debugMode) {
1529 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1530 pattern, targetPxlSize, p);
1532 XFreeFontNames(fonts);
1538 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1541 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1547 MarkMenuItem (char *menuRef, int state)
1549 MenuItem *item = MenuNameToItem(menuRef);
1553 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1554 XtSetValues(item->handle, args, 1);
1559 EnableNamedMenuItem (char *menuRef, int state)
1561 MenuItem *item = MenuNameToItem(menuRef);
1563 if(item) XtSetSensitive(item->handle, state);
1567 EnableButtonBar (int state)
1569 XtSetSensitive(optList[W_BUTTON].handle, state);
1574 SetMenuEnables (Enables *enab)
1576 while (enab->name != NULL) {
1577 EnableNamedMenuItem(enab->name, enab->value);
1583 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1584 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1586 if(*nprms == 0) return;
1587 item = MenuNameToItem(prms[0]);
1588 if(item) ((MenuProc *) item->proc) ();
1600 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1601 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1602 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1603 dmEnables[i].piece);
1604 XtSetSensitive(entry, p != NULL || !appData.testLegality
1605 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1606 && !appData.icsActive));
1608 while (p && *p++ == dmEnables[i].piece) count++;
1609 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1611 XtSetArg(args[j], XtNlabel, label); j++;
1612 XtSetValues(entry, args, j);
1617 do_flash_delay (unsigned long msec)
1623 FlashDelay (int flash_delay)
1625 XSync(xDisplay, False);
1626 if(flash_delay) do_flash_delay(flash_delay);
1630 Fraction (int x, int start, int stop)
1632 double f = ((double) x - start)/(stop - start);
1633 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1637 static WindowPlacement wpNew;
1640 CoDrag (Widget sh, WindowPlacement *wp)
1643 int j=0, touch=0, fudge = 2;
1644 GetActualPlacement(sh, wp);
1645 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1646 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1647 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1648 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1649 if(!touch ) return; // only windows that touch co-move
1650 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1651 int heightInc = wpNew.height - wpMain.height;
1652 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1653 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1654 wp->y += fracTop * heightInc;
1655 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1656 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1657 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1658 int widthInc = wpNew.width - wpMain.width;
1659 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1660 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1661 wp->y += fracLeft * widthInc;
1662 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1663 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1665 wp->x += wpNew.x - wpMain.x;
1666 wp->y += wpNew.y - wpMain.y;
1667 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1668 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1669 XtSetArg(args[j], XtNx, wp->x); j++;
1670 XtSetArg(args[j], XtNy, wp->y); j++;
1671 XtSetValues(sh, args, j);
1675 ReSize (WindowPlacement *wp)
1678 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1679 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1680 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1681 if(sqy < sqx) sqx = sqy;
1682 if(sqx != squareSize) {
1683 squareSize = sqx; // adopt new square size
1684 CreatePNGPieces(); // make newly scaled pieces
1685 InitDrawingSizes(0, 0); // creates grid etc.
1686 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1687 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1688 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1689 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1690 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1693 static XtIntervalId delayedDragID = 0;
1702 GetActualPlacement(shellWidget, &wpNew);
1703 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1704 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1705 busy = 0; return; // false alarm
1708 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1709 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1710 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1711 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1713 DrawPosition(True, NULL);
1714 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1722 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1724 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1728 EventProc (Widget widget, caddr_t unused, XEvent *event)
1730 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1731 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1735 * event handler for redrawing the board
1738 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1740 DrawPosition(True, NULL);
1745 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1746 { // [HGM] pv: walk PV
1747 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1750 extern int savedIndex; /* gross that this is global */
1753 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1756 XawTextPosition index, dummy;
1759 XawTextGetSelectionPos(w, &index, &dummy);
1760 XtSetArg(arg, XtNstring, &val);
1761 XtGetValues(w, &arg, 1);
1762 ReplaceComment(savedIndex, val);
1763 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1764 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1768 /* Disable all user input other than deleting the window */
1769 static int frozen = 0;
1775 /* Grab by a widget that doesn't accept input */
1776 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1780 /* Undo a FreezeUI */
1784 if (!frozen) return;
1785 XtRemoveGrab(optList[W_MESSG].handle);
1793 static int oldPausing = FALSE;
1794 static GameMode oldmode = (GameMode) -1;
1797 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1799 if (pausing != oldPausing) {
1800 oldPausing = pausing;
1801 MarkMenuItem("Mode.Pause", pausing);
1803 if (appData.showButtonBar) {
1804 /* Always toggle, don't set. Previous code messes up when
1805 invoked while the button is pressed, as releasing it
1806 toggles the state again. */
1809 XtSetArg(args[0], XtNbackground, &oldbg);
1810 XtSetArg(args[1], XtNforeground, &oldfg);
1811 XtGetValues(optList[W_PAUSE].handle,
1813 XtSetArg(args[0], XtNbackground, oldfg);
1814 XtSetArg(args[1], XtNforeground, oldbg);
1816 XtSetValues(optList[W_PAUSE].handle, args, 2);
1820 wname = ModeToWidgetName(oldmode);
1821 if (wname != NULL) {
1822 MarkMenuItem(wname, False);
1824 wname = ModeToWidgetName(gameMode);
1825 if (wname != NULL) {
1826 MarkMenuItem(wname, True);
1829 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1831 /* Maybe all the enables should be handled here, not just this one */
1832 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1834 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1839 * Button/menu procedures
1842 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1843 char *selected_fen_position=NULL;
1846 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1847 Atom *type_return, XtPointer *value_return,
1848 unsigned long *length_return, int *format_return)
1850 char *selection_tmp;
1852 // if (!selected_fen_position) return False; /* should never happen */
1853 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1854 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1855 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1858 if (f == NULL) return False;
1862 selection_tmp = XtMalloc(len + 1);
1863 count = fread(selection_tmp, 1, len, f);
1866 XtFree(selection_tmp);
1869 selection_tmp[len] = NULLCHAR;
1871 /* note: since no XtSelectionDoneProc was registered, Xt will
1872 * automatically call XtFree on the value returned. So have to
1873 * make a copy of it allocated with XtMalloc */
1874 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1875 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1878 *value_return=selection_tmp;
1879 *length_return=strlen(selection_tmp);
1880 *type_return=*target;
1881 *format_return = 8; /* bits per byte */
1883 } else if (*target == XA_TARGETS(xDisplay)) {
1884 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1885 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1886 targets_tmp[1] = XA_STRING;
1887 *value_return = targets_tmp;
1888 *type_return = XA_ATOM;
1891 // This code leads to a read of value_return out of bounds on 64-bit systems.
1892 // Other code which I have seen always sets *format_return to 32 independent of
1893 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1894 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1895 *format_return = 8 * sizeof(Atom);
1896 if (*format_return > 32) {
1897 *length_return *= *format_return / 32;
1898 *format_return = 32;
1901 *format_return = 32;
1909 /* note: when called from menu all parameters are NULL, so no clue what the
1910 * Widget which was clicked on was, or what the click event was
1913 CopySomething (char *src)
1915 selected_fen_position = src;
1917 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1918 * have a notion of a position that is selected but not copied.
1919 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1921 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1923 SendPositionSelection,
1924 NULL/* lose_ownership_proc */ ,
1925 NULL/* transfer_done_proc */);
1926 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1928 SendPositionSelection,
1929 NULL/* lose_ownership_proc */ ,
1930 NULL/* transfer_done_proc */);
1933 /* function called when the data to Paste is ready */
1935 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1936 Atom *type, XtPointer value, unsigned long *len, int *format)
1939 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1940 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1941 EditPositionPasteFEN(fenstr);
1945 /* called when Paste Position button is pressed,
1946 * all parameters will be NULL */
1948 PastePositionProc ()
1950 XtGetSelectionValue(menuBarWidget,
1951 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1952 /* (XtSelectionCallbackProc) */ PastePositionCB,
1953 NULL, /* client_data passed to PastePositionCB */
1955 /* better to use the time field from the event that triggered the
1956 * call to this function, but that isn't trivial to get
1963 /* note: when called from menu all parameters are NULL, so no clue what the
1964 * Widget which was clicked on was, or what the click event was
1966 /* function called when the data to Paste is ready */
1968 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1969 Atom *type, XtPointer value, unsigned long *len, int *format)
1972 if (value == NULL || *len == 0) {
1973 return; /* nothing had been selected to copy */
1975 f = fopen(gamePasteFilename, "w");
1977 DisplayError(_("Can't open temp file"), errno);
1980 fwrite(value, 1, *len, f);
1983 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1986 /* called when Paste Game button is pressed,
1987 * all parameters will be NULL */
1991 XtGetSelectionValue(menuBarWidget,
1992 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1993 /* (XtSelectionCallbackProc) */ PasteGameCB,
1994 NULL, /* client_data passed to PasteGameCB */
1996 /* better to use the time field from the event that triggered the
1997 * call to this function, but that isn't trivial to get
2006 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2013 { // bassic primitive for determining if modifier keys are pressed
2014 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2017 XQueryKeymap(xDisplay,keys);
2018 for(i=0; i<6; i++) {
2020 j = XKeysymToKeycode(xDisplay, codes[i]);
2021 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2027 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2031 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2032 if ( n == 1 && *buf >= 32 // printable
2033 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2034 ) BoxAutoPopUp (buf);
2038 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2039 { // [HGM] input: let up-arrow recall previous line from history
2044 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2045 { // [HGM] input: let down-arrow recall next line from history
2050 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2056 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2058 if (!TempBackwardActive) {
2059 TempBackwardActive = True;
2065 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2067 /* Check to see if triggered by a key release event for a repeating key.
2068 * If so the next queued event will be a key press of the same key at the same time */
2069 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2071 XPeekEvent(xDisplay, &next);
2072 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2073 next.xkey.keycode == event->xkey.keycode)
2077 TempBackwardActive = False;
2081 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2082 { // called as key binding
2085 if (nprms && *nprms > 0)
2089 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2095 { // called from menu
2096 ManInner(NULL, NULL, NULL, NULL);
2100 SetWindowTitle (char *text, char *title, char *icon)
2104 if (appData.titleInWindow) {
2106 XtSetArg(args[i], XtNlabel, text); i++;
2107 XtSetValues(titleWidget, args, i);
2110 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2111 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2112 XtSetValues(shellWidget, args, i);
2113 XSync(xDisplay, False);
2118 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2124 DisplayIcsInteractionTitle (String message)
2126 if (oldICSInteractionTitle == NULL) {
2127 /* Magic to find the old window title, adapted from vim */
2128 char *wina = getenv("WINDOWID");
2130 Window win = (Window) atoi(wina);
2131 Window root, parent, *children;
2132 unsigned int nchildren;
2133 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2135 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2136 if (!XQueryTree(xDisplay, win, &root, &parent,
2137 &children, &nchildren)) break;
2138 if (children) XFree((void *)children);
2139 if (parent == root || parent == 0) break;
2142 XSetErrorHandler(oldHandler);
2144 if (oldICSInteractionTitle == NULL) {
2145 oldICSInteractionTitle = "xterm";
2148 printf("\033]0;%s\007", message);
2153 XtIntervalId delayedEventTimerXID = 0;
2154 DelayedEventCallback delayedEventCallback = 0;
2159 delayedEventTimerXID = 0;
2160 delayedEventCallback();
2164 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2166 if(delayedEventTimerXID && delayedEventCallback == cb)
2167 // [HGM] alive: replace, rather than add or flush identical event
2168 XtRemoveTimeOut(delayedEventTimerXID);
2169 delayedEventCallback = cb;
2170 delayedEventTimerXID =
2171 XtAppAddTimeOut(appContext, millisec,
2172 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2175 DelayedEventCallback
2178 if (delayedEventTimerXID) {
2179 return delayedEventCallback;
2186 CancelDelayedEvent ()
2188 if (delayedEventTimerXID) {
2189 XtRemoveTimeOut(delayedEventTimerXID);
2190 delayedEventTimerXID = 0;
2194 XtIntervalId loadGameTimerXID = 0;
2197 LoadGameTimerRunning ()
2199 return loadGameTimerXID != 0;
2203 StopLoadGameTimer ()
2205 if (loadGameTimerXID != 0) {
2206 XtRemoveTimeOut(loadGameTimerXID);
2207 loadGameTimerXID = 0;
2215 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2217 loadGameTimerXID = 0;
2222 StartLoadGameTimer (long millisec)
2225 XtAppAddTimeOut(appContext, millisec,
2226 (XtTimerCallbackProc) LoadGameTimerCallback,
2230 XtIntervalId analysisClockXID = 0;
2233 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2235 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2236 || appData.icsEngineAnalyze) { // [DM]
2237 AnalysisPeriodicEvent(0);
2238 StartAnalysisClock();
2243 StartAnalysisClock ()
2246 XtAppAddTimeOut(appContext, 2000,
2247 (XtTimerCallbackProc) AnalysisClockCallback,
2251 XtIntervalId clockTimerXID = 0;
2254 ClockTimerRunning ()
2256 return clockTimerXID != 0;
2262 if (clockTimerXID != 0) {
2263 XtRemoveTimeOut(clockTimerXID);
2272 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2279 StartClockTimer (long millisec)
2282 XtAppAddTimeOut(appContext, millisec,
2283 (XtTimerCallbackProc) ClockTimerCallback,
2288 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2292 Widget w = (Widget) opt->handle;
2294 /* check for low time warning */
2295 Pixel foregroundOrWarningColor = timerForegroundPixel;
2298 appData.lowTimeWarning &&
2299 (timer / 1000) < appData.icsAlarmTime)
2300 foregroundOrWarningColor = lowTimeWarningColor;
2302 if (appData.clockMode) {
2303 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2304 XtSetArg(args[0], XtNlabel, buf);
2306 snprintf(buf, MSG_SIZ, "%s ", color);
2307 XtSetArg(args[0], XtNlabel, buf);
2312 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2313 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2315 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2316 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2319 XtSetValues(w, args, 3);
2322 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2325 SetClockIcon (int color)
2328 Pixmap pm = *clockIcons[color];
2329 if (iconPixmap != pm) {
2331 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2332 XtSetValues(shellWidget, args, 1);
2336 #define INPUT_SOURCE_BUF_SIZE 8192
2345 char buf[INPUT_SOURCE_BUF_SIZE];
2350 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2352 InputSource *is = (InputSource *) closure;
2357 if (is->lineByLine) {
2358 count = read(is->fd, is->unused,
2359 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2361 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2364 is->unused += count;
2366 while (p < is->unused) {
2367 q = memchr(p, '\n', is->unused - p);
2368 if (q == NULL) break;
2370 (is->func)(is, is->closure, p, q - p, 0);
2374 while (p < is->unused) {
2379 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2384 (is->func)(is, is->closure, is->buf, count, error);
2389 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2392 ChildProc *cp = (ChildProc *) pr;
2394 is = (InputSource *) calloc(1, sizeof(InputSource));
2395 is->lineByLine = lineByLine;
2399 is->fd = fileno(stdin);
2401 is->kind = cp->kind;
2402 is->fd = cp->fdFrom;
2405 is->unused = is->buf;
2408 is->xid = XtAppAddInput(appContext, is->fd,
2409 (XtPointer) (XtInputReadMask),
2410 (XtInputCallbackProc) DoInputCallback,
2412 is->closure = closure;
2413 return (InputSourceRef) is;
2417 RemoveInputSource (InputSourceRef isr)
2419 InputSource *is = (InputSource *) isr;
2421 if (is->xid == 0) return;
2422 XtRemoveInput(is->xid);
2428 static Boolean frameWaiting;
2431 FrameAlarm (int sig)
2433 frameWaiting = False;
2434 /* In case System-V style signals. Needed?? */
2435 signal(SIGALRM, FrameAlarm);
2439 FrameDelay (int time)
2441 struct itimerval delay;
2443 XSync(xDisplay, False);
2446 frameWaiting = True;
2447 signal(SIGALRM, FrameAlarm);
2448 delay.it_interval.tv_sec =
2449 delay.it_value.tv_sec = time / 1000;
2450 delay.it_interval.tv_usec =
2451 delay.it_value.tv_usec = (time % 1000) * 1000;
2452 setitimer(ITIMER_REAL, &delay, NULL);
2453 while (frameWaiting) pause();
2454 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2455 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2456 setitimer(ITIMER_REAL, &delay, NULL);
2463 FrameDelay (int time)
2465 XSync(xDisplay, False);
2467 usleep(time * 1000);
2473 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2475 char buf[MSG_SIZ], *logoName = buf;
2476 if(appData.logo[n][0]) {
2477 logoName = appData.logo[n];
2478 } else if(appData.autoLogo) {
2479 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2480 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2481 } else if(appData.directory[n] && appData.directory[n][0]) {
2482 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2486 { ASSIGN(cps->programLogo, logoName); }
2490 UpdateLogos (int displ)
2492 if(optList[W_WHITE-1].handle == NULL) return;
2493 LoadLogo(&first, 0, 0);
2494 LoadLogo(&second, 1, appData.icsActive);
2495 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);