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 */
852 output[0] = strdup(""); // build keystrokes with and wo mod keys separately
853 output[1] = strdup(""); // so the more specific can preceed the other
855 /* loop over all menu entries */
856 for( i=0; menuBar[i-n].mi || !n++; i++)
858 mi = menuBar[i+n].mi; // kludge to access 'noMenu' behind sentinel
859 for(j=0; mi[j].proc; j++)
867 char *key,*test, *mods;
869 /* check for Ctrl/Alt */
870 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
871 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
872 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
874 /* remove all <...> */
875 test = strrchr(mi[j].accel, '>');
877 key = strdup(mi[j].accel);
879 key = strdup(++test); // remove ">"
881 /* instead of shift X11 uses the uppercase letter directly*/
882 if (shift && strlen(key)==1 )
884 *key = toupper(*key);
888 /* handle some special cases which have different names in X11 */
889 if ( strncmp(key, "Page_Down", 9) == 0 )
894 else if ( strncmp(key, "Page_Up", 7) == 0 )
900 /* create string of mods */
902 mods = strdup("Ctrl ");
908 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
909 strncat(mods, "Meta ", 5);
914 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
915 strncat(mods, "Shift ", 6);
918 // remove trailing space
919 if( isspace(mods[strlen(mods)-1]) )
920 mods[strlen(mods)-1]='\0';
922 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
923 char *name = malloc(MSG_SIZ);
924 if(n) snprintf(name, MSG_SIZ, "%s", mi[j].ref);
925 else snprintf(name, MSG_SIZ, "%s.%s", menuBar[i].ref, mi[j].ref);
927 char *buffer = malloc(MSG_SIZ);
928 snprintf(buffer, MSG_SIZ, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
930 /* add string to the output */
931 output[shift|alt|ctrl] = realloc(output[shift|alt|ctrl], strlen(output[shift|alt|ctrl]) + strlen(buffer)+1);
932 strncat(output[shift|alt|ctrl], buffer, strlen(buffer));
942 output[1] = realloc(output[1], strlen(output[1]) + strlen(output[0])+1);
943 strncat(output[1], output[0], strlen(output[0]));
954 ArgDescriptor *q, *p = argDescriptors+5;
955 printf("\nXBoard accepts the following options:\n"
956 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
957 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
958 " SIZE = board-size spec(s)\n"
959 " Within parentheses are short forms, or options to set to true or false.\n"
960 " Persistent options (saved in the settings file) are marked with *)\n\n");
962 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
963 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
964 if(p->save) strcat(buf+len, "*");
965 for(q=p+1; q->argLoc == p->argLoc; q++) {
966 if(q->argName[0] == '-') continue;
967 strcat(buf+len, q == p+1 ? " (" : " ");
968 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
970 if(q != p+1) strcat(buf+len, ")");
972 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
975 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
979 SlaveResize (Option *opt)
984 main (int argc, char **argv)
986 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
987 XSetWindowAttributes window_attributes;
989 Dimension boardWidth, boardHeight, w, h;
991 int forceMono = False;
993 srandom(time(0)); // [HGM] book: make random truly random
995 setbuf(stdout, NULL);
996 setbuf(stderr, NULL);
999 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1000 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1004 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1009 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1010 typedef struct {char *name, *value; } Config;
1011 static Config configList[] = {
1012 { "Datadir", DATADIR },
1013 { "Sysconfdir", SYSCONFDIR },
1018 for(i=0; configList[i].name; i++) {
1019 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1020 if(argc > 2) printf("%s", configList[i].value);
1021 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1026 programName = strrchr(argv[0], '/');
1027 if (programName == NULL)
1028 programName = argv[0];
1033 XtSetLanguageProc(NULL, NULL, NULL);
1034 if (appData.debugMode) {
1035 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1038 bindtextdomain(PACKAGE, LOCALEDIR);
1039 textdomain(PACKAGE);
1042 appData.boardSize = "";
1043 InitAppData(ConvertToLine(argc, argv));
1045 if (p == NULL) p = "/tmp";
1046 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1047 gameCopyFilename = (char*) malloc(i);
1048 gamePasteFilename = (char*) malloc(i);
1049 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1050 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1052 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1053 static char buf[MSG_SIZ];
1054 EscapeExpand(buf, appData.firstInitString);
1055 appData.firstInitString = strdup(buf);
1056 EscapeExpand(buf, appData.secondInitString);
1057 appData.secondInitString = strdup(buf);
1058 EscapeExpand(buf, appData.firstComputerString);
1059 appData.firstComputerString = strdup(buf);
1060 EscapeExpand(buf, appData.secondComputerString);
1061 appData.secondComputerString = strdup(buf);
1064 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1067 if (chdir(chessDir) != 0) {
1068 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1074 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1075 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1076 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1077 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1080 setbuf(debugFP, NULL);
1083 /* [HGM,HR] make sure board size is acceptable */
1084 if(appData.NrFiles > BOARD_FILES ||
1085 appData.NrRanks > BOARD_RANKS )
1086 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1089 /* This feature does not work; animation needs a rewrite */
1090 appData.highlightDragging = FALSE;
1094 gameInfo.variant = StringToVariant(appData.variant);
1095 InitPosition(FALSE);
1098 XtAppInitialize(&appContext, "XBoard", shellOptions,
1099 XtNumber(shellOptions),
1100 &argc, argv, xboardResources, NULL, 0);
1102 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1103 clientResources, XtNumber(clientResources),
1106 xDisplay = XtDisplay(shellWidget);
1107 xScreen = DefaultScreen(xDisplay);
1108 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1111 * determine size, based on supplied or remembered -size, or screen size
1113 if (isdigit(appData.boardSize[0])) {
1114 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1115 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1116 &fontPxlSize, &smallLayout, &tinyLayout);
1118 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1119 programName, appData.boardSize);
1123 squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
1125 /* Find some defaults; use the nearest known size */
1126 SizeDefaults *szd, *nearest;
1127 int distance = 99999;
1128 nearest = szd = sizeDefaults;
1129 while (szd->name != NULL) {
1130 if (abs(szd->squareSize - squareSize) < distance) {
1132 distance = abs(szd->squareSize - squareSize);
1133 if (distance == 0) break;
1137 if (i < 2) lineGap = nearest->lineGap;
1138 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1139 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1140 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1141 if (i < 6) smallLayout = nearest->smallLayout;
1142 if (i < 7) tinyLayout = nearest->tinyLayout;
1145 SizeDefaults *szd = sizeDefaults;
1146 if (*appData.boardSize == NULLCHAR) {
1147 while (DisplayWidth(xDisplay, xScreen) < (szd->minScreenSize*BOARD_WIDTH + 4)/8 ||
1148 DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
1151 if (szd->name == NULL) szd--;
1152 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1154 while (szd->name != NULL &&
1155 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1156 if (szd->name == NULL) {
1157 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1158 programName, appData.boardSize);
1162 squareSize = szd->squareSize;
1163 lineGap = szd->lineGap;
1164 clockFontPxlSize = szd->clockFontPxlSize;
1165 coordFontPxlSize = szd->coordFontPxlSize;
1166 fontPxlSize = szd->fontPxlSize;
1167 smallLayout = szd->smallLayout;
1168 tinyLayout = szd->tinyLayout;
1169 // [HGM] font: use defaults from settings file if available and not overruled
1172 defaultLineGap = lineGap;
1173 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1175 /* [HR] height treated separately (hacked) */
1176 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1177 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1180 * Determine what fonts to use.
1182 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1185 * Detect if there are not enough colors available and adapt.
1187 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1188 appData.monoMode = True;
1191 forceMono = MakeColors();
1194 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1196 appData.monoMode = True;
1199 if (appData.monoMode && appData.debugMode) {
1200 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1201 (unsigned long) XWhitePixel(xDisplay, xScreen),
1202 (unsigned long) XBlackPixel(xDisplay, xScreen));
1205 ParseIcsTextColors();
1207 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1213 layoutName = "tinyLayout";
1214 } else if (smallLayout) {
1215 layoutName = "smallLayout";
1217 layoutName = "normalLayout";
1220 optList = BoardPopUp(squareSize, lineGap, (void*)
1226 InitDrawingHandle(optList + W_BOARD);
1227 currBoard = &optList[W_BOARD];
1228 boardWidget = optList[W_BOARD].handle;
1229 menuBarWidget = optList[W_MENU].handle;
1230 dropMenu = optList[W_DROP].handle;
1231 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1232 formWidget = XtParent(boardWidget);
1233 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1234 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1235 XtGetValues(optList[W_WHITE].handle, args, 2);
1236 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1237 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1238 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1239 XtGetValues(optList[W_PAUSE].handle, args, 2);
1242 xBoardWindow = XtWindow(boardWidget);
1244 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1245 // not need to go into InitDrawingSizes().
1248 * Create X checkmark bitmap and initialize option menu checks.
1250 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1251 checkmark_bits, checkmark_width, checkmark_height);
1257 ReadBitmap(&wIconPixmap, "icon_white.bm",
1258 icon_white_bits, icon_white_width, icon_white_height);
1259 ReadBitmap(&bIconPixmap, "icon_black.bm",
1260 icon_black_bits, icon_black_width, icon_black_height);
1261 iconPixmap = wIconPixmap;
1263 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1264 XtSetValues(shellWidget, args, i);
1267 * Create a cursor for the board widget.
1269 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1270 XChangeWindowAttributes(xDisplay, xBoardWindow,
1271 CWCursor, &window_attributes);
1274 * Inhibit shell resizing.
1276 shellArgs[0].value = (XtArgVal) &w;
1277 shellArgs[1].value = (XtArgVal) &h;
1278 XtGetValues(shellWidget, shellArgs, 2);
1279 shellArgs[4].value = shellArgs[2].value = w;
1280 shellArgs[5].value = shellArgs[3].value = h;
1281 // XtSetValues(shellWidget, &shellArgs[2], 4);
1282 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1283 marginH = h - boardHeight;
1285 CatchDeleteWindow(shellWidget, "QuitProc");
1290 if(appData.logoSize)
1291 { // locate and read user logo
1293 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1294 ASSIGN(userLogo, buf);
1297 if (appData.animate || appData.animateDragging)
1301 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1303 XtAugmentTranslations(formWidget,
1304 XtParseTranslationTable(globalTranslations));
1305 XtAugmentTranslations(formWidget,
1306 XtParseTranslationTable(TranslationsTableMenus));
1308 XtAddEventHandler(formWidget, KeyPressMask, False,
1309 (XtEventHandler) MoveTypeInProc, NULL);
1310 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1311 (XtEventHandler) EventProc, NULL);
1313 /* [AS] Restore layout */
1314 if( wpMoveHistory.visible ) {
1318 if( wpEvalGraph.visible )
1323 if( wpEngineOutput.visible ) {
1324 EngineOutputPopUp();
1327 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1332 if (errorExitStatus == -1) {
1333 if (appData.icsActive) {
1334 /* We now wait until we see "login:" from the ICS before
1335 sending the logon script (problems with timestamp otherwise) */
1336 /*ICSInitScript();*/
1337 if (appData.icsInputBox) ICSInputBoxPopUp();
1341 signal(SIGWINCH, TermSizeSigHandler);
1343 signal(SIGINT, IntSigHandler);
1344 signal(SIGTERM, IntSigHandler);
1345 if (*appData.cmailGameName != NULLCHAR) {
1346 signal(SIGUSR1, CmailSigHandler);
1351 // XtSetKeyboardFocus(shellWidget, formWidget);
1352 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1354 XtAppMainLoop(appContext);
1355 if (appData.debugMode) fclose(debugFP); // [DM] debug
1363 while((m = XtAppPending(appContext))) XtAppProcessEvent(appContext, m);
1367 TermSizeSigHandler (int sig)
1373 IntSigHandler (int sig)
1379 CmailSigHandler (int sig)
1384 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1386 /* Activate call-back function CmailSigHandlerCallBack() */
1387 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1389 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1393 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1396 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1398 /**** end signal code ****/
1401 #define Abs(n) ((n)<0 ? -(n) : (n))
1405 InsertPxlSize (char *pattern, int targetPxlSize)
1407 char *base_fnt_lst, strInt[12], *p, *q;
1408 int alternatives, i, len, strIntLen;
1411 * Replace the "*" (if present) in the pixel-size slot of each
1412 * alternative with the targetPxlSize.
1416 while ((p = strchr(p, ',')) != NULL) {
1420 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1421 strIntLen = strlen(strInt);
1422 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1426 while (alternatives--) {
1427 char *comma = strchr(p, ',');
1428 for (i=0; i<14; i++) {
1429 char *hyphen = strchr(p, '-');
1431 if (comma && hyphen > comma) break;
1432 len = hyphen + 1 - p;
1433 if (i == 7 && *p == '*' && len == 2) {
1435 memcpy(q, strInt, strIntLen);
1445 len = comma + 1 - p;
1452 return base_fnt_lst;
1456 CreateFontSet (char *base_fnt_lst)
1459 char **missing_list;
1463 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1464 &missing_list, &missing_count, &def_string);
1465 if (appData.debugMode) {
1467 XFontStruct **font_struct_list;
1468 char **font_name_list;
1469 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1471 fprintf(debugFP, " got list %s, locale %s\n",
1472 XBaseFontNameListOfFontSet(fntSet),
1473 XLocaleOfFontSet(fntSet));
1474 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1475 for (i = 0; i < count; i++) {
1476 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1479 for (i = 0; i < missing_count; i++) {
1480 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1483 if (fntSet == NULL) {
1484 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1489 #else // not ENABLE_NLS
1491 * Find a font that matches "pattern" that is as close as
1492 * possible to the targetPxlSize. Prefer fonts that are k
1493 * pixels smaller to fonts that are k pixels larger. The
1494 * pattern must be in the X Consortium standard format,
1495 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1496 * The return value should be freed with XtFree when no
1500 FindFont (char *pattern, int targetPxlSize)
1502 char **fonts, *p, *best, *scalable, *scalableTail;
1503 int i, j, nfonts, minerr, err, pxlSize;
1505 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1507 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1508 programName, pattern);
1515 for (i=0; i<nfonts; i++) {
1518 if (*p != '-') continue;
1520 if (*p == NULLCHAR) break;
1521 if (*p++ == '-') j++;
1523 if (j < 7) continue;
1526 scalable = fonts[i];
1529 err = pxlSize - targetPxlSize;
1530 if (Abs(err) < Abs(minerr) ||
1531 (minerr > 0 && err < 0 && -err == minerr)) {
1537 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1538 /* If the error is too big and there is a scalable font,
1539 use the scalable font. */
1540 int headlen = scalableTail - scalable;
1541 p = (char *) XtMalloc(strlen(scalable) + 10);
1542 while (isdigit(*scalableTail)) scalableTail++;
1543 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1545 p = (char *) XtMalloc(strlen(best) + 2);
1546 safeStrCpy(p, best, strlen(best)+1 );
1548 if (appData.debugMode) {
1549 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1550 pattern, targetPxlSize, p);
1552 XFreeFontNames(fonts);
1558 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1561 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1567 MarkMenuItem (char *menuRef, int state)
1569 MenuItem *item = MenuNameToItem(menuRef);
1573 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1574 XtSetValues(item->handle, args, 1);
1579 EnableNamedMenuItem (char *menuRef, int state)
1581 MenuItem *item = MenuNameToItem(menuRef);
1583 if(item) XtSetSensitive(item->handle, state);
1587 EnableButtonBar (int state)
1589 XtSetSensitive(optList[W_BUTTON].handle, state);
1594 SetMenuEnables (Enables *enab)
1596 while (enab->name != NULL) {
1597 EnableNamedMenuItem(enab->name, enab->value);
1603 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1604 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1606 if(*nprms == 0) return;
1607 item = MenuNameToItem(prms[0]);
1608 if(item) ((MenuProc *) item->proc) ();
1620 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1621 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1622 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1623 dmEnables[i].piece);
1624 XtSetSensitive(entry, p != NULL || !appData.testLegality
1625 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1626 && !appData.icsActive));
1628 while (p && *p++ == dmEnables[i].piece) count++;
1629 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1631 XtSetArg(args[j], XtNlabel, label); j++;
1632 XtSetValues(entry, args, j);
1637 do_flash_delay (unsigned long msec)
1643 FlashDelay (int flash_delay)
1645 XSync(xDisplay, False);
1646 if(flash_delay) do_flash_delay(flash_delay);
1650 Fraction (int x, int start, int stop)
1652 double f = ((double) x - start)/(stop - start);
1653 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1657 static WindowPlacement wpNew;
1660 CoDrag (Widget sh, WindowPlacement *wp)
1663 int j=0, touch=0, fudge = 2;
1664 GetActualPlacement(sh, wp);
1665 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1666 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1667 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1668 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1669 if(!touch ) return; // only windows that touch co-move
1670 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1671 int heightInc = wpNew.height - wpMain.height;
1672 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1673 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1674 wp->y += fracTop * heightInc;
1675 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1676 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1677 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1678 int widthInc = wpNew.width - wpMain.width;
1679 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1680 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1681 wp->y += fracLeft * widthInc;
1682 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1683 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1685 wp->x += wpNew.x - wpMain.x;
1686 wp->y += wpNew.y - wpMain.y;
1687 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1688 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1689 XtSetArg(args[j], XtNx, wp->x); j++;
1690 XtSetArg(args[j], XtNy, wp->y); j++;
1691 XtSetValues(sh, args, j);
1695 ReSize (WindowPlacement *wp)
1698 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1699 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1700 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1701 if(sqy < sqx) sqx = sqy;
1702 if(sqx != squareSize) {
1703 squareSize = sqx; // adopt new square size
1704 CreatePNGPieces(); // make newly scaled pieces
1705 InitDrawingSizes(0, 0); // creates grid etc.
1706 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1707 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1708 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1709 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1710 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1713 static XtIntervalId delayedDragID = 0;
1722 GetActualPlacement(shellWidget, &wpNew);
1723 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1724 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1725 busy = 0; return; // false alarm
1728 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1729 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1730 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1731 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1733 DrawPosition(True, NULL);
1734 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1742 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1744 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1748 EventProc (Widget widget, caddr_t unused, XEvent *event)
1750 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1751 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1755 * event handler for redrawing the board
1758 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1760 DrawPosition(True, NULL);
1765 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1766 { // [HGM] pv: walk PV
1767 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1770 extern int savedIndex; /* gross that this is global */
1773 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1776 XawTextPosition index, dummy;
1779 XawTextGetSelectionPos(w, &index, &dummy);
1780 XtSetArg(arg, XtNstring, &val);
1781 XtGetValues(w, &arg, 1);
1782 ReplaceComment(savedIndex, val);
1783 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1784 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1788 /* Disable all user input other than deleting the window */
1789 static int frozen = 0;
1795 /* Grab by a widget that doesn't accept input */
1796 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1800 /* Undo a FreezeUI */
1804 if (!frozen) return;
1805 XtRemoveGrab(optList[W_MESSG].handle);
1813 static int oldPausing = FALSE;
1814 static GameMode oldmode = (GameMode) -1;
1817 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1819 if (pausing != oldPausing) {
1820 oldPausing = pausing;
1821 MarkMenuItem("Mode.Pause", pausing);
1823 if (appData.showButtonBar) {
1824 /* Always toggle, don't set. Previous code messes up when
1825 invoked while the button is pressed, as releasing it
1826 toggles the state again. */
1829 XtSetArg(args[0], XtNbackground, &oldbg);
1830 XtSetArg(args[1], XtNforeground, &oldfg);
1831 XtGetValues(optList[W_PAUSE].handle,
1833 XtSetArg(args[0], XtNbackground, oldfg);
1834 XtSetArg(args[1], XtNforeground, oldbg);
1836 XtSetValues(optList[W_PAUSE].handle, args, 2);
1840 wname = ModeToWidgetName(oldmode);
1841 if (wname != NULL) {
1842 MarkMenuItem(wname, False);
1844 wname = ModeToWidgetName(gameMode);
1845 if (wname != NULL) {
1846 MarkMenuItem(wname, True);
1849 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1851 /* Maybe all the enables should be handled here, not just this one */
1852 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1854 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1859 * Button/menu procedures
1862 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1863 char *selected_fen_position=NULL;
1866 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1867 Atom *type_return, XtPointer *value_return,
1868 unsigned long *length_return, int *format_return)
1870 char *selection_tmp;
1872 // if (!selected_fen_position) return False; /* should never happen */
1873 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1874 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1875 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1878 if (f == NULL) return False;
1882 selection_tmp = XtMalloc(len + 1);
1883 count = fread(selection_tmp, 1, len, f);
1886 XtFree(selection_tmp);
1889 selection_tmp[len] = NULLCHAR;
1891 /* note: since no XtSelectionDoneProc was registered, Xt will
1892 * automatically call XtFree on the value returned. So have to
1893 * make a copy of it allocated with XtMalloc */
1894 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1895 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1898 *value_return=selection_tmp;
1899 *length_return=strlen(selection_tmp);
1900 *type_return=*target;
1901 *format_return = 8; /* bits per byte */
1903 } else if (*target == XA_TARGETS(xDisplay)) {
1904 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1905 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1906 targets_tmp[1] = XA_STRING;
1907 *value_return = targets_tmp;
1908 *type_return = XA_ATOM;
1911 // This code leads to a read of value_return out of bounds on 64-bit systems.
1912 // Other code which I have seen always sets *format_return to 32 independent of
1913 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1914 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1915 *format_return = 8 * sizeof(Atom);
1916 if (*format_return > 32) {
1917 *length_return *= *format_return / 32;
1918 *format_return = 32;
1921 *format_return = 32;
1929 /* note: when called from menu all parameters are NULL, so no clue what the
1930 * Widget which was clicked on was, or what the click event was
1933 CopySomething (char *src)
1935 selected_fen_position = src;
1937 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1938 * have a notion of a position that is selected but not copied.
1939 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1941 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1943 SendPositionSelection,
1944 NULL/* lose_ownership_proc */ ,
1945 NULL/* transfer_done_proc */);
1946 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1948 SendPositionSelection,
1949 NULL/* lose_ownership_proc */ ,
1950 NULL/* transfer_done_proc */);
1953 /* function called when the data to Paste is ready */
1955 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1956 Atom *type, XtPointer value, unsigned long *len, int *format)
1959 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1960 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1961 EditPositionPasteFEN(fenstr);
1965 /* called when Paste Position button is pressed,
1966 * all parameters will be NULL */
1968 PastePositionProc ()
1970 XtGetSelectionValue(menuBarWidget,
1971 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1972 /* (XtSelectionCallbackProc) */ PastePositionCB,
1973 NULL, /* client_data passed to PastePositionCB */
1975 /* better to use the time field from the event that triggered the
1976 * call to this function, but that isn't trivial to get
1983 /* note: when called from menu all parameters are NULL, so no clue what the
1984 * Widget which was clicked on was, or what the click event was
1986 /* function called when the data to Paste is ready */
1988 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1989 Atom *type, XtPointer value, unsigned long *len, int *format)
1992 if (value == NULL || *len == 0) {
1993 return; /* nothing had been selected to copy */
1995 f = fopen(gamePasteFilename, "w");
1997 DisplayError(_("Can't open temp file"), errno);
2000 fwrite(value, 1, *len, f);
2003 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2006 /* called when Paste Game button is pressed,
2007 * all parameters will be NULL */
2011 XtGetSelectionValue(menuBarWidget,
2012 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2013 /* (XtSelectionCallbackProc) */ PasteGameCB,
2014 NULL, /* client_data passed to PasteGameCB */
2016 /* better to use the time field from the event that triggered the
2017 * call to this function, but that isn't trivial to get
2026 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2033 { // bassic primitive for determining if modifier keys are pressed
2034 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2037 XQueryKeymap(xDisplay,keys);
2038 for(i=0; i<6; i++) {
2040 j = XKeysymToKeycode(xDisplay, codes[i]);
2041 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2047 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2051 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2052 if ( n == 1 && *buf >= 32 // printable
2053 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2054 ) BoxAutoPopUp (buf);
2058 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2059 { // [HGM] input: let up-arrow recall previous line from history
2064 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2065 { // [HGM] input: let down-arrow recall next line from history
2070 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2076 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2078 if (!TempBackwardActive) {
2079 TempBackwardActive = True;
2085 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2087 /* Check to see if triggered by a key release event for a repeating key.
2088 * If so the next queued event will be a key press of the same key at the same time */
2089 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2091 XPeekEvent(xDisplay, &next);
2092 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2093 next.xkey.keycode == event->xkey.keycode)
2097 TempBackwardActive = False;
2101 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2102 { // called as key binding
2105 if (nprms && *nprms > 0)
2109 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2115 { // called from menu
2116 ManInner(NULL, NULL, NULL, NULL);
2120 SetWindowTitle (char *text, char *title, char *icon)
2124 if (appData.titleInWindow) {
2126 XtSetArg(args[i], XtNlabel, text); i++;
2127 XtSetValues(titleWidget, args, i);
2130 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2131 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2132 XtSetValues(shellWidget, args, i);
2133 XSync(xDisplay, False);
2138 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2144 DisplayIcsInteractionTitle (String message)
2146 if (oldICSInteractionTitle == NULL) {
2147 /* Magic to find the old window title, adapted from vim */
2148 char *wina = getenv("WINDOWID");
2150 Window win = (Window) atoi(wina);
2151 Window root, parent, *children;
2152 unsigned int nchildren;
2153 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2155 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2156 if (!XQueryTree(xDisplay, win, &root, &parent,
2157 &children, &nchildren)) break;
2158 if (children) XFree((void *)children);
2159 if (parent == root || parent == 0) break;
2162 XSetErrorHandler(oldHandler);
2164 if (oldICSInteractionTitle == NULL) {
2165 oldICSInteractionTitle = "xterm";
2168 printf("\033]0;%s\007", message);
2173 XtIntervalId delayedEventTimerXID = 0;
2174 DelayedEventCallback delayedEventCallback = 0;
2179 delayedEventTimerXID = 0;
2180 delayedEventCallback();
2184 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2186 if(delayedEventTimerXID && delayedEventCallback == cb)
2187 // [HGM] alive: replace, rather than add or flush identical event
2188 XtRemoveTimeOut(delayedEventTimerXID);
2189 delayedEventCallback = cb;
2190 delayedEventTimerXID =
2191 XtAppAddTimeOut(appContext, millisec,
2192 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2195 DelayedEventCallback
2198 if (delayedEventTimerXID) {
2199 return delayedEventCallback;
2206 CancelDelayedEvent ()
2208 if (delayedEventTimerXID) {
2209 XtRemoveTimeOut(delayedEventTimerXID);
2210 delayedEventTimerXID = 0;
2214 XtIntervalId loadGameTimerXID = 0;
2217 LoadGameTimerRunning ()
2219 return loadGameTimerXID != 0;
2223 StopLoadGameTimer ()
2225 if (loadGameTimerXID != 0) {
2226 XtRemoveTimeOut(loadGameTimerXID);
2227 loadGameTimerXID = 0;
2235 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2237 loadGameTimerXID = 0;
2242 StartLoadGameTimer (long millisec)
2245 XtAppAddTimeOut(appContext, millisec,
2246 (XtTimerCallbackProc) LoadGameTimerCallback,
2250 XtIntervalId analysisClockXID = 0;
2253 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2255 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2256 || appData.icsEngineAnalyze) { // [DM]
2257 AnalysisPeriodicEvent(0);
2258 StartAnalysisClock();
2263 StartAnalysisClock ()
2266 XtAppAddTimeOut(appContext, 2000,
2267 (XtTimerCallbackProc) AnalysisClockCallback,
2271 XtIntervalId clockTimerXID = 0;
2274 ClockTimerRunning ()
2276 return clockTimerXID != 0;
2282 if (clockTimerXID != 0) {
2283 XtRemoveTimeOut(clockTimerXID);
2292 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2299 StartClockTimer (long millisec)
2302 XtAppAddTimeOut(appContext, millisec,
2303 (XtTimerCallbackProc) ClockTimerCallback,
2308 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2312 Widget w = (Widget) opt->handle;
2314 /* check for low time warning */
2315 Pixel foregroundOrWarningColor = timerForegroundPixel;
2318 appData.lowTimeWarning &&
2319 (timer / 1000) < appData.icsAlarmTime)
2320 foregroundOrWarningColor = lowTimeWarningColor;
2322 if (appData.clockMode) {
2323 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2324 XtSetArg(args[0], XtNlabel, buf);
2326 snprintf(buf, MSG_SIZ, "%s ", color);
2327 XtSetArg(args[0], XtNlabel, buf);
2332 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2333 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2335 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2336 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2339 XtSetValues(w, args, 3);
2342 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2345 SetClockIcon (int color)
2348 Pixmap pm = *clockIcons[color];
2349 if (iconPixmap != pm) {
2351 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2352 XtSetValues(shellWidget, args, 1);
2356 #define INPUT_SOURCE_BUF_SIZE 8192
2365 char buf[INPUT_SOURCE_BUF_SIZE];
2370 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2372 InputSource *is = (InputSource *) closure;
2377 if (is->lineByLine) {
2378 count = read(is->fd, is->unused,
2379 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2381 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2384 is->unused += count;
2386 while (p < is->unused) {
2387 q = memchr(p, '\n', is->unused - p);
2388 if (q == NULL) break;
2390 (is->func)(is, is->closure, p, q - p, 0);
2394 while (p < is->unused) {
2399 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2404 (is->func)(is, is->closure, is->buf, count, error);
2409 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2412 ChildProc *cp = (ChildProc *) pr;
2414 is = (InputSource *) calloc(1, sizeof(InputSource));
2415 is->lineByLine = lineByLine;
2419 is->fd = fileno(stdin);
2421 is->kind = cp->kind;
2422 is->fd = cp->fdFrom;
2425 is->unused = is->buf;
2428 is->xid = XtAppAddInput(appContext, is->fd,
2429 (XtPointer) (XtInputReadMask),
2430 (XtInputCallbackProc) DoInputCallback,
2432 is->closure = closure;
2433 return (InputSourceRef) is;
2437 RemoveInputSource (InputSourceRef isr)
2439 InputSource *is = (InputSource *) isr;
2441 if (is->xid == 0) return;
2442 XtRemoveInput(is->xid);
2448 static Boolean frameWaiting;
2451 FrameAlarm (int sig)
2453 frameWaiting = False;
2454 /* In case System-V style signals. Needed?? */
2455 signal(SIGALRM, FrameAlarm);
2459 FrameDelay (int time)
2461 struct itimerval delay;
2463 XSync(xDisplay, False);
2466 frameWaiting = True;
2467 signal(SIGALRM, FrameAlarm);
2468 delay.it_interval.tv_sec =
2469 delay.it_value.tv_sec = time / 1000;
2470 delay.it_interval.tv_usec =
2471 delay.it_value.tv_usec = (time % 1000) * 1000;
2472 setitimer(ITIMER_REAL, &delay, NULL);
2473 while (frameWaiting) pause();
2474 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2475 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2476 setitimer(ITIMER_REAL, &delay, NULL);
2483 FrameDelay (int time)
2485 XSync(xDisplay, False);
2487 usleep(time * 1000);
2493 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2495 char buf[MSG_SIZ], *logoName = buf;
2496 if(appData.logo[n][0]) {
2497 logoName = appData.logo[n];
2498 } else if(appData.autoLogo) {
2499 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2500 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2501 } else if(appData.directory[n] && appData.directory[n][0]) {
2502 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2506 { ASSIGN(cps->programLogo, logoName); }
2510 UpdateLogos (int displ)
2512 if(optList[W_WHITE-1].handle == NULL) return;
2513 LoadLogo(&first, 0, 0);
2514 LoadLogo(&second, 1, appData.icsActive);
2515 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);