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(strstr(name, "-*-") && // only pay attention to things that look like X-fonts
500 size >= 0 && size<MAX_SIZE) { // for now, fixed limit
501 fontTable[number][size] = strdup(strchr(name, ':')+1);
502 fontValid[number][size] = True;
507 case 0: // CLOCK_FONT
508 appData.clockFont = strdup(name);
510 case 1: // MESSAGE_FONT
511 appData.font = strdup(name);
513 case 2: // COORD_FONT
514 appData.coordFont = strdup(name);
519 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
524 { // only 2 fonts currently
525 appData.clockFont = CLOCK_FONT_NAME;
526 appData.coordFont = COORD_FONT_NAME;
527 appData.font = DEFAULT_FONT_NAME;
532 { // no-op, until we identify the code for this already in XBoard and move it here
536 ParseColor (int n, char *name)
537 { // in XBoard, just copy the color-name string
538 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
544 return *(char**)colorVariable[n];
548 ParseTextAttribs (ColorClass cc, char *s)
550 (&appData.colorShout)[cc] = strdup(s);
554 ParseBoardSize (void *addr, char *name)
556 appData.boardSize = strdup(name);
561 { // In XBoard the sound-playing program takes care of obtaining the actual sound
565 SetCommPortDefaults ()
566 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
569 // [HGM] args: these three cases taken out to stay in front-end
571 SaveFontArg (FILE *f, ArgDescriptor *ad)
574 int i, n = (int)(intptr_t)ad->argLoc;
576 case 0: // CLOCK_FONT
577 name = appData.clockFont;
579 case 1: // MESSAGE_FONT
582 case 2: // COORD_FONT
583 name = appData.coordFont;
588 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
589 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
590 fontTable[n][squareSize] = strdup(name);
591 fontValid[n][squareSize] = True;
594 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
595 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
600 { // nothing to do, as the sounds are at all times represented by their text-string names already
604 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
605 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
606 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
610 SaveColor (FILE *f, ArgDescriptor *ad)
611 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
612 if(colorVariable[(int)(intptr_t)ad->argLoc])
613 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
617 SaveBoardSize (FILE *f, char *name, void *addr)
618 { // wrapper to shield back-end from BoardSize & sizeInfo
619 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
623 ParseCommPortSettings (char *s)
624 { // no such option in XBoard (yet)
630 GetActualPlacement (Widget wg, WindowPlacement *wp)
632 XWindowAttributes winAt;
639 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
640 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
641 wp->x = rx - winAt.x;
642 wp->y = ry - winAt.y;
643 wp->height = winAt.height;
644 wp->width = winAt.width;
645 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
649 GetPlacement (DialogClass dlg, WindowPlacement *wp)
650 { // wrapper to shield back-end from widget type
651 if(shellUp[dlg]) GetActualPlacement(shells[dlg], wp);
656 { // wrapper to shield use of window handles from back-end (make addressible by number?)
657 // In XBoard this will have to wait until awareness of window parameters is implemented
658 GetActualPlacement(shellWidget, &wpMain);
659 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
660 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
661 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
662 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
663 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
664 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
668 PrintCommPortSettings (FILE *f, char *name)
669 { // This option does not exist in XBoard
673 EnsureOnScreen (int *x, int *y, int minX, int minY)
680 { // [HGM] args: allows testing if main window is realized from back-end
681 return xBoardWindow != 0;
685 PopUpStartupDialog ()
686 { // start menu not implemented in XBoard
690 ConvertToLine (int argc, char **argv)
692 static char line[128*1024], buf[1024];
696 for(i=1; i<argc; i++)
698 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
699 && argv[i][0] != '{' )
700 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
702 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
703 strncat(line, buf, 128*1024 - strlen(line) - 1 );
706 line[strlen(line)-1] = NULLCHAR;
710 //--------------------------------------------------------------------------------------------
713 ResizeBoardWindow (int w, int h, int inhibit)
715 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
717 shellArgs[0].value = w;
718 shellArgs[1].value = h;
719 shellArgs[4].value = shellArgs[2].value = w;
720 shellArgs[5].value = shellArgs[3].value = h;
721 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
723 XSync(xDisplay, False);
727 MakeOneColor (char *name, Pixel *color)
730 if (!appData.monoMode) {
731 vFrom.addr = (caddr_t) name;
732 vFrom.size = strlen(name);
733 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
734 if (vTo.addr == NULL) {
735 appData.monoMode = True;
738 *color = *(Pixel *) vTo.addr;
746 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
747 int forceMono = False;
749 if (appData.lowTimeWarning)
750 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
751 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
752 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
758 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
759 { // detervtomine what fonts to use, and create them
763 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
764 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
765 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
766 appData.font = fontTable[MESSAGE_FONT][squareSize];
767 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
768 appData.coordFont = fontTable[COORD_FONT][squareSize];
771 appData.font = InsertPxlSize(appData.font, fontPxlSize);
772 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
773 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
774 fontSet = CreateFontSet(appData.font);
775 clockFontSet = CreateFontSet(appData.clockFont);
777 /* For the coordFont, use the 0th font of the fontset. */
778 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
779 XFontStruct **font_struct_list;
780 XFontSetExtents *fontSize;
781 char **font_name_list;
782 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
783 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
784 coordFontStruct = XQueryFont(xDisplay, coordFontID);
785 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
786 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
789 appData.font = FindFont(appData.font, fontPxlSize);
790 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
791 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
792 clockFontID = XLoadFont(xDisplay, appData.clockFont);
793 clockFontStruct = XQueryFont(xDisplay, clockFontID);
794 coordFontID = XLoadFont(xDisplay, appData.coordFont);
795 coordFontStruct = XQueryFont(xDisplay, coordFontID);
796 // textHeight in !NLS mode!
798 countFontID = coordFontID; // [HGM] holdings
799 countFontStruct = coordFontStruct;
801 xdb = XtDatabase(xDisplay);
803 XrmPutLineResource(&xdb, "*international: True");
804 vTo.size = sizeof(XFontSet);
805 vTo.addr = (XtPointer) &fontSet;
806 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
808 XrmPutStringResource(&xdb, "*font", appData.font);
818 case ArgInt: p = " N"; break;
819 case ArgString: p = " STR"; break;
820 case ArgBoolean: p = " TF"; break;
821 case ArgSettingsFilename:
822 case ArgBackupSettingsFile:
823 case ArgFilename: p = " FILE"; break;
824 case ArgX: p = " Nx"; break;
825 case ArgY: p = " Ny"; break;
826 case ArgAttribs: p = " TEXTCOL"; break;
827 case ArgColor: p = " COL"; break;
828 case ArgFont: p = " FONT"; break;
829 case ArgBoardSize: p = " SIZE"; break;
830 case ArgFloat: p = " FLOAT"; break;
835 case ArgCommSettings:
844 GenerateGlobalTranslationTable (void)
846 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
854 /* loop over all menu entries */
855 for( i=0; menuBar[i].mi ; i++)
858 for(j=0; mi[j].proc; j++)
866 char *key,*test, *mods;
868 /* check for Ctrl/Alt */
869 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
870 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
871 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
873 /* remove all <...> */
874 test = strrchr(mi[j].accel, '>');
876 key = strdup(mi[j].accel);
878 key = strdup(++test); // remove ">"
880 /* instead of shift X11 uses the uppercase letter directly*/
881 if (shift && strlen(key)==1 )
883 *key = toupper(*key);
887 /* handle some special cases which have different names in X11 */
888 if ( strncmp(key, "Page_Down", 9) == 0 )
893 else if ( strncmp(key, "Page_Up", 7) == 0 )
899 /* create string of mods */
901 mods = strdup("Ctrl ");
907 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
908 strncat(mods, "Meta ", 5);
913 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
914 strncat(mods, "Shift ", 6);
917 // remove trailing space
918 if( isspace(mods[strlen(mods)-1]) )
919 mods[strlen(mods)-1]='\0';
921 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
922 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
923 char *name = malloc(namesize+1);
924 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
926 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
927 char *buffer = malloc(buffersize+1);
928 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
930 /* add string to the output */
931 output = realloc(output, strlen(output) + strlen(buffer)+1);
932 strncat(output, buffer, strlen(buffer));
951 ArgDescriptor *q, *p = argDescriptors+5;
952 printf("\nXBoard accepts the following options:\n"
953 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
954 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
955 " SIZE = board-size spec(s)\n"
956 " Within parentheses are short forms, or options to set to true or false.\n"
957 " Persistent options (saved in the settings file) are marked with *)\n\n");
959 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
960 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
961 if(p->save) strcat(buf+len, "*");
962 for(q=p+1; q->argLoc == p->argLoc; q++) {
963 if(q->argName[0] == '-') continue;
964 strcat(buf+len, q == p+1 ? " (" : " ");
965 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
967 if(q != p+1) strcat(buf+len, ")");
969 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
972 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
976 SlaveResize (Option *opt)
981 main (int argc, char **argv)
983 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
984 XSetWindowAttributes window_attributes;
986 Dimension boardWidth, boardHeight, w, h;
988 int forceMono = False;
990 srandom(time(0)); // [HGM] book: make random truly random
992 setbuf(stdout, NULL);
993 setbuf(stderr, NULL);
996 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
997 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1001 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1006 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1007 typedef struct {char *name, *value; } Config;
1008 static Config configList[] = {
1009 { "Datadir", DATADIR },
1010 { "Sysconfdir", SYSCONFDIR },
1015 for(i=0; configList[i].name; i++) {
1016 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1017 if(argc > 2) printf("%s", configList[i].value);
1018 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1023 programName = strrchr(argv[0], '/');
1024 if (programName == NULL)
1025 programName = argv[0];
1030 XtSetLanguageProc(NULL, NULL, NULL);
1031 if (appData.debugMode) {
1032 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1035 bindtextdomain(PACKAGE, LOCALEDIR);
1036 textdomain(PACKAGE);
1039 appData.boardSize = "";
1040 InitAppData(ConvertToLine(argc, argv));
1042 if (p == NULL) p = "/tmp";
1043 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1044 gameCopyFilename = (char*) malloc(i);
1045 gamePasteFilename = (char*) malloc(i);
1046 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1047 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1049 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1050 static char buf[MSG_SIZ];
1051 EscapeExpand(buf, appData.firstInitString);
1052 appData.firstInitString = strdup(buf);
1053 EscapeExpand(buf, appData.secondInitString);
1054 appData.secondInitString = strdup(buf);
1055 EscapeExpand(buf, appData.firstComputerString);
1056 appData.firstComputerString = strdup(buf);
1057 EscapeExpand(buf, appData.secondComputerString);
1058 appData.secondComputerString = strdup(buf);
1061 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1064 if (chdir(chessDir) != 0) {
1065 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1071 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1072 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1073 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1074 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1077 setbuf(debugFP, NULL);
1080 /* [HGM,HR] make sure board size is acceptable */
1081 if(appData.NrFiles > BOARD_FILES ||
1082 appData.NrRanks > BOARD_RANKS )
1083 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1086 /* This feature does not work; animation needs a rewrite */
1087 appData.highlightDragging = FALSE;
1091 gameInfo.variant = StringToVariant(appData.variant);
1092 InitPosition(FALSE);
1095 XtAppInitialize(&appContext, "XBoard", shellOptions,
1096 XtNumber(shellOptions),
1097 &argc, argv, xboardResources, NULL, 0);
1099 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1100 clientResources, XtNumber(clientResources),
1103 xDisplay = XtDisplay(shellWidget);
1104 xScreen = DefaultScreen(xDisplay);
1105 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1108 * determine size, based on supplied or remembered -size, or screen size
1110 if (isdigit(appData.boardSize[0])) {
1111 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1112 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1113 &fontPxlSize, &smallLayout, &tinyLayout);
1115 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1116 programName, appData.boardSize);
1120 squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
1122 /* Find some defaults; use the nearest known size */
1123 SizeDefaults *szd, *nearest;
1124 int distance = 99999;
1125 nearest = szd = sizeDefaults;
1126 while (szd->name != NULL) {
1127 if (abs(szd->squareSize - squareSize) < distance) {
1129 distance = abs(szd->squareSize - squareSize);
1130 if (distance == 0) break;
1134 if (i < 2) lineGap = nearest->lineGap;
1135 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1136 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1137 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1138 if (i < 6) smallLayout = nearest->smallLayout;
1139 if (i < 7) tinyLayout = nearest->tinyLayout;
1142 SizeDefaults *szd = sizeDefaults;
1143 if (*appData.boardSize == NULLCHAR) {
1144 while (DisplayWidth(xDisplay, xScreen) < (szd->minScreenSize*BOARD_WIDTH + 4)/8 ||
1145 DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
1148 if (szd->name == NULL) szd--;
1149 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1151 while (szd->name != NULL &&
1152 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1153 if (szd->name == NULL) {
1154 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1155 programName, appData.boardSize);
1159 squareSize = szd->squareSize;
1160 lineGap = szd->lineGap;
1161 clockFontPxlSize = szd->clockFontPxlSize;
1162 coordFontPxlSize = szd->coordFontPxlSize;
1163 fontPxlSize = szd->fontPxlSize;
1164 smallLayout = szd->smallLayout;
1165 tinyLayout = szd->tinyLayout;
1166 // [HGM] font: use defaults from settings file if available and not overruled
1169 defaultLineGap = lineGap;
1170 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1172 /* [HR] height treated separately (hacked) */
1173 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1174 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1177 * Determine what fonts to use.
1179 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1182 * Detect if there are not enough colors available and adapt.
1184 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1185 appData.monoMode = True;
1188 forceMono = MakeColors();
1191 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1193 appData.monoMode = True;
1196 if (appData.monoMode && appData.debugMode) {
1197 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1198 (unsigned long) XWhitePixel(xDisplay, xScreen),
1199 (unsigned long) XBlackPixel(xDisplay, xScreen));
1202 ParseIcsTextColors();
1204 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1210 layoutName = "tinyLayout";
1211 } else if (smallLayout) {
1212 layoutName = "smallLayout";
1214 layoutName = "normalLayout";
1217 optList = BoardPopUp(squareSize, lineGap, (void*)
1223 InitDrawingHandle(optList + W_BOARD);
1224 currBoard = &optList[W_BOARD];
1225 boardWidget = optList[W_BOARD].handle;
1226 menuBarWidget = optList[W_MENU].handle;
1227 dropMenu = optList[W_DROP].handle;
1228 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1229 formWidget = XtParent(boardWidget);
1230 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1231 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1232 XtGetValues(optList[W_WHITE].handle, args, 2);
1233 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1234 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1235 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1236 XtGetValues(optList[W_PAUSE].handle, args, 2);
1239 xBoardWindow = XtWindow(boardWidget);
1241 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1242 // not need to go into InitDrawingSizes().
1245 * Create X checkmark bitmap and initialize option menu checks.
1247 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1248 checkmark_bits, checkmark_width, checkmark_height);
1254 ReadBitmap(&wIconPixmap, "icon_white.bm",
1255 icon_white_bits, icon_white_width, icon_white_height);
1256 ReadBitmap(&bIconPixmap, "icon_black.bm",
1257 icon_black_bits, icon_black_width, icon_black_height);
1258 iconPixmap = wIconPixmap;
1260 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1261 XtSetValues(shellWidget, args, i);
1264 * Create a cursor for the board widget.
1266 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1267 XChangeWindowAttributes(xDisplay, xBoardWindow,
1268 CWCursor, &window_attributes);
1271 * Inhibit shell resizing.
1273 shellArgs[0].value = (XtArgVal) &w;
1274 shellArgs[1].value = (XtArgVal) &h;
1275 XtGetValues(shellWidget, shellArgs, 2);
1276 shellArgs[4].value = shellArgs[2].value = w;
1277 shellArgs[5].value = shellArgs[3].value = h;
1278 // XtSetValues(shellWidget, &shellArgs[2], 4);
1279 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1280 marginH = h - boardHeight;
1282 CatchDeleteWindow(shellWidget, "QuitProc");
1287 if(appData.logoSize)
1288 { // locate and read user logo
1290 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1291 ASSIGN(userLogo, buf);
1294 if (appData.animate || appData.animateDragging)
1298 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1300 XtAugmentTranslations(formWidget,
1301 XtParseTranslationTable(globalTranslations));
1302 XtAugmentTranslations(formWidget,
1303 XtParseTranslationTable(TranslationsTableMenus));
1305 XtAddEventHandler(formWidget, KeyPressMask, False,
1306 (XtEventHandler) MoveTypeInProc, NULL);
1307 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1308 (XtEventHandler) EventProc, NULL);
1310 /* [AS] Restore layout */
1311 if( wpMoveHistory.visible ) {
1315 if( wpEvalGraph.visible )
1320 if( wpEngineOutput.visible ) {
1321 EngineOutputPopUp();
1324 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1329 if (errorExitStatus == -1) {
1330 if (appData.icsActive) {
1331 /* We now wait until we see "login:" from the ICS before
1332 sending the logon script (problems with timestamp otherwise) */
1333 /*ICSInitScript();*/
1334 if (appData.icsInputBox) ICSInputBoxPopUp();
1338 signal(SIGWINCH, TermSizeSigHandler);
1340 signal(SIGINT, IntSigHandler);
1341 signal(SIGTERM, IntSigHandler);
1342 if (*appData.cmailGameName != NULLCHAR) {
1343 signal(SIGUSR1, CmailSigHandler);
1348 // XtSetKeyboardFocus(shellWidget, formWidget);
1349 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1351 XtAppMainLoop(appContext);
1352 if (appData.debugMode) fclose(debugFP); // [DM] debug
1357 TermSizeSigHandler (int sig)
1363 IntSigHandler (int sig)
1369 CmailSigHandler (int sig)
1374 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1376 /* Activate call-back function CmailSigHandlerCallBack() */
1377 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1379 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1383 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1386 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1388 /**** end signal code ****/
1391 #define Abs(n) ((n)<0 ? -(n) : (n))
1395 InsertPxlSize (char *pattern, int targetPxlSize)
1397 char *base_fnt_lst, strInt[12], *p, *q;
1398 int alternatives, i, len, strIntLen;
1401 * Replace the "*" (if present) in the pixel-size slot of each
1402 * alternative with the targetPxlSize.
1406 while ((p = strchr(p, ',')) != NULL) {
1410 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1411 strIntLen = strlen(strInt);
1412 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1416 while (alternatives--) {
1417 char *comma = strchr(p, ',');
1418 for (i=0; i<14; i++) {
1419 char *hyphen = strchr(p, '-');
1421 if (comma && hyphen > comma) break;
1422 len = hyphen + 1 - p;
1423 if (i == 7 && *p == '*' && len == 2) {
1425 memcpy(q, strInt, strIntLen);
1435 len = comma + 1 - p;
1442 return base_fnt_lst;
1446 CreateFontSet (char *base_fnt_lst)
1449 char **missing_list;
1453 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1454 &missing_list, &missing_count, &def_string);
1455 if (appData.debugMode) {
1457 XFontStruct **font_struct_list;
1458 char **font_name_list;
1459 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1461 fprintf(debugFP, " got list %s, locale %s\n",
1462 XBaseFontNameListOfFontSet(fntSet),
1463 XLocaleOfFontSet(fntSet));
1464 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1465 for (i = 0; i < count; i++) {
1466 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1469 for (i = 0; i < missing_count; i++) {
1470 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1473 if (fntSet == NULL) {
1474 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1479 #else // not ENABLE_NLS
1481 * Find a font that matches "pattern" that is as close as
1482 * possible to the targetPxlSize. Prefer fonts that are k
1483 * pixels smaller to fonts that are k pixels larger. The
1484 * pattern must be in the X Consortium standard format,
1485 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1486 * The return value should be freed with XtFree when no
1490 FindFont (char *pattern, int targetPxlSize)
1492 char **fonts, *p, *best, *scalable, *scalableTail;
1493 int i, j, nfonts, minerr, err, pxlSize;
1495 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1497 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1498 programName, pattern);
1505 for (i=0; i<nfonts; i++) {
1508 if (*p != '-') continue;
1510 if (*p == NULLCHAR) break;
1511 if (*p++ == '-') j++;
1513 if (j < 7) continue;
1516 scalable = fonts[i];
1519 err = pxlSize - targetPxlSize;
1520 if (Abs(err) < Abs(minerr) ||
1521 (minerr > 0 && err < 0 && -err == minerr)) {
1527 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1528 /* If the error is too big and there is a scalable font,
1529 use the scalable font. */
1530 int headlen = scalableTail - scalable;
1531 p = (char *) XtMalloc(strlen(scalable) + 10);
1532 while (isdigit(*scalableTail)) scalableTail++;
1533 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1535 p = (char *) XtMalloc(strlen(best) + 2);
1536 safeStrCpy(p, best, strlen(best)+1 );
1538 if (appData.debugMode) {
1539 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1540 pattern, targetPxlSize, p);
1542 XFreeFontNames(fonts);
1548 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1551 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1557 MarkMenuItem (char *menuRef, int state)
1559 MenuItem *item = MenuNameToItem(menuRef);
1563 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1564 XtSetValues(item->handle, args, 1);
1569 EnableNamedMenuItem (char *menuRef, int state)
1571 MenuItem *item = MenuNameToItem(menuRef);
1573 if(item) XtSetSensitive(item->handle, state);
1577 EnableButtonBar (int state)
1579 XtSetSensitive(optList[W_BUTTON].handle, state);
1584 SetMenuEnables (Enables *enab)
1586 while (enab->name != NULL) {
1587 EnableNamedMenuItem(enab->name, enab->value);
1593 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1594 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1596 if(*nprms == 0) return;
1597 item = MenuNameToItem(prms[0]);
1598 if(item) ((MenuProc *) item->proc) ();
1610 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1611 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1612 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1613 dmEnables[i].piece);
1614 XtSetSensitive(entry, p != NULL || !appData.testLegality
1615 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1616 && !appData.icsActive));
1618 while (p && *p++ == dmEnables[i].piece) count++;
1619 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1621 XtSetArg(args[j], XtNlabel, label); j++;
1622 XtSetValues(entry, args, j);
1627 do_flash_delay (unsigned long msec)
1633 FlashDelay (int flash_delay)
1635 XSync(xDisplay, False);
1636 if(flash_delay) do_flash_delay(flash_delay);
1640 Fraction (int x, int start, int stop)
1642 double f = ((double) x - start)/(stop - start);
1643 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1647 static WindowPlacement wpNew;
1650 CoDrag (Widget sh, WindowPlacement *wp)
1653 int j=0, touch=0, fudge = 2;
1654 GetActualPlacement(sh, wp);
1655 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1656 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1657 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1658 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1659 if(!touch ) return; // only windows that touch co-move
1660 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1661 int heightInc = wpNew.height - wpMain.height;
1662 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1663 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1664 wp->y += fracTop * heightInc;
1665 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1666 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1667 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1668 int widthInc = wpNew.width - wpMain.width;
1669 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1670 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1671 wp->y += fracLeft * widthInc;
1672 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1673 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1675 wp->x += wpNew.x - wpMain.x;
1676 wp->y += wpNew.y - wpMain.y;
1677 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1678 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1679 XtSetArg(args[j], XtNx, wp->x); j++;
1680 XtSetArg(args[j], XtNy, wp->y); j++;
1681 XtSetValues(sh, args, j);
1685 ReSize (WindowPlacement *wp)
1688 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1689 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1690 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1691 if(sqy < sqx) sqx = sqy;
1692 if(sqx != squareSize) {
1693 squareSize = sqx; // adopt new square size
1694 CreatePNGPieces(); // make newly scaled pieces
1695 InitDrawingSizes(0, 0); // creates grid etc.
1696 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1697 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1698 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1699 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1700 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1703 static XtIntervalId delayedDragID = 0;
1712 GetActualPlacement(shellWidget, &wpNew);
1713 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1714 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1715 busy = 0; return; // false alarm
1718 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1719 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1720 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1721 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1723 DrawPosition(True, NULL);
1724 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1732 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1734 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1738 EventProc (Widget widget, caddr_t unused, XEvent *event)
1740 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1741 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1745 * event handler for redrawing the board
1748 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1750 DrawPosition(True, NULL);
1755 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1756 { // [HGM] pv: walk PV
1757 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1760 extern int savedIndex; /* gross that this is global */
1763 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1766 XawTextPosition index, dummy;
1769 XawTextGetSelectionPos(w, &index, &dummy);
1770 XtSetArg(arg, XtNstring, &val);
1771 XtGetValues(w, &arg, 1);
1772 ReplaceComment(savedIndex, val);
1773 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1774 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1778 /* Disable all user input other than deleting the window */
1779 static int frozen = 0;
1785 /* Grab by a widget that doesn't accept input */
1786 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1790 /* Undo a FreezeUI */
1794 if (!frozen) return;
1795 XtRemoveGrab(optList[W_MESSG].handle);
1803 static int oldPausing = FALSE;
1804 static GameMode oldmode = (GameMode) -1;
1807 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1809 if (pausing != oldPausing) {
1810 oldPausing = pausing;
1811 MarkMenuItem("Mode.Pause", pausing);
1813 if (appData.showButtonBar) {
1814 /* Always toggle, don't set. Previous code messes up when
1815 invoked while the button is pressed, as releasing it
1816 toggles the state again. */
1819 XtSetArg(args[0], XtNbackground, &oldbg);
1820 XtSetArg(args[1], XtNforeground, &oldfg);
1821 XtGetValues(optList[W_PAUSE].handle,
1823 XtSetArg(args[0], XtNbackground, oldfg);
1824 XtSetArg(args[1], XtNforeground, oldbg);
1826 XtSetValues(optList[W_PAUSE].handle, args, 2);
1830 wname = ModeToWidgetName(oldmode);
1831 if (wname != NULL) {
1832 MarkMenuItem(wname, False);
1834 wname = ModeToWidgetName(gameMode);
1835 if (wname != NULL) {
1836 MarkMenuItem(wname, True);
1839 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1841 /* Maybe all the enables should be handled here, not just this one */
1842 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1844 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1849 * Button/menu procedures
1852 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1853 char *selected_fen_position=NULL;
1856 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1857 Atom *type_return, XtPointer *value_return,
1858 unsigned long *length_return, int *format_return)
1860 char *selection_tmp;
1862 // if (!selected_fen_position) return False; /* should never happen */
1863 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1864 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1865 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1868 if (f == NULL) return False;
1872 selection_tmp = XtMalloc(len + 1);
1873 count = fread(selection_tmp, 1, len, f);
1876 XtFree(selection_tmp);
1879 selection_tmp[len] = NULLCHAR;
1881 /* note: since no XtSelectionDoneProc was registered, Xt will
1882 * automatically call XtFree on the value returned. So have to
1883 * make a copy of it allocated with XtMalloc */
1884 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1885 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1888 *value_return=selection_tmp;
1889 *length_return=strlen(selection_tmp);
1890 *type_return=*target;
1891 *format_return = 8; /* bits per byte */
1893 } else if (*target == XA_TARGETS(xDisplay)) {
1894 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1895 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1896 targets_tmp[1] = XA_STRING;
1897 *value_return = targets_tmp;
1898 *type_return = XA_ATOM;
1901 // This code leads to a read of value_return out of bounds on 64-bit systems.
1902 // Other code which I have seen always sets *format_return to 32 independent of
1903 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1904 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1905 *format_return = 8 * sizeof(Atom);
1906 if (*format_return > 32) {
1907 *length_return *= *format_return / 32;
1908 *format_return = 32;
1911 *format_return = 32;
1919 /* note: when called from menu all parameters are NULL, so no clue what the
1920 * Widget which was clicked on was, or what the click event was
1923 CopySomething (char *src)
1925 selected_fen_position = src;
1927 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1928 * have a notion of a position that is selected but not copied.
1929 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1931 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1933 SendPositionSelection,
1934 NULL/* lose_ownership_proc */ ,
1935 NULL/* transfer_done_proc */);
1936 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1938 SendPositionSelection,
1939 NULL/* lose_ownership_proc */ ,
1940 NULL/* transfer_done_proc */);
1943 /* function called when the data to Paste is ready */
1945 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1946 Atom *type, XtPointer value, unsigned long *len, int *format)
1949 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1950 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1951 EditPositionPasteFEN(fenstr);
1955 /* called when Paste Position button is pressed,
1956 * all parameters will be NULL */
1958 PastePositionProc ()
1960 XtGetSelectionValue(menuBarWidget,
1961 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1962 /* (XtSelectionCallbackProc) */ PastePositionCB,
1963 NULL, /* client_data passed to PastePositionCB */
1965 /* better to use the time field from the event that triggered the
1966 * call to this function, but that isn't trivial to get
1973 /* note: when called from menu all parameters are NULL, so no clue what the
1974 * Widget which was clicked on was, or what the click event was
1976 /* function called when the data to Paste is ready */
1978 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1979 Atom *type, XtPointer value, unsigned long *len, int *format)
1982 if (value == NULL || *len == 0) {
1983 return; /* nothing had been selected to copy */
1985 f = fopen(gamePasteFilename, "w");
1987 DisplayError(_("Can't open temp file"), errno);
1990 fwrite(value, 1, *len, f);
1993 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
1996 /* called when Paste Game button is pressed,
1997 * all parameters will be NULL */
2001 XtGetSelectionValue(menuBarWidget,
2002 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2003 /* (XtSelectionCallbackProc) */ PasteGameCB,
2004 NULL, /* client_data passed to PasteGameCB */
2006 /* better to use the time field from the event that triggered the
2007 * call to this function, but that isn't trivial to get
2016 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2023 { // bassic primitive for determining if modifier keys are pressed
2024 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2027 XQueryKeymap(xDisplay,keys);
2028 for(i=0; i<6; i++) {
2030 j = XKeysymToKeycode(xDisplay, codes[i]);
2031 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2037 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2041 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2042 if ( n == 1 && *buf >= 32 // printable
2043 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2044 ) BoxAutoPopUp (buf);
2048 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2049 { // [HGM] input: let up-arrow recall previous line from history
2054 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2055 { // [HGM] input: let down-arrow recall next line from history
2060 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2066 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2068 if (!TempBackwardActive) {
2069 TempBackwardActive = True;
2075 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2077 /* Check to see if triggered by a key release event for a repeating key.
2078 * If so the next queued event will be a key press of the same key at the same time */
2079 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2081 XPeekEvent(xDisplay, &next);
2082 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2083 next.xkey.keycode == event->xkey.keycode)
2087 TempBackwardActive = False;
2091 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2092 { // called as key binding
2095 if (nprms && *nprms > 0)
2099 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2105 { // called from menu
2106 ManInner(NULL, NULL, NULL, NULL);
2110 SetWindowTitle (char *text, char *title, char *icon)
2114 if (appData.titleInWindow) {
2116 XtSetArg(args[i], XtNlabel, text); i++;
2117 XtSetValues(titleWidget, args, i);
2120 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2121 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2122 XtSetValues(shellWidget, args, i);
2123 XSync(xDisplay, False);
2128 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2134 DisplayIcsInteractionTitle (String message)
2136 if (oldICSInteractionTitle == NULL) {
2137 /* Magic to find the old window title, adapted from vim */
2138 char *wina = getenv("WINDOWID");
2140 Window win = (Window) atoi(wina);
2141 Window root, parent, *children;
2142 unsigned int nchildren;
2143 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2145 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2146 if (!XQueryTree(xDisplay, win, &root, &parent,
2147 &children, &nchildren)) break;
2148 if (children) XFree((void *)children);
2149 if (parent == root || parent == 0) break;
2152 XSetErrorHandler(oldHandler);
2154 if (oldICSInteractionTitle == NULL) {
2155 oldICSInteractionTitle = "xterm";
2158 printf("\033]0;%s\007", message);
2163 XtIntervalId delayedEventTimerXID = 0;
2164 DelayedEventCallback delayedEventCallback = 0;
2169 delayedEventTimerXID = 0;
2170 delayedEventCallback();
2174 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2176 if(delayedEventTimerXID && delayedEventCallback == cb)
2177 // [HGM] alive: replace, rather than add or flush identical event
2178 XtRemoveTimeOut(delayedEventTimerXID);
2179 delayedEventCallback = cb;
2180 delayedEventTimerXID =
2181 XtAppAddTimeOut(appContext, millisec,
2182 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2185 DelayedEventCallback
2188 if (delayedEventTimerXID) {
2189 return delayedEventCallback;
2196 CancelDelayedEvent ()
2198 if (delayedEventTimerXID) {
2199 XtRemoveTimeOut(delayedEventTimerXID);
2200 delayedEventTimerXID = 0;
2204 XtIntervalId loadGameTimerXID = 0;
2207 LoadGameTimerRunning ()
2209 return loadGameTimerXID != 0;
2213 StopLoadGameTimer ()
2215 if (loadGameTimerXID != 0) {
2216 XtRemoveTimeOut(loadGameTimerXID);
2217 loadGameTimerXID = 0;
2225 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2227 loadGameTimerXID = 0;
2232 StartLoadGameTimer (long millisec)
2235 XtAppAddTimeOut(appContext, millisec,
2236 (XtTimerCallbackProc) LoadGameTimerCallback,
2240 XtIntervalId analysisClockXID = 0;
2243 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2245 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2246 || appData.icsEngineAnalyze) { // [DM]
2247 AnalysisPeriodicEvent(0);
2248 StartAnalysisClock();
2253 StartAnalysisClock ()
2256 XtAppAddTimeOut(appContext, 2000,
2257 (XtTimerCallbackProc) AnalysisClockCallback,
2261 XtIntervalId clockTimerXID = 0;
2264 ClockTimerRunning ()
2266 return clockTimerXID != 0;
2272 if (clockTimerXID != 0) {
2273 XtRemoveTimeOut(clockTimerXID);
2282 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2289 StartClockTimer (long millisec)
2292 XtAppAddTimeOut(appContext, millisec,
2293 (XtTimerCallbackProc) ClockTimerCallback,
2298 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2302 Widget w = (Widget) opt->handle;
2304 /* check for low time warning */
2305 Pixel foregroundOrWarningColor = timerForegroundPixel;
2308 appData.lowTimeWarning &&
2309 (timer / 1000) < appData.icsAlarmTime)
2310 foregroundOrWarningColor = lowTimeWarningColor;
2312 if (appData.clockMode) {
2313 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2314 XtSetArg(args[0], XtNlabel, buf);
2316 snprintf(buf, MSG_SIZ, "%s ", color);
2317 XtSetArg(args[0], XtNlabel, buf);
2322 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2323 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2325 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2326 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2329 XtSetValues(w, args, 3);
2332 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2335 SetClockIcon (int color)
2338 Pixmap pm = *clockIcons[color];
2339 if (iconPixmap != pm) {
2341 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2342 XtSetValues(shellWidget, args, 1);
2346 #define INPUT_SOURCE_BUF_SIZE 8192
2355 char buf[INPUT_SOURCE_BUF_SIZE];
2360 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2362 InputSource *is = (InputSource *) closure;
2367 if (is->lineByLine) {
2368 count = read(is->fd, is->unused,
2369 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2371 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2374 is->unused += count;
2376 while (p < is->unused) {
2377 q = memchr(p, '\n', is->unused - p);
2378 if (q == NULL) break;
2380 (is->func)(is, is->closure, p, q - p, 0);
2384 while (p < is->unused) {
2389 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2394 (is->func)(is, is->closure, is->buf, count, error);
2399 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2402 ChildProc *cp = (ChildProc *) pr;
2404 is = (InputSource *) calloc(1, sizeof(InputSource));
2405 is->lineByLine = lineByLine;
2409 is->fd = fileno(stdin);
2411 is->kind = cp->kind;
2412 is->fd = cp->fdFrom;
2415 is->unused = is->buf;
2418 is->xid = XtAppAddInput(appContext, is->fd,
2419 (XtPointer) (XtInputReadMask),
2420 (XtInputCallbackProc) DoInputCallback,
2422 is->closure = closure;
2423 return (InputSourceRef) is;
2427 RemoveInputSource (InputSourceRef isr)
2429 InputSource *is = (InputSource *) isr;
2431 if (is->xid == 0) return;
2432 XtRemoveInput(is->xid);
2438 static Boolean frameWaiting;
2441 FrameAlarm (int sig)
2443 frameWaiting = False;
2444 /* In case System-V style signals. Needed?? */
2445 signal(SIGALRM, FrameAlarm);
2449 FrameDelay (int time)
2451 struct itimerval delay;
2453 XSync(xDisplay, False);
2456 frameWaiting = True;
2457 signal(SIGALRM, FrameAlarm);
2458 delay.it_interval.tv_sec =
2459 delay.it_value.tv_sec = time / 1000;
2460 delay.it_interval.tv_usec =
2461 delay.it_value.tv_usec = (time % 1000) * 1000;
2462 setitimer(ITIMER_REAL, &delay, NULL);
2463 while (frameWaiting) pause();
2464 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2465 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2466 setitimer(ITIMER_REAL, &delay, NULL);
2473 FrameDelay (int time)
2475 XSync(xDisplay, False);
2477 usleep(time * 1000);
2483 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2485 char buf[MSG_SIZ], *logoName = buf;
2486 if(appData.logo[n][0]) {
2487 logoName = appData.logo[n];
2488 } else if(appData.autoLogo) {
2489 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2490 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2491 } else if(appData.directory[n] && appData.directory[n][0]) {
2492 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2496 { ASSIGN(cps->programLogo, logoName); }
2500 UpdateLogos (int displ)
2502 if(optList[W_WHITE-1].handle == NULL) return;
2503 LoadLogo(&first, 0, 0);
2504 LoadLogo(&second, 1, appData.icsActive);
2505 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);