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 squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
1121 /* Find some defaults; use the nearest known size */
1122 SizeDefaults *szd, *nearest;
1123 int distance = 99999;
1124 nearest = szd = sizeDefaults;
1125 while (szd->name != NULL) {
1126 if (abs(szd->squareSize - squareSize) < distance) {
1128 distance = abs(szd->squareSize - squareSize);
1129 if (distance == 0) break;
1133 if (i < 2) lineGap = nearest->lineGap;
1134 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1135 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1136 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1137 if (i < 6) smallLayout = nearest->smallLayout;
1138 if (i < 7) tinyLayout = nearest->tinyLayout;
1141 SizeDefaults *szd = sizeDefaults;
1142 if (*appData.boardSize == NULLCHAR) {
1143 while (DisplayWidth(xDisplay, xScreen) < (szd->minScreenSize*BOARD_WIDTH + 4)/8 ||
1144 DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
1147 if (szd->name == NULL) szd--;
1148 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1150 while (szd->name != NULL &&
1151 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1152 if (szd->name == NULL) {
1153 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1154 programName, appData.boardSize);
1158 squareSize = szd->squareSize;
1159 lineGap = szd->lineGap;
1160 clockFontPxlSize = szd->clockFontPxlSize;
1161 coordFontPxlSize = szd->coordFontPxlSize;
1162 fontPxlSize = szd->fontPxlSize;
1163 smallLayout = szd->smallLayout;
1164 tinyLayout = szd->tinyLayout;
1165 // [HGM] font: use defaults from settings file if available and not overruled
1168 defaultLineGap = lineGap;
1169 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1171 /* [HR] height treated separately (hacked) */
1172 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1173 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1176 * Determine what fonts to use.
1178 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1181 * Detect if there are not enough colors available and adapt.
1183 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1184 appData.monoMode = True;
1187 forceMono = MakeColors();
1190 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1192 appData.monoMode = True;
1195 if (appData.monoMode && appData.debugMode) {
1196 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1197 (unsigned long) XWhitePixel(xDisplay, xScreen),
1198 (unsigned long) XBlackPixel(xDisplay, xScreen));
1201 ParseIcsTextColors();
1203 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1209 layoutName = "tinyLayout";
1210 } else if (smallLayout) {
1211 layoutName = "smallLayout";
1213 layoutName = "normalLayout";
1216 optList = BoardPopUp(squareSize, lineGap, (void*)
1222 InitDrawingHandle(optList + W_BOARD);
1223 currBoard = &optList[W_BOARD];
1224 boardWidget = optList[W_BOARD].handle;
1225 menuBarWidget = optList[W_MENU].handle;
1226 dropMenu = optList[W_DROP].handle;
1227 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1228 formWidget = XtParent(boardWidget);
1229 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1230 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1231 XtGetValues(optList[W_WHITE].handle, args, 2);
1232 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1233 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1234 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1235 XtGetValues(optList[W_PAUSE].handle, args, 2);
1238 xBoardWindow = XtWindow(boardWidget);
1240 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1241 // not need to go into InitDrawingSizes().
1244 * Create X checkmark bitmap and initialize option menu checks.
1246 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1247 checkmark_bits, checkmark_width, checkmark_height);
1253 ReadBitmap(&wIconPixmap, "icon_white.bm",
1254 icon_white_bits, icon_white_width, icon_white_height);
1255 ReadBitmap(&bIconPixmap, "icon_black.bm",
1256 icon_black_bits, icon_black_width, icon_black_height);
1257 iconPixmap = wIconPixmap;
1259 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1260 XtSetValues(shellWidget, args, i);
1263 * Create a cursor for the board widget.
1265 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1266 XChangeWindowAttributes(xDisplay, xBoardWindow,
1267 CWCursor, &window_attributes);
1270 * Inhibit shell resizing.
1272 shellArgs[0].value = (XtArgVal) &w;
1273 shellArgs[1].value = (XtArgVal) &h;
1274 XtGetValues(shellWidget, shellArgs, 2);
1275 shellArgs[4].value = shellArgs[2].value = w;
1276 shellArgs[5].value = shellArgs[3].value = h;
1277 // XtSetValues(shellWidget, &shellArgs[2], 4);
1278 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1279 marginH = h - boardHeight;
1281 CatchDeleteWindow(shellWidget, "QuitProc");
1286 if(appData.logoSize)
1287 { // locate and read user logo
1289 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1290 ASSIGN(userLogo, buf);
1293 if (appData.animate || appData.animateDragging)
1297 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1299 XtAugmentTranslations(formWidget,
1300 XtParseTranslationTable(globalTranslations));
1301 XtAugmentTranslations(formWidget,
1302 XtParseTranslationTable(TranslationsTableMenus));
1304 XtAddEventHandler(formWidget, KeyPressMask, False,
1305 (XtEventHandler) MoveTypeInProc, NULL);
1306 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1307 (XtEventHandler) EventProc, NULL);
1309 /* [AS] Restore layout */
1310 if( wpMoveHistory.visible ) {
1314 if( wpEvalGraph.visible )
1319 if( wpEngineOutput.visible ) {
1320 EngineOutputPopUp();
1325 if (errorExitStatus == -1) {
1326 if (appData.icsActive) {
1327 /* We now wait until we see "login:" from the ICS before
1328 sending the logon script (problems with timestamp otherwise) */
1329 /*ICSInitScript();*/
1330 if (appData.icsInputBox) ICSInputBoxPopUp();
1334 signal(SIGWINCH, TermSizeSigHandler);
1336 signal(SIGINT, IntSigHandler);
1337 signal(SIGTERM, IntSigHandler);
1338 if (*appData.cmailGameName != NULLCHAR) {
1339 signal(SIGUSR1, CmailSigHandler);
1343 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1346 // XtSetKeyboardFocus(shellWidget, formWidget);
1347 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1349 XtAppMainLoop(appContext);
1350 if (appData.debugMode) fclose(debugFP); // [DM] debug
1355 TermSizeSigHandler (int sig)
1361 IntSigHandler (int sig)
1367 CmailSigHandler (int sig)
1372 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1374 /* Activate call-back function CmailSigHandlerCallBack() */
1375 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1377 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1381 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1384 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1386 /**** end signal code ****/
1389 #define Abs(n) ((n)<0 ? -(n) : (n))
1393 InsertPxlSize (char *pattern, int targetPxlSize)
1395 char *base_fnt_lst, strInt[12], *p, *q;
1396 int alternatives, i, len, strIntLen;
1399 * Replace the "*" (if present) in the pixel-size slot of each
1400 * alternative with the targetPxlSize.
1404 while ((p = strchr(p, ',')) != NULL) {
1408 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1409 strIntLen = strlen(strInt);
1410 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1414 while (alternatives--) {
1415 char *comma = strchr(p, ',');
1416 for (i=0; i<14; i++) {
1417 char *hyphen = strchr(p, '-');
1419 if (comma && hyphen > comma) break;
1420 len = hyphen + 1 - p;
1421 if (i == 7 && *p == '*' && len == 2) {
1423 memcpy(q, strInt, strIntLen);
1433 len = comma + 1 - p;
1440 return base_fnt_lst;
1444 CreateFontSet (char *base_fnt_lst)
1447 char **missing_list;
1451 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1452 &missing_list, &missing_count, &def_string);
1453 if (appData.debugMode) {
1455 XFontStruct **font_struct_list;
1456 char **font_name_list;
1457 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1459 fprintf(debugFP, " got list %s, locale %s\n",
1460 XBaseFontNameListOfFontSet(fntSet),
1461 XLocaleOfFontSet(fntSet));
1462 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1463 for (i = 0; i < count; i++) {
1464 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1467 for (i = 0; i < missing_count; i++) {
1468 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1471 if (fntSet == NULL) {
1472 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1477 #else // not ENABLE_NLS
1479 * Find a font that matches "pattern" that is as close as
1480 * possible to the targetPxlSize. Prefer fonts that are k
1481 * pixels smaller to fonts that are k pixels larger. The
1482 * pattern must be in the X Consortium standard format,
1483 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1484 * The return value should be freed with XtFree when no
1488 FindFont (char *pattern, int targetPxlSize)
1490 char **fonts, *p, *best, *scalable, *scalableTail;
1491 int i, j, nfonts, minerr, err, pxlSize;
1493 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1495 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1496 programName, pattern);
1503 for (i=0; i<nfonts; i++) {
1506 if (*p != '-') continue;
1508 if (*p == NULLCHAR) break;
1509 if (*p++ == '-') j++;
1511 if (j < 7) continue;
1514 scalable = fonts[i];
1517 err = pxlSize - targetPxlSize;
1518 if (Abs(err) < Abs(minerr) ||
1519 (minerr > 0 && err < 0 && -err == minerr)) {
1525 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1526 /* If the error is too big and there is a scalable font,
1527 use the scalable font. */
1528 int headlen = scalableTail - scalable;
1529 p = (char *) XtMalloc(strlen(scalable) + 10);
1530 while (isdigit(*scalableTail)) scalableTail++;
1531 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1533 p = (char *) XtMalloc(strlen(best) + 2);
1534 safeStrCpy(p, best, strlen(best)+1 );
1536 if (appData.debugMode) {
1537 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1538 pattern, targetPxlSize, p);
1540 XFreeFontNames(fonts);
1546 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1549 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1555 MarkMenuItem (char *menuRef, int state)
1557 MenuItem *item = MenuNameToItem(menuRef);
1561 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1562 XtSetValues(item->handle, args, 1);
1567 EnableNamedMenuItem (char *menuRef, int state)
1569 MenuItem *item = MenuNameToItem(menuRef);
1571 if(item) XtSetSensitive(item->handle, state);
1575 EnableButtonBar (int state)
1577 XtSetSensitive(optList[W_BUTTON].handle, state);
1582 SetMenuEnables (Enables *enab)
1584 while (enab->name != NULL) {
1585 EnableNamedMenuItem(enab->name, enab->value);
1591 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1592 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1594 if(*nprms == 0) return;
1595 item = MenuNameToItem(prms[0]);
1596 if(item) ((MenuProc *) item->proc) ();
1608 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1609 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1610 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1611 dmEnables[i].piece);
1612 XtSetSensitive(entry, p != NULL || !appData.testLegality
1613 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1614 && !appData.icsActive));
1616 while (p && *p++ == dmEnables[i].piece) count++;
1617 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1619 XtSetArg(args[j], XtNlabel, label); j++;
1620 XtSetValues(entry, args, j);
1625 do_flash_delay (unsigned long msec)
1631 FlashDelay (int flash_delay)
1633 XSync(xDisplay, False);
1634 if(flash_delay) do_flash_delay(flash_delay);
1638 Fraction (int x, int start, int stop)
1640 double f = ((double) x - start)/(stop - start);
1641 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1645 static WindowPlacement wpNew;
1648 CoDrag (Widget sh, WindowPlacement *wp)
1651 int j=0, touch=0, fudge = 2;
1652 GetActualPlacement(sh, wp);
1653 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1654 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1655 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1656 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1657 if(!touch ) return; // only windows that touch co-move
1658 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1659 int heightInc = wpNew.height - wpMain.height;
1660 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1661 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1662 wp->y += fracTop * heightInc;
1663 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1664 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1665 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1666 int widthInc = wpNew.width - wpMain.width;
1667 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1668 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1669 wp->y += fracLeft * widthInc;
1670 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1671 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1673 wp->x += wpNew.x - wpMain.x;
1674 wp->y += wpNew.y - wpMain.y;
1675 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1676 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1677 XtSetArg(args[j], XtNx, wp->x); j++;
1678 XtSetArg(args[j], XtNy, wp->y); j++;
1679 XtSetValues(sh, args, j);
1683 ReSize (WindowPlacement *wp)
1686 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1687 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1688 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1689 if(sqy < sqx) sqx = sqy;
1690 if(sqx != squareSize) {
1691 squareSize = sqx; // adopt new square size
1692 CreatePNGPieces(); // make newly scaled pieces
1693 InitDrawingSizes(0, 0); // creates grid etc.
1694 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1695 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1696 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1697 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1698 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1701 static XtIntervalId delayedDragID = 0;
1710 GetActualPlacement(shellWidget, &wpNew);
1711 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1712 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1713 busy = 0; return; // false alarm
1716 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1717 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1718 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1719 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1721 DrawPosition(True, NULL);
1722 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1730 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1732 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1736 EventProc (Widget widget, caddr_t unused, XEvent *event)
1738 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1739 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1743 * event handler for redrawing the board
1746 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1748 DrawPosition(True, NULL);
1753 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1754 { // [HGM] pv: walk PV
1755 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1758 extern int savedIndex; /* gross that this is global */
1761 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1764 XawTextPosition index, dummy;
1767 XawTextGetSelectionPos(w, &index, &dummy);
1768 XtSetArg(arg, XtNstring, &val);
1769 XtGetValues(w, &arg, 1);
1770 ReplaceComment(savedIndex, val);
1771 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1772 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1776 /* Disable all user input other than deleting the window */
1777 static int frozen = 0;
1783 /* Grab by a widget that doesn't accept input */
1784 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1788 /* Undo a FreezeUI */
1792 if (!frozen) return;
1793 XtRemoveGrab(optList[W_MESSG].handle);
1801 static int oldPausing = FALSE;
1802 static GameMode oldmode = (GameMode) -1;
1805 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1807 if (pausing != oldPausing) {
1808 oldPausing = pausing;
1809 MarkMenuItem("Mode.Pause", pausing);
1811 if (appData.showButtonBar) {
1812 /* Always toggle, don't set. Previous code messes up when
1813 invoked while the button is pressed, as releasing it
1814 toggles the state again. */
1817 XtSetArg(args[0], XtNbackground, &oldbg);
1818 XtSetArg(args[1], XtNforeground, &oldfg);
1819 XtGetValues(optList[W_PAUSE].handle,
1821 XtSetArg(args[0], XtNbackground, oldfg);
1822 XtSetArg(args[1], XtNforeground, oldbg);
1824 XtSetValues(optList[W_PAUSE].handle, args, 2);
1828 wname = ModeToWidgetName(oldmode);
1829 if (wname != NULL) {
1830 MarkMenuItem(wname, False);
1832 wname = ModeToWidgetName(gameMode);
1833 if (wname != NULL) {
1834 MarkMenuItem(wname, True);
1837 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1839 /* Maybe all the enables should be handled here, not just this one */
1840 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1842 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1847 * Button/menu procedures
1850 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1851 char *selected_fen_position=NULL;
1854 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1855 Atom *type_return, XtPointer *value_return,
1856 unsigned long *length_return, int *format_return)
1858 char *selection_tmp;
1860 // if (!selected_fen_position) return False; /* should never happen */
1861 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1862 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1863 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1866 if (f == NULL) return False;
1870 selection_tmp = XtMalloc(len + 1);
1871 count = fread(selection_tmp, 1, len, f);
1874 XtFree(selection_tmp);
1877 selection_tmp[len] = NULLCHAR;
1879 /* note: since no XtSelectionDoneProc was registered, Xt will
1880 * automatically call XtFree on the value returned. So have to
1881 * make a copy of it allocated with XtMalloc */
1882 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1883 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1886 *value_return=selection_tmp;
1887 *length_return=strlen(selection_tmp);
1888 *type_return=*target;
1889 *format_return = 8; /* bits per byte */
1891 } else if (*target == XA_TARGETS(xDisplay)) {
1892 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1893 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1894 targets_tmp[1] = XA_STRING;
1895 *value_return = targets_tmp;
1896 *type_return = XA_ATOM;
1899 // This code leads to a read of value_return out of bounds on 64-bit systems.
1900 // Other code which I have seen always sets *format_return to 32 independent of
1901 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1902 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1903 *format_return = 8 * sizeof(Atom);
1904 if (*format_return > 32) {
1905 *length_return *= *format_return / 32;
1906 *format_return = 32;
1909 *format_return = 32;
1917 /* note: when called from menu all parameters are NULL, so no clue what the
1918 * Widget which was clicked on was, or what the click event was
1921 CopySomething (char *src)
1923 selected_fen_position = src;
1925 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1926 * have a notion of a position that is selected but not copied.
1927 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1929 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1931 SendPositionSelection,
1932 NULL/* lose_ownership_proc */ ,
1933 NULL/* transfer_done_proc */);
1934 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1936 SendPositionSelection,
1937 NULL/* lose_ownership_proc */ ,
1938 NULL/* transfer_done_proc */);
1941 /* function called when the data to Paste is ready */
1943 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1944 Atom *type, XtPointer value, unsigned long *len, int *format)
1947 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1948 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1949 EditPositionPasteFEN(fenstr);
1953 /* called when Paste Position button is pressed,
1954 * all parameters will be NULL */
1956 PastePositionProc ()
1958 XtGetSelectionValue(menuBarWidget,
1959 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1960 /* (XtSelectionCallbackProc) */ PastePositionCB,
1961 NULL, /* client_data passed to PastePositionCB */
1963 /* better to use the time field from the event that triggered the
1964 * call to this function, but that isn't trivial to get
1971 /* note: when called from menu all parameters are NULL, so no clue what the
1972 * Widget which was clicked on was, or what the click event was
1974 /* function called when the data to Paste is ready */
1976 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1977 Atom *type, XtPointer value, unsigned long *len, int *format)
1980 if (value == NULL || *len == 0) {
1981 return; /* nothing had been selected to copy */
1983 f = fopen(gamePasteFilename, "w");
1985 DisplayError(_("Can't open temp file"), errno);
1988 fwrite(value, 1, *len, f);
1991 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1994 /* called when Paste Game button is pressed,
1995 * all parameters will be NULL */
1999 XtGetSelectionValue(menuBarWidget,
2000 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2001 /* (XtSelectionCallbackProc) */ PasteGameCB,
2002 NULL, /* client_data passed to PasteGameCB */
2004 /* better to use the time field from the event that triggered the
2005 * call to this function, but that isn't trivial to get
2014 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2021 { // bassic primitive for determining if modifier keys are pressed
2022 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2025 XQueryKeymap(xDisplay,keys);
2026 for(i=0; i<6; i++) {
2028 j = XKeysymToKeycode(xDisplay, codes[i]);
2029 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2035 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2039 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2040 if ( n == 1 && *buf >= 32 // printable
2041 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2042 ) BoxAutoPopUp (buf);
2046 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2047 { // [HGM] input: let up-arrow recall previous line from history
2052 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2053 { // [HGM] input: let down-arrow recall next line from history
2058 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2064 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2066 if (!TempBackwardActive) {
2067 TempBackwardActive = True;
2073 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2075 /* Check to see if triggered by a key release event for a repeating key.
2076 * If so the next queued event will be a key press of the same key at the same time */
2077 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2079 XPeekEvent(xDisplay, &next);
2080 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2081 next.xkey.keycode == event->xkey.keycode)
2085 TempBackwardActive = False;
2089 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2090 { // called as key binding
2093 if (nprms && *nprms > 0)
2097 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2103 { // called from menu
2104 ManInner(NULL, NULL, NULL, NULL);
2108 SetWindowTitle (char *text, char *title, char *icon)
2112 if (appData.titleInWindow) {
2114 XtSetArg(args[i], XtNlabel, text); i++;
2115 XtSetValues(titleWidget, args, i);
2118 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2119 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2120 XtSetValues(shellWidget, args, i);
2121 XSync(xDisplay, False);
2126 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2132 DisplayIcsInteractionTitle (String message)
2134 if (oldICSInteractionTitle == NULL) {
2135 /* Magic to find the old window title, adapted from vim */
2136 char *wina = getenv("WINDOWID");
2138 Window win = (Window) atoi(wina);
2139 Window root, parent, *children;
2140 unsigned int nchildren;
2141 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2143 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2144 if (!XQueryTree(xDisplay, win, &root, &parent,
2145 &children, &nchildren)) break;
2146 if (children) XFree((void *)children);
2147 if (parent == root || parent == 0) break;
2150 XSetErrorHandler(oldHandler);
2152 if (oldICSInteractionTitle == NULL) {
2153 oldICSInteractionTitle = "xterm";
2156 printf("\033]0;%s\007", message);
2161 XtIntervalId delayedEventTimerXID = 0;
2162 DelayedEventCallback delayedEventCallback = 0;
2167 delayedEventTimerXID = 0;
2168 delayedEventCallback();
2172 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2174 if(delayedEventTimerXID && delayedEventCallback == cb)
2175 // [HGM] alive: replace, rather than add or flush identical event
2176 XtRemoveTimeOut(delayedEventTimerXID);
2177 delayedEventCallback = cb;
2178 delayedEventTimerXID =
2179 XtAppAddTimeOut(appContext, millisec,
2180 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2183 DelayedEventCallback
2186 if (delayedEventTimerXID) {
2187 return delayedEventCallback;
2194 CancelDelayedEvent ()
2196 if (delayedEventTimerXID) {
2197 XtRemoveTimeOut(delayedEventTimerXID);
2198 delayedEventTimerXID = 0;
2202 XtIntervalId loadGameTimerXID = 0;
2205 LoadGameTimerRunning ()
2207 return loadGameTimerXID != 0;
2211 StopLoadGameTimer ()
2213 if (loadGameTimerXID != 0) {
2214 XtRemoveTimeOut(loadGameTimerXID);
2215 loadGameTimerXID = 0;
2223 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2225 loadGameTimerXID = 0;
2230 StartLoadGameTimer (long millisec)
2233 XtAppAddTimeOut(appContext, millisec,
2234 (XtTimerCallbackProc) LoadGameTimerCallback,
2238 XtIntervalId analysisClockXID = 0;
2241 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2243 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2244 || appData.icsEngineAnalyze) { // [DM]
2245 AnalysisPeriodicEvent(0);
2246 StartAnalysisClock();
2251 StartAnalysisClock ()
2254 XtAppAddTimeOut(appContext, 2000,
2255 (XtTimerCallbackProc) AnalysisClockCallback,
2259 XtIntervalId clockTimerXID = 0;
2262 ClockTimerRunning ()
2264 return clockTimerXID != 0;
2270 if (clockTimerXID != 0) {
2271 XtRemoveTimeOut(clockTimerXID);
2280 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2287 StartClockTimer (long millisec)
2290 XtAppAddTimeOut(appContext, millisec,
2291 (XtTimerCallbackProc) ClockTimerCallback,
2296 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2300 Widget w = (Widget) opt->handle;
2302 /* check for low time warning */
2303 Pixel foregroundOrWarningColor = timerForegroundPixel;
2306 appData.lowTimeWarning &&
2307 (timer / 1000) < appData.icsAlarmTime)
2308 foregroundOrWarningColor = lowTimeWarningColor;
2310 if (appData.clockMode) {
2311 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2312 XtSetArg(args[0], XtNlabel, buf);
2314 snprintf(buf, MSG_SIZ, "%s ", color);
2315 XtSetArg(args[0], XtNlabel, buf);
2320 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2321 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2323 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2324 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2327 XtSetValues(w, args, 3);
2330 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2333 SetClockIcon (int color)
2336 Pixmap pm = *clockIcons[color];
2337 if (iconPixmap != pm) {
2339 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2340 XtSetValues(shellWidget, args, 1);
2344 #define INPUT_SOURCE_BUF_SIZE 8192
2353 char buf[INPUT_SOURCE_BUF_SIZE];
2358 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2360 InputSource *is = (InputSource *) closure;
2365 if (is->lineByLine) {
2366 count = read(is->fd, is->unused,
2367 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2369 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2372 is->unused += count;
2374 while (p < is->unused) {
2375 q = memchr(p, '\n', is->unused - p);
2376 if (q == NULL) break;
2378 (is->func)(is, is->closure, p, q - p, 0);
2382 while (p < is->unused) {
2387 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2392 (is->func)(is, is->closure, is->buf, count, error);
2397 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2400 ChildProc *cp = (ChildProc *) pr;
2402 is = (InputSource *) calloc(1, sizeof(InputSource));
2403 is->lineByLine = lineByLine;
2407 is->fd = fileno(stdin);
2409 is->kind = cp->kind;
2410 is->fd = cp->fdFrom;
2413 is->unused = is->buf;
2416 is->xid = XtAppAddInput(appContext, is->fd,
2417 (XtPointer) (XtInputReadMask),
2418 (XtInputCallbackProc) DoInputCallback,
2420 is->closure = closure;
2421 return (InputSourceRef) is;
2425 RemoveInputSource (InputSourceRef isr)
2427 InputSource *is = (InputSource *) isr;
2429 if (is->xid == 0) return;
2430 XtRemoveInput(is->xid);
2436 static Boolean frameWaiting;
2439 FrameAlarm (int sig)
2441 frameWaiting = False;
2442 /* In case System-V style signals. Needed?? */
2443 signal(SIGALRM, FrameAlarm);
2447 FrameDelay (int time)
2449 struct itimerval delay;
2451 XSync(xDisplay, False);
2454 frameWaiting = True;
2455 signal(SIGALRM, FrameAlarm);
2456 delay.it_interval.tv_sec =
2457 delay.it_value.tv_sec = time / 1000;
2458 delay.it_interval.tv_usec =
2459 delay.it_value.tv_usec = (time % 1000) * 1000;
2460 setitimer(ITIMER_REAL, &delay, NULL);
2461 while (frameWaiting) pause();
2462 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2463 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2464 setitimer(ITIMER_REAL, &delay, NULL);
2471 FrameDelay (int time)
2473 XSync(xDisplay, False);
2475 usleep(time * 1000);
2481 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2483 char buf[MSG_SIZ], *logoName = buf;
2484 if(appData.logo[n][0]) {
2485 logoName = appData.logo[n];
2486 } else if(appData.autoLogo) {
2487 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2488 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2489 } else if(appData.directory[n] && appData.directory[n][0]) {
2490 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2494 { ASSIGN(cps->programLogo, logoName); }
2498 UpdateLogos (int displ)
2500 if(optList[W_WHITE-1].handle == NULL) return;
2501 LoadLogo(&first, 0, 0);
2502 LoadLogo(&second, 1, appData.icsActive);
2503 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);