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();
1323 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1328 if (errorExitStatus == -1) {
1329 if (appData.icsActive) {
1330 /* We now wait until we see "login:" from the ICS before
1331 sending the logon script (problems with timestamp otherwise) */
1332 /*ICSInitScript();*/
1333 if (appData.icsInputBox) ICSInputBoxPopUp();
1337 signal(SIGWINCH, TermSizeSigHandler);
1339 signal(SIGINT, IntSigHandler);
1340 signal(SIGTERM, IntSigHandler);
1341 if (*appData.cmailGameName != NULLCHAR) {
1342 signal(SIGUSR1, CmailSigHandler);
1347 // XtSetKeyboardFocus(shellWidget, formWidget);
1348 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1350 XtAppMainLoop(appContext);
1351 if (appData.debugMode) fclose(debugFP); // [DM] debug
1356 TermSizeSigHandler (int sig)
1362 IntSigHandler (int sig)
1368 CmailSigHandler (int sig)
1373 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1375 /* Activate call-back function CmailSigHandlerCallBack() */
1376 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1378 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1382 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1385 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1387 /**** end signal code ****/
1390 #define Abs(n) ((n)<0 ? -(n) : (n))
1394 InsertPxlSize (char *pattern, int targetPxlSize)
1396 char *base_fnt_lst, strInt[12], *p, *q;
1397 int alternatives, i, len, strIntLen;
1400 * Replace the "*" (if present) in the pixel-size slot of each
1401 * alternative with the targetPxlSize.
1405 while ((p = strchr(p, ',')) != NULL) {
1409 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1410 strIntLen = strlen(strInt);
1411 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1415 while (alternatives--) {
1416 char *comma = strchr(p, ',');
1417 for (i=0; i<14; i++) {
1418 char *hyphen = strchr(p, '-');
1420 if (comma && hyphen > comma) break;
1421 len = hyphen + 1 - p;
1422 if (i == 7 && *p == '*' && len == 2) {
1424 memcpy(q, strInt, strIntLen);
1434 len = comma + 1 - p;
1441 return base_fnt_lst;
1445 CreateFontSet (char *base_fnt_lst)
1448 char **missing_list;
1452 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1453 &missing_list, &missing_count, &def_string);
1454 if (appData.debugMode) {
1456 XFontStruct **font_struct_list;
1457 char **font_name_list;
1458 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1460 fprintf(debugFP, " got list %s, locale %s\n",
1461 XBaseFontNameListOfFontSet(fntSet),
1462 XLocaleOfFontSet(fntSet));
1463 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1464 for (i = 0; i < count; i++) {
1465 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1468 for (i = 0; i < missing_count; i++) {
1469 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1472 if (fntSet == NULL) {
1473 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1478 #else // not ENABLE_NLS
1480 * Find a font that matches "pattern" that is as close as
1481 * possible to the targetPxlSize. Prefer fonts that are k
1482 * pixels smaller to fonts that are k pixels larger. The
1483 * pattern must be in the X Consortium standard format,
1484 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1485 * The return value should be freed with XtFree when no
1489 FindFont (char *pattern, int targetPxlSize)
1491 char **fonts, *p, *best, *scalable, *scalableTail;
1492 int i, j, nfonts, minerr, err, pxlSize;
1494 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1496 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1497 programName, pattern);
1504 for (i=0; i<nfonts; i++) {
1507 if (*p != '-') continue;
1509 if (*p == NULLCHAR) break;
1510 if (*p++ == '-') j++;
1512 if (j < 7) continue;
1515 scalable = fonts[i];
1518 err = pxlSize - targetPxlSize;
1519 if (Abs(err) < Abs(minerr) ||
1520 (minerr > 0 && err < 0 && -err == minerr)) {
1526 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1527 /* If the error is too big and there is a scalable font,
1528 use the scalable font. */
1529 int headlen = scalableTail - scalable;
1530 p = (char *) XtMalloc(strlen(scalable) + 10);
1531 while (isdigit(*scalableTail)) scalableTail++;
1532 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1534 p = (char *) XtMalloc(strlen(best) + 2);
1535 safeStrCpy(p, best, strlen(best)+1 );
1537 if (appData.debugMode) {
1538 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1539 pattern, targetPxlSize, p);
1541 XFreeFontNames(fonts);
1547 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1550 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1556 MarkMenuItem (char *menuRef, int state)
1558 MenuItem *item = MenuNameToItem(menuRef);
1562 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1563 XtSetValues(item->handle, args, 1);
1568 EnableNamedMenuItem (char *menuRef, int state)
1570 MenuItem *item = MenuNameToItem(menuRef);
1572 if(item) XtSetSensitive(item->handle, state);
1576 EnableButtonBar (int state)
1578 XtSetSensitive(optList[W_BUTTON].handle, state);
1583 SetMenuEnables (Enables *enab)
1585 while (enab->name != NULL) {
1586 EnableNamedMenuItem(enab->name, enab->value);
1592 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1593 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1595 if(*nprms == 0) return;
1596 item = MenuNameToItem(prms[0]);
1597 if(item) ((MenuProc *) item->proc) ();
1609 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1610 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1611 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1612 dmEnables[i].piece);
1613 XtSetSensitive(entry, p != NULL || !appData.testLegality
1614 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1615 && !appData.icsActive));
1617 while (p && *p++ == dmEnables[i].piece) count++;
1618 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1620 XtSetArg(args[j], XtNlabel, label); j++;
1621 XtSetValues(entry, args, j);
1626 do_flash_delay (unsigned long msec)
1632 FlashDelay (int flash_delay)
1634 XSync(xDisplay, False);
1635 if(flash_delay) do_flash_delay(flash_delay);
1639 Fraction (int x, int start, int stop)
1641 double f = ((double) x - start)/(stop - start);
1642 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1646 static WindowPlacement wpNew;
1649 CoDrag (Widget sh, WindowPlacement *wp)
1652 int j=0, touch=0, fudge = 2;
1653 GetActualPlacement(sh, wp);
1654 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1655 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1656 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1657 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1658 if(!touch ) return; // only windows that touch co-move
1659 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1660 int heightInc = wpNew.height - wpMain.height;
1661 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1662 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1663 wp->y += fracTop * heightInc;
1664 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1665 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1666 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1667 int widthInc = wpNew.width - wpMain.width;
1668 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1669 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1670 wp->y += fracLeft * widthInc;
1671 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1672 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1674 wp->x += wpNew.x - wpMain.x;
1675 wp->y += wpNew.y - wpMain.y;
1676 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1677 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1678 XtSetArg(args[j], XtNx, wp->x); j++;
1679 XtSetArg(args[j], XtNy, wp->y); j++;
1680 XtSetValues(sh, args, j);
1684 ReSize (WindowPlacement *wp)
1687 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1688 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1689 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1690 if(sqy < sqx) sqx = sqy;
1691 if(sqx != squareSize) {
1692 squareSize = sqx; // adopt new square size
1693 CreatePNGPieces(); // make newly scaled pieces
1694 InitDrawingSizes(0, 0); // creates grid etc.
1695 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1696 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1697 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1698 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1699 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1702 static XtIntervalId delayedDragID = 0;
1711 GetActualPlacement(shellWidget, &wpNew);
1712 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1713 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1714 busy = 0; return; // false alarm
1717 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1718 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1719 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1720 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1722 DrawPosition(True, NULL);
1723 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1731 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1733 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1737 EventProc (Widget widget, caddr_t unused, XEvent *event)
1739 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1740 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1744 * event handler for redrawing the board
1747 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1749 DrawPosition(True, NULL);
1754 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1755 { // [HGM] pv: walk PV
1756 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1759 extern int savedIndex; /* gross that this is global */
1762 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1765 XawTextPosition index, dummy;
1768 XawTextGetSelectionPos(w, &index, &dummy);
1769 XtSetArg(arg, XtNstring, &val);
1770 XtGetValues(w, &arg, 1);
1771 ReplaceComment(savedIndex, val);
1772 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1773 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1777 /* Disable all user input other than deleting the window */
1778 static int frozen = 0;
1784 /* Grab by a widget that doesn't accept input */
1785 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1789 /* Undo a FreezeUI */
1793 if (!frozen) return;
1794 XtRemoveGrab(optList[W_MESSG].handle);
1802 static int oldPausing = FALSE;
1803 static GameMode oldmode = (GameMode) -1;
1806 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1808 if (pausing != oldPausing) {
1809 oldPausing = pausing;
1810 MarkMenuItem("Mode.Pause", pausing);
1812 if (appData.showButtonBar) {
1813 /* Always toggle, don't set. Previous code messes up when
1814 invoked while the button is pressed, as releasing it
1815 toggles the state again. */
1818 XtSetArg(args[0], XtNbackground, &oldbg);
1819 XtSetArg(args[1], XtNforeground, &oldfg);
1820 XtGetValues(optList[W_PAUSE].handle,
1822 XtSetArg(args[0], XtNbackground, oldfg);
1823 XtSetArg(args[1], XtNforeground, oldbg);
1825 XtSetValues(optList[W_PAUSE].handle, args, 2);
1829 wname = ModeToWidgetName(oldmode);
1830 if (wname != NULL) {
1831 MarkMenuItem(wname, False);
1833 wname = ModeToWidgetName(gameMode);
1834 if (wname != NULL) {
1835 MarkMenuItem(wname, True);
1838 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1840 /* Maybe all the enables should be handled here, not just this one */
1841 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1843 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1848 * Button/menu procedures
1851 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1852 char *selected_fen_position=NULL;
1855 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1856 Atom *type_return, XtPointer *value_return,
1857 unsigned long *length_return, int *format_return)
1859 char *selection_tmp;
1861 // if (!selected_fen_position) return False; /* should never happen */
1862 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1863 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1864 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1867 if (f == NULL) return False;
1871 selection_tmp = XtMalloc(len + 1);
1872 count = fread(selection_tmp, 1, len, f);
1875 XtFree(selection_tmp);
1878 selection_tmp[len] = NULLCHAR;
1880 /* note: since no XtSelectionDoneProc was registered, Xt will
1881 * automatically call XtFree on the value returned. So have to
1882 * make a copy of it allocated with XtMalloc */
1883 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1884 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1887 *value_return=selection_tmp;
1888 *length_return=strlen(selection_tmp);
1889 *type_return=*target;
1890 *format_return = 8; /* bits per byte */
1892 } else if (*target == XA_TARGETS(xDisplay)) {
1893 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1894 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1895 targets_tmp[1] = XA_STRING;
1896 *value_return = targets_tmp;
1897 *type_return = XA_ATOM;
1900 // This code leads to a read of value_return out of bounds on 64-bit systems.
1901 // Other code which I have seen always sets *format_return to 32 independent of
1902 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1903 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1904 *format_return = 8 * sizeof(Atom);
1905 if (*format_return > 32) {
1906 *length_return *= *format_return / 32;
1907 *format_return = 32;
1910 *format_return = 32;
1918 /* note: when called from menu all parameters are NULL, so no clue what the
1919 * Widget which was clicked on was, or what the click event was
1922 CopySomething (char *src)
1924 selected_fen_position = src;
1926 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1927 * have a notion of a position that is selected but not copied.
1928 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1930 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1932 SendPositionSelection,
1933 NULL/* lose_ownership_proc */ ,
1934 NULL/* transfer_done_proc */);
1935 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1937 SendPositionSelection,
1938 NULL/* lose_ownership_proc */ ,
1939 NULL/* transfer_done_proc */);
1942 /* function called when the data to Paste is ready */
1944 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1945 Atom *type, XtPointer value, unsigned long *len, int *format)
1948 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1949 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1950 EditPositionPasteFEN(fenstr);
1954 /* called when Paste Position button is pressed,
1955 * all parameters will be NULL */
1957 PastePositionProc ()
1959 XtGetSelectionValue(menuBarWidget,
1960 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1961 /* (XtSelectionCallbackProc) */ PastePositionCB,
1962 NULL, /* client_data passed to PastePositionCB */
1964 /* better to use the time field from the event that triggered the
1965 * call to this function, but that isn't trivial to get
1972 /* note: when called from menu all parameters are NULL, so no clue what the
1973 * Widget which was clicked on was, or what the click event was
1975 /* function called when the data to Paste is ready */
1977 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1978 Atom *type, XtPointer value, unsigned long *len, int *format)
1981 if (value == NULL || *len == 0) {
1982 return; /* nothing had been selected to copy */
1984 f = fopen(gamePasteFilename, "w");
1986 DisplayError(_("Can't open temp file"), errno);
1989 fwrite(value, 1, *len, f);
1992 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1995 /* called when Paste Game button is pressed,
1996 * all parameters will be NULL */
2000 XtGetSelectionValue(menuBarWidget,
2001 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2002 /* (XtSelectionCallbackProc) */ PasteGameCB,
2003 NULL, /* client_data passed to PasteGameCB */
2005 /* better to use the time field from the event that triggered the
2006 * call to this function, but that isn't trivial to get
2015 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2022 { // bassic primitive for determining if modifier keys are pressed
2023 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2026 XQueryKeymap(xDisplay,keys);
2027 for(i=0; i<6; i++) {
2029 j = XKeysymToKeycode(xDisplay, codes[i]);
2030 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2036 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2040 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2041 if ( n == 1 && *buf >= 32 // printable
2042 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2043 ) BoxAutoPopUp (buf);
2047 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2048 { // [HGM] input: let up-arrow recall previous line from history
2053 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2054 { // [HGM] input: let down-arrow recall next line from history
2059 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2065 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2067 if (!TempBackwardActive) {
2068 TempBackwardActive = True;
2074 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2076 /* Check to see if triggered by a key release event for a repeating key.
2077 * If so the next queued event will be a key press of the same key at the same time */
2078 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2080 XPeekEvent(xDisplay, &next);
2081 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2082 next.xkey.keycode == event->xkey.keycode)
2086 TempBackwardActive = False;
2090 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2091 { // called as key binding
2094 if (nprms && *nprms > 0)
2098 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2104 { // called from menu
2105 ManInner(NULL, NULL, NULL, NULL);
2109 SetWindowTitle (char *text, char *title, char *icon)
2113 if (appData.titleInWindow) {
2115 XtSetArg(args[i], XtNlabel, text); i++;
2116 XtSetValues(titleWidget, args, i);
2119 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2120 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2121 XtSetValues(shellWidget, args, i);
2122 XSync(xDisplay, False);
2127 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2133 DisplayIcsInteractionTitle (String message)
2135 if (oldICSInteractionTitle == NULL) {
2136 /* Magic to find the old window title, adapted from vim */
2137 char *wina = getenv("WINDOWID");
2139 Window win = (Window) atoi(wina);
2140 Window root, parent, *children;
2141 unsigned int nchildren;
2142 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2144 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2145 if (!XQueryTree(xDisplay, win, &root, &parent,
2146 &children, &nchildren)) break;
2147 if (children) XFree((void *)children);
2148 if (parent == root || parent == 0) break;
2151 XSetErrorHandler(oldHandler);
2153 if (oldICSInteractionTitle == NULL) {
2154 oldICSInteractionTitle = "xterm";
2157 printf("\033]0;%s\007", message);
2162 XtIntervalId delayedEventTimerXID = 0;
2163 DelayedEventCallback delayedEventCallback = 0;
2168 delayedEventTimerXID = 0;
2169 delayedEventCallback();
2173 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2175 if(delayedEventTimerXID && delayedEventCallback == cb)
2176 // [HGM] alive: replace, rather than add or flush identical event
2177 XtRemoveTimeOut(delayedEventTimerXID);
2178 delayedEventCallback = cb;
2179 delayedEventTimerXID =
2180 XtAppAddTimeOut(appContext, millisec,
2181 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2184 DelayedEventCallback
2187 if (delayedEventTimerXID) {
2188 return delayedEventCallback;
2195 CancelDelayedEvent ()
2197 if (delayedEventTimerXID) {
2198 XtRemoveTimeOut(delayedEventTimerXID);
2199 delayedEventTimerXID = 0;
2203 XtIntervalId loadGameTimerXID = 0;
2206 LoadGameTimerRunning ()
2208 return loadGameTimerXID != 0;
2212 StopLoadGameTimer ()
2214 if (loadGameTimerXID != 0) {
2215 XtRemoveTimeOut(loadGameTimerXID);
2216 loadGameTimerXID = 0;
2224 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2226 loadGameTimerXID = 0;
2231 StartLoadGameTimer (long millisec)
2234 XtAppAddTimeOut(appContext, millisec,
2235 (XtTimerCallbackProc) LoadGameTimerCallback,
2239 XtIntervalId analysisClockXID = 0;
2242 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2244 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2245 || appData.icsEngineAnalyze) { // [DM]
2246 AnalysisPeriodicEvent(0);
2247 StartAnalysisClock();
2252 StartAnalysisClock ()
2255 XtAppAddTimeOut(appContext, 2000,
2256 (XtTimerCallbackProc) AnalysisClockCallback,
2260 XtIntervalId clockTimerXID = 0;
2263 ClockTimerRunning ()
2265 return clockTimerXID != 0;
2271 if (clockTimerXID != 0) {
2272 XtRemoveTimeOut(clockTimerXID);
2281 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2288 StartClockTimer (long millisec)
2291 XtAppAddTimeOut(appContext, millisec,
2292 (XtTimerCallbackProc) ClockTimerCallback,
2297 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2301 Widget w = (Widget) opt->handle;
2303 /* check for low time warning */
2304 Pixel foregroundOrWarningColor = timerForegroundPixel;
2307 appData.lowTimeWarning &&
2308 (timer / 1000) < appData.icsAlarmTime)
2309 foregroundOrWarningColor = lowTimeWarningColor;
2311 if (appData.clockMode) {
2312 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2313 XtSetArg(args[0], XtNlabel, buf);
2315 snprintf(buf, MSG_SIZ, "%s ", color);
2316 XtSetArg(args[0], XtNlabel, buf);
2321 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2322 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2324 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2325 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2328 XtSetValues(w, args, 3);
2331 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2334 SetClockIcon (int color)
2337 Pixmap pm = *clockIcons[color];
2338 if (iconPixmap != pm) {
2340 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2341 XtSetValues(shellWidget, args, 1);
2345 #define INPUT_SOURCE_BUF_SIZE 8192
2354 char buf[INPUT_SOURCE_BUF_SIZE];
2359 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2361 InputSource *is = (InputSource *) closure;
2366 if (is->lineByLine) {
2367 count = read(is->fd, is->unused,
2368 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2370 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2373 is->unused += count;
2375 while (p < is->unused) {
2376 q = memchr(p, '\n', is->unused - p);
2377 if (q == NULL) break;
2379 (is->func)(is, is->closure, p, q - p, 0);
2383 while (p < is->unused) {
2388 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2393 (is->func)(is, is->closure, is->buf, count, error);
2398 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2401 ChildProc *cp = (ChildProc *) pr;
2403 is = (InputSource *) calloc(1, sizeof(InputSource));
2404 is->lineByLine = lineByLine;
2408 is->fd = fileno(stdin);
2410 is->kind = cp->kind;
2411 is->fd = cp->fdFrom;
2414 is->unused = is->buf;
2417 is->xid = XtAppAddInput(appContext, is->fd,
2418 (XtPointer) (XtInputReadMask),
2419 (XtInputCallbackProc) DoInputCallback,
2421 is->closure = closure;
2422 return (InputSourceRef) is;
2426 RemoveInputSource (InputSourceRef isr)
2428 InputSource *is = (InputSource *) isr;
2430 if (is->xid == 0) return;
2431 XtRemoveInput(is->xid);
2437 static Boolean frameWaiting;
2440 FrameAlarm (int sig)
2442 frameWaiting = False;
2443 /* In case System-V style signals. Needed?? */
2444 signal(SIGALRM, FrameAlarm);
2448 FrameDelay (int time)
2450 struct itimerval delay;
2452 XSync(xDisplay, False);
2455 frameWaiting = True;
2456 signal(SIGALRM, FrameAlarm);
2457 delay.it_interval.tv_sec =
2458 delay.it_value.tv_sec = time / 1000;
2459 delay.it_interval.tv_usec =
2460 delay.it_value.tv_usec = (time % 1000) * 1000;
2461 setitimer(ITIMER_REAL, &delay, NULL);
2462 while (frameWaiting) pause();
2463 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2464 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2465 setitimer(ITIMER_REAL, &delay, NULL);
2472 FrameDelay (int time)
2474 XSync(xDisplay, False);
2476 usleep(time * 1000);
2482 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2484 char buf[MSG_SIZ], *logoName = buf;
2485 if(appData.logo[n][0]) {
2486 logoName = appData.logo[n];
2487 } else if(appData.autoLogo) {
2488 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2489 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2490 } else if(appData.directory[n] && appData.directory[n][0]) {
2491 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2495 { ASSIGN(cps->programLogo, logoName); }
2499 UpdateLogos (int displ)
2501 if(optList[W_WHITE-1].handle == NULL) return;
2502 LoadLogo(&first, 0, 0);
2503 LoadLogo(&second, 1, appData.icsActive);
2504 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);