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 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.
188 #define IMAGE_EXT "xpm"
190 #define IMAGE_EXT "xim"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
208 #include "engineoutput.h"
218 #define usleep(t) _sleep2(((t)+500)/1000)
222 # define _(s) gettext (s)
223 # define N_(s) gettext_noop (s)
229 int main P((int argc, char **argv));
230 RETSIGTYPE CmailSigHandler P((int sig));
231 RETSIGTYPE IntSigHandler P((int sig));
232 RETSIGTYPE TermSizeSigHandler P((int sig));
233 Widget CreateMenuBar P((Menu *mb, int boardWidth));
235 char *InsertPxlSize P((char *pattern, int targetPxlSize));
236 XFontSet CreateFontSet P((char *base_fnt_lst));
238 char *FindFont P((char *pattern, int targetPxlSize));
240 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
241 u_int wreq, u_int hreq));
242 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
243 void DelayedDrag P((void));
244 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
245 void HandlePV P((Widget w, XEvent * event,
246 String * params, Cardinal * nParams));
247 void DrawPositionProc P((Widget w, XEvent *event,
248 String *prms, Cardinal *nprms));
249 void CommentClick P((Widget w, XEvent * event,
250 String * params, Cardinal * nParams));
251 void ICSInputBoxPopUp P((void));
252 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
253 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
254 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
255 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
257 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
258 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
259 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
260 Boolean TempBackwardActive = False;
261 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
262 void DisplayMove P((int moveNumber));
263 void update_ics_width P(());
264 int CopyMemoProc P(());
267 * XBoard depends on Xt R4 or higher
269 int xtVersion = XtSpecificationRelease;
274 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
275 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
276 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
277 Option *optList; // contains all widgets of main window
279 XFontSet fontSet, clockFontSet;
282 XFontStruct *clockFontStruct;
284 Font coordFontID, countFontID;
285 XFontStruct *coordFontStruct, *countFontStruct;
286 XtAppContext appContext;
289 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
291 Position commentX = -1, commentY = -1;
292 Dimension commentW, commentH;
293 typedef unsigned int BoardSize;
295 Boolean chessProgram;
297 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
298 int smallLayout = 0, tinyLayout = 0,
299 marginW, marginH, // [HGM] for run-time resizing
300 fromX = -1, fromY = -1, toX, toY, commentUp = False,
301 errorExitStatus = -1, defaultLineGap;
302 Dimension textHeight;
303 Pixel timerForegroundPixel, timerBackgroundPixel;
304 Pixel buttonForegroundPixel, buttonBackgroundPixel;
305 char *chessDir, *programName, *programVersion;
306 Boolean alwaysOnTop = False;
307 char *icsTextMenuString;
309 char *firstChessProgramNames;
310 char *secondChessProgramNames;
312 WindowPlacement wpMain;
313 WindowPlacement wpConsole;
314 WindowPlacement wpComment;
315 WindowPlacement wpMoveHistory;
316 WindowPlacement wpEvalGraph;
317 WindowPlacement wpEngineOutput;
318 WindowPlacement wpGameList;
319 WindowPlacement wpTags;
320 WindowPlacement wpDualBoard;
323 /* This magic number is the number of intermediate frames used
324 in each half of the animation. For short moves it's reduced
325 by 1. The total number of frames will be factor * 2 + 1. */
328 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
335 DropMenuEnables dmEnables[] = {
352 XtResource clientResources[] = {
353 { "flashCount", "flashCount", XtRInt, sizeof(int),
354 XtOffset(AppDataPtr, flashCount), XtRImmediate,
355 (XtPointer) FLASH_COUNT },
358 XrmOptionDescRec shellOptions[] = {
359 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
360 { "-flash", "flashCount", XrmoptionNoArg, "3" },
361 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
364 XtActionsRec boardActions[] = {
365 { "DrawPosition", DrawPositionProc },
366 { "HandlePV", HandlePV },
367 { "SelectPV", SelectPV },
368 { "StopPV", StopPV },
369 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
370 { "QuitProc", QuitWrapper },
371 { "ManProc", ManInner },
372 { "TempBackwardProc", TempBackwardProc },
373 { "TempForwardProc", TempForwardProc },
374 { "CommentClick", (XtActionProc) CommentClick },
375 { "GenericPopDown", (XtActionProc) GenericPopDown },
376 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
377 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
378 { "SelectMove", (XtActionProc) SelectMoveX },
379 { "LoadSelectedProc", LoadSelectedProc },
380 { "SetFilterProc", SetFilterProc },
381 { "TypeInProc", TypeInProc },
382 { "EnterKeyProc", EnterKeyProc },
383 { "UpKeyProc", UpKeyProc },
384 { "DownKeyProc", DownKeyProc },
385 { "WheelProc", WheelProc },
386 { "TabProc", TabProc },
389 char globalTranslations[] =
390 ":Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
391 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
392 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
393 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
394 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
395 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
396 :<Key>Pause: MenuItem(Mode.Pause) \n \
397 :Ctrl<Key>d: MenuItem(DebugProc) \n \
398 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
399 :<Key>Left: MenuItem(Edit.Backward) \n \
400 :<Key>Right: MenuItem(Edit.Forward) \n \
401 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
402 #ifndef OPTIONSDIALOG
404 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
405 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
406 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
407 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
408 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
411 :<KeyDown>Return: TempBackwardProc() \n \
412 :<KeyUp>Return: TempForwardProc() \n";
414 char ICSInputTranslations[] =
415 "<Key>Up: UpKeyProc() \n "
416 "<Key>Down: DownKeyProc() \n "
417 "<Key>Return: EnterKeyProc() \n";
419 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
420 // as the widget is destroyed before the up-click can call extend-end
421 char commentTranslations[] = "<Btn3Down>: extend-end(PRIMARY) select-start() CommentClick() \n";
423 String xboardResources[] = {
424 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
429 /* Max possible square size */
430 #define MAXSQSIZE 256
432 static int xpm_avail[MAXSQSIZE];
434 #ifdef HAVE_DIR_STRUCT
436 /* Extract piece size from filename */
438 xpm_getsize (char *name, int len, char *ext)
446 if ((p=strchr(name, '.')) == NULL ||
447 StrCaseCmp(p+1, ext) != 0)
453 while (*p && isdigit(*p))
460 /* Setup xpm_avail */
462 xpm_getavail (char *dirname, char *ext)
468 for (i=0; i<MAXSQSIZE; ++i)
471 if (appData.debugMode)
472 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
474 dir = opendir(dirname);
477 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
478 programName, dirname);
482 while ((ent=readdir(dir)) != NULL) {
483 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
484 if (i > 0 && i < MAXSQSIZE)
494 xpm_print_avail (FILE *fp, char *ext)
498 fprintf(fp, _("Available '%s' sizes:\n"), ext);
499 for (i=1; i<MAXSQSIZE; ++i) {
505 /* Return XPM piecesize closest to size */
507 xpm_closest_to (char *dirname, int size, char *ext)
510 int sm_diff = MAXSQSIZE;
514 xpm_getavail(dirname, ext);
516 if (appData.debugMode)
517 xpm_print_avail(stderr, ext);
519 for (i=1; i<MAXSQSIZE; ++i) {
522 diff = (diff<0) ? -diff : diff;
523 if (diff < sm_diff) {
531 fprintf(stderr, _("Error: No '%s' files!\n"), ext);
537 #else /* !HAVE_DIR_STRUCT */
538 /* If we are on a system without a DIR struct, we can't
539 read the directory, so we can't collect a list of
540 filenames, etc., so we can't do any size-fitting. */
542 xpm_closest_to (char *dirname, int size, char *ext)
545 Warning: No DIR structure found on this system --\n\
546 Unable to autosize for XPM/XIM pieces.\n\
547 Please report this error to %s.\n\
548 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
551 #endif /* HAVE_DIR_STRUCT */
554 /* Arrange to catch delete-window events */
555 Atom wm_delete_window;
557 CatchDeleteWindow (Widget w, String procname)
560 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
561 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
562 XtAugmentTranslations(w, XtParseTranslationTable(buf));
569 XtSetArg(args[0], XtNiconic, False);
570 XtSetValues(shellWidget, args, 1);
572 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
575 //---------------------------------------------------------------------------------------------------------
576 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
579 #define CW_USEDEFAULT (1<<31)
580 #define ICS_TEXT_MENU_SIZE 90
581 #define DEBUG_FILE "xboard.debug"
582 #define SetCurrentDirectory chdir
583 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
587 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
590 // front-end part of option handling
592 // [HGM] This platform-dependent table provides the location for storing the color info
593 extern char *crWhite, * crBlack;
597 &appData.whitePieceColor,
598 &appData.blackPieceColor,
599 &appData.lightSquareColor,
600 &appData.darkSquareColor,
601 &appData.highlightSquareColor,
602 &appData.premoveHighlightColor,
603 &appData.lowTimeWarningColor,
614 // [HGM] font: keep a font for each square size, even non-stndard ones
617 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
618 char *fontTable[NUM_FONTS][MAX_SIZE];
621 ParseFont (char *name, int number)
622 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
624 if(sscanf(name, "size%d:", &size)) {
625 // [HGM] font: font is meant for specific boardSize (likely from settings file);
626 // defer processing it until we know if it matches our board size
627 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
628 fontTable[number][size] = strdup(strchr(name, ':')+1);
629 fontValid[number][size] = True;
634 case 0: // CLOCK_FONT
635 appData.clockFont = strdup(name);
637 case 1: // MESSAGE_FONT
638 appData.font = strdup(name);
640 case 2: // COORD_FONT
641 appData.coordFont = strdup(name);
646 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
651 { // only 2 fonts currently
652 appData.clockFont = CLOCK_FONT_NAME;
653 appData.coordFont = COORD_FONT_NAME;
654 appData.font = DEFAULT_FONT_NAME;
659 { // no-op, until we identify the code for this already in XBoard and move it here
663 ParseColor (int n, char *name)
664 { // in XBoard, just copy the color-name string
665 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
669 ParseTextAttribs (ColorClass cc, char *s)
671 (&appData.colorShout)[cc] = strdup(s);
675 ParseBoardSize (void *addr, char *name)
677 appData.boardSize = strdup(name);
682 { // In XBoard the sound-playing program takes care of obtaining the actual sound
686 SetCommPortDefaults ()
687 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
690 // [HGM] args: these three cases taken out to stay in front-end
692 SaveFontArg (FILE *f, ArgDescriptor *ad)
695 int i, n = (int)(intptr_t)ad->argLoc;
697 case 0: // CLOCK_FONT
698 name = appData.clockFont;
700 case 1: // MESSAGE_FONT
703 case 2: // COORD_FONT
704 name = appData.coordFont;
709 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
710 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
711 fontTable[n][squareSize] = strdup(name);
712 fontValid[n][squareSize] = True;
715 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
716 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
721 { // nothing to do, as the sounds are at all times represented by their text-string names already
725 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
726 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
727 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
731 SaveColor (FILE *f, ArgDescriptor *ad)
732 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
733 if(colorVariable[(int)(intptr_t)ad->argLoc])
734 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
738 SaveBoardSize (FILE *f, char *name, void *addr)
739 { // wrapper to shield back-end from BoardSize & sizeInfo
740 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
744 ParseCommPortSettings (char *s)
745 { // no such option in XBoard (yet)
751 GetActualPlacement (Widget wg, WindowPlacement *wp)
753 XWindowAttributes winAt;
760 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
761 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
762 wp->x = rx - winAt.x;
763 wp->y = ry - winAt.y;
764 wp->height = winAt.height;
765 wp->width = winAt.width;
766 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
771 { // wrapper to shield use of window handles from back-end (make addressible by number?)
772 // In XBoard this will have to wait until awareness of window parameters is implemented
773 GetActualPlacement(shellWidget, &wpMain);
774 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
775 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
776 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
777 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
778 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
779 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
783 PrintCommPortSettings (FILE *f, char *name)
784 { // This option does not exist in XBoard
788 EnsureOnScreen (int *x, int *y, int minX, int minY)
795 { // [HGM] args: allows testing if main window is realized from back-end
796 return xBoardWindow != 0;
800 PopUpStartupDialog ()
801 { // start menu not implemented in XBoard
805 ConvertToLine (int argc, char **argv)
807 static char line[128*1024], buf[1024];
811 for(i=1; i<argc; i++)
813 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
814 && argv[i][0] != '{' )
815 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
817 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
818 strncat(line, buf, 128*1024 - strlen(line) - 1 );
821 line[strlen(line)-1] = NULLCHAR;
825 //--------------------------------------------------------------------------------------------
828 ResizeBoardWindow (int w, int h, int inhibit)
830 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
832 shellArgs[0].value = w;
833 shellArgs[1].value = h;
834 shellArgs[4].value = shellArgs[2].value = w;
835 shellArgs[5].value = shellArgs[3].value = h;
836 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
838 XSync(xDisplay, False);
842 MakeOneColor (char *name, Pixel *color)
845 if (!appData.monoMode) {
846 vFrom.addr = (caddr_t) name;
847 vFrom.size = strlen(name);
848 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
849 if (vTo.addr == NULL) {
850 appData.monoMode = True;
853 *color = *(Pixel *) vTo.addr;
861 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
862 int forceMono = False;
864 if (appData.lowTimeWarning)
865 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
866 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
867 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
873 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
874 { // detervtomine what fonts to use, and create them
878 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
879 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
880 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
881 appData.font = fontTable[MESSAGE_FONT][squareSize];
882 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
883 appData.coordFont = fontTable[COORD_FONT][squareSize];
886 appData.font = InsertPxlSize(appData.font, fontPxlSize);
887 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
888 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
889 fontSet = CreateFontSet(appData.font);
890 clockFontSet = CreateFontSet(appData.clockFont);
892 /* For the coordFont, use the 0th font of the fontset. */
893 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
894 XFontStruct **font_struct_list;
895 XFontSetExtents *fontSize;
896 char **font_name_list;
897 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
898 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
899 coordFontStruct = XQueryFont(xDisplay, coordFontID);
900 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
901 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
904 appData.font = FindFont(appData.font, fontPxlSize);
905 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
906 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
907 clockFontID = XLoadFont(xDisplay, appData.clockFont);
908 clockFontStruct = XQueryFont(xDisplay, clockFontID);
909 coordFontID = XLoadFont(xDisplay, appData.coordFont);
910 coordFontStruct = XQueryFont(xDisplay, coordFontID);
911 // textHeight in !NLS mode!
913 countFontID = coordFontID; // [HGM] holdings
914 countFontStruct = coordFontStruct;
916 xdb = XtDatabase(xDisplay);
918 XrmPutLineResource(&xdb, "*international: True");
919 vTo.size = sizeof(XFontSet);
920 vTo.addr = (XtPointer) &fontSet;
921 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
923 XrmPutStringResource(&xdb, "*font", appData.font);
933 case ArgInt: p = " N"; break;
934 case ArgString: p = " STR"; break;
935 case ArgBoolean: p = " TF"; break;
936 case ArgSettingsFilename:
937 case ArgBackupSettingsFile:
938 case ArgFilename: p = " FILE"; break;
939 case ArgX: p = " Nx"; break;
940 case ArgY: p = " Ny"; break;
941 case ArgAttribs: p = " TEXTCOL"; break;
942 case ArgColor: p = " COL"; break;
943 case ArgFont: p = " FONT"; break;
944 case ArgBoardSize: p = " SIZE"; break;
945 case ArgFloat: p = " FLOAT"; break;
950 case ArgCommSettings:
957 GenerateGlobalTranslationTable (void)
959 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
967 /* loop over all menu entries */
968 for( i=0; menuBar[i].mi ; i++)
971 for(j=0; mi[j].proc; j++)
979 char *key,*test, *mods;
981 /* check for Ctrl/Alt */
982 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
983 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
984 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
986 /* remove all <...> */
987 test = strrchr(mi[j].accel, '>');
989 key = strdup(mi[j].accel);
991 key = strdup(++test); // remove ">"
993 /* instead of shift X11 uses the uppercase letter directly*/
994 if (shift && strlen(key)==1 )
996 *key = toupper(*key);
1000 /* handle some special cases which have different names in X11 */
1001 if ( strncmp(key, "Page_Down", 9) == 0 )
1006 else if ( strncmp(key, "Page_Up", 7) == 0 )
1009 key=strdup("Prior");
1012 /* create string of mods */
1014 mods = strdup("Ctrl ");
1020 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
1021 strncat(mods, "Meta ", 5);
1026 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
1027 strncat(mods, "Shift ", 6);
1030 // remove trailing space
1031 if( isspace(mods[strlen(mods)-1]) )
1032 mods[strlen(mods)-1]='\0';
1034 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
1035 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
1036 char *name = malloc(namesize+1);
1037 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
1039 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
1040 char *buffer = malloc(buffersize+1);
1041 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
1043 /* add string to the output */
1044 output = realloc(output, strlen(output) + strlen(buffer)+1);
1045 strncat(output, buffer, strlen(buffer));
1064 ArgDescriptor *q, *p = argDescriptors+5;
1065 printf("\nXBoard accepts the following options:\n"
1066 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1067 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1068 " SIZE = board-size spec(s)\n"
1069 " Within parentheses are short forms, or options to set to true or false.\n"
1070 " Persistent options (saved in the settings file) are marked with *)\n\n");
1072 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1073 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1074 if(p->save) strcat(buf+len, "*");
1075 for(q=p+1; q->argLoc == p->argLoc; q++) {
1076 if(q->argName[0] == '-') continue;
1077 strcat(buf+len, q == p+1 ? " (" : " ");
1078 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1080 if(q != p+1) strcat(buf+len, ")");
1082 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1085 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1089 SlaveResize (Option *opt)
1094 main (int argc, char **argv)
1096 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1097 XSetWindowAttributes window_attributes;
1099 Dimension boardWidth, boardHeight, w, h;
1101 int forceMono = False;
1103 srandom(time(0)); // [HGM] book: make random truly random
1105 setbuf(stdout, NULL);
1106 setbuf(stderr, NULL);
1109 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1110 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1114 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1119 programName = strrchr(argv[0], '/');
1120 if (programName == NULL)
1121 programName = argv[0];
1126 XtSetLanguageProc(NULL, NULL, NULL);
1127 if (appData.debugMode) {
1128 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1131 bindtextdomain(PACKAGE, LOCALEDIR);
1132 textdomain(PACKAGE);
1135 appData.boardSize = "";
1136 InitAppData(ConvertToLine(argc, argv));
1138 if (p == NULL) p = "/tmp";
1139 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1140 gameCopyFilename = (char*) malloc(i);
1141 gamePasteFilename = (char*) malloc(i);
1142 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1143 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1145 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1146 static char buf[MSG_SIZ];
1147 EscapeExpand(buf, appData.firstInitString);
1148 appData.firstInitString = strdup(buf);
1149 EscapeExpand(buf, appData.secondInitString);
1150 appData.secondInitString = strdup(buf);
1151 EscapeExpand(buf, appData.firstComputerString);
1152 appData.firstComputerString = strdup(buf);
1153 EscapeExpand(buf, appData.secondComputerString);
1154 appData.secondComputerString = strdup(buf);
1157 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1160 if (chdir(chessDir) != 0) {
1161 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1167 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1168 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1169 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1170 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1173 setbuf(debugFP, NULL);
1176 /* [HGM,HR] make sure board size is acceptable */
1177 if(appData.NrFiles > BOARD_FILES ||
1178 appData.NrRanks > BOARD_RANKS )
1179 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1182 /* This feature does not work; animation needs a rewrite */
1183 appData.highlightDragging = FALSE;
1187 gameInfo.variant = StringToVariant(appData.variant);
1188 InitPosition(FALSE);
1191 XtAppInitialize(&appContext, "XBoard", shellOptions,
1192 XtNumber(shellOptions),
1193 &argc, argv, xboardResources, NULL, 0);
1195 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1196 clientResources, XtNumber(clientResources),
1199 xDisplay = XtDisplay(shellWidget);
1200 xScreen = DefaultScreen(xDisplay);
1201 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1204 * determine size, based on supplied or remembered -size, or screen size
1206 if (isdigit(appData.boardSize[0])) {
1207 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1208 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1209 &fontPxlSize, &smallLayout, &tinyLayout);
1211 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1212 programName, appData.boardSize);
1216 /* Find some defaults; use the nearest known size */
1217 SizeDefaults *szd, *nearest;
1218 int distance = 99999;
1219 nearest = szd = sizeDefaults;
1220 while (szd->name != NULL) {
1221 if (abs(szd->squareSize - squareSize) < distance) {
1223 distance = abs(szd->squareSize - squareSize);
1224 if (distance == 0) break;
1228 if (i < 2) lineGap = nearest->lineGap;
1229 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1230 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1231 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1232 if (i < 6) smallLayout = nearest->smallLayout;
1233 if (i < 7) tinyLayout = nearest->tinyLayout;
1236 SizeDefaults *szd = sizeDefaults;
1237 if (*appData.boardSize == NULLCHAR) {
1238 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1239 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1242 if (szd->name == NULL) szd--;
1243 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1245 while (szd->name != NULL &&
1246 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1247 if (szd->name == NULL) {
1248 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1249 programName, appData.boardSize);
1253 squareSize = szd->squareSize;
1254 lineGap = szd->lineGap;
1255 clockFontPxlSize = szd->clockFontPxlSize;
1256 coordFontPxlSize = szd->coordFontPxlSize;
1257 fontPxlSize = szd->fontPxlSize;
1258 smallLayout = szd->smallLayout;
1259 tinyLayout = szd->tinyLayout;
1260 // [HGM] font: use defaults from settings file if available and not overruled
1263 defaultLineGap = lineGap;
1264 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1266 /* [HR] height treated separately (hacked) */
1267 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1268 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1271 * Determine what fonts to use.
1273 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1276 * Detect if there are not enough colors available and adapt.
1278 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1279 appData.monoMode = True;
1282 forceMono = MakeColors();
1285 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1287 appData.monoMode = True;
1290 if (appData.monoMode && appData.debugMode) {
1291 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1292 (unsigned long) XWhitePixel(xDisplay, xScreen),
1293 (unsigned long) XBlackPixel(xDisplay, xScreen));
1296 ParseIcsTextColors();
1298 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1304 layoutName = "tinyLayout";
1305 } else if (smallLayout) {
1306 layoutName = "smallLayout";
1308 layoutName = "normalLayout";
1311 optList = BoardPopUp(squareSize, lineGap, (void*)
1317 InitDrawingHandle(optList + W_BOARD);
1318 currBoard = &optList[W_BOARD];
1319 boardWidget = optList[W_BOARD].handle;
1320 menuBarWidget = optList[W_MENU].handle;
1321 dropMenu = optList[W_DROP].handle;
1322 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1323 formWidget = XtParent(boardWidget);
1324 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1325 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1326 XtGetValues(optList[W_WHITE].handle, args, 2);
1327 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1328 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1329 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1330 XtGetValues(optList[W_PAUSE].handle, args, 2);
1333 xBoardWindow = XtWindow(boardWidget);
1335 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1336 // not need to go into InitDrawingSizes().
1339 * Create X checkmark bitmap and initialize option menu checks.
1341 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1342 checkmark_bits, checkmark_width, checkmark_height);
1348 ReadBitmap(&wIconPixmap, "icon_white.bm",
1349 icon_white_bits, icon_white_width, icon_white_height);
1350 ReadBitmap(&bIconPixmap, "icon_black.bm",
1351 icon_black_bits, icon_black_width, icon_black_height);
1352 iconPixmap = wIconPixmap;
1354 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1355 XtSetValues(shellWidget, args, i);
1358 * Create a cursor for the board widget.
1360 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1361 XChangeWindowAttributes(xDisplay, xBoardWindow,
1362 CWCursor, &window_attributes);
1365 * Inhibit shell resizing.
1367 shellArgs[0].value = (XtArgVal) &w;
1368 shellArgs[1].value = (XtArgVal) &h;
1369 XtGetValues(shellWidget, shellArgs, 2);
1370 shellArgs[4].value = shellArgs[2].value = w;
1371 shellArgs[5].value = shellArgs[3].value = h;
1372 // XtSetValues(shellWidget, &shellArgs[2], 4);
1373 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1374 marginH = h - boardHeight;
1376 CatchDeleteWindow(shellWidget, "QuitProc");
1381 if(appData.logoSize)
1382 { // locate and read user logo
1384 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1385 ASSIGN(userLogo, buf);
1388 if (appData.animate || appData.animateDragging)
1392 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1394 XtAugmentTranslations(formWidget,
1395 XtParseTranslationTable(globalTranslations));
1396 XtAugmentTranslations(formWidget,
1397 XtParseTranslationTable(TranslationsTableMenus));
1399 XtAddEventHandler(formWidget, KeyPressMask, False,
1400 (XtEventHandler) MoveTypeInProc, NULL);
1401 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1402 (XtEventHandler) EventProc, NULL);
1404 /* [AS] Restore layout */
1405 if( wpMoveHistory.visible ) {
1409 if( wpEvalGraph.visible )
1414 if( wpEngineOutput.visible ) {
1415 EngineOutputPopUp();
1420 if (errorExitStatus == -1) {
1421 if (appData.icsActive) {
1422 /* We now wait until we see "login:" from the ICS before
1423 sending the logon script (problems with timestamp otherwise) */
1424 /*ICSInitScript();*/
1425 if (appData.icsInputBox) ICSInputBoxPopUp();
1429 signal(SIGWINCH, TermSizeSigHandler);
1431 signal(SIGINT, IntSigHandler);
1432 signal(SIGTERM, IntSigHandler);
1433 if (*appData.cmailGameName != NULLCHAR) {
1434 signal(SIGUSR1, CmailSigHandler);
1438 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1441 // XtSetKeyboardFocus(shellWidget, formWidget);
1442 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1444 XtAppMainLoop(appContext);
1445 if (appData.debugMode) fclose(debugFP); // [DM] debug
1450 TermSizeSigHandler (int sig)
1456 IntSigHandler (int sig)
1462 CmailSigHandler (int sig)
1467 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1469 /* Activate call-back function CmailSigHandlerCallBack() */
1470 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1472 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1476 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1479 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1481 /**** end signal code ****/
1484 #define Abs(n) ((n)<0 ? -(n) : (n))
1488 InsertPxlSize (char *pattern, int targetPxlSize)
1490 char *base_fnt_lst, strInt[12], *p, *q;
1491 int alternatives, i, len, strIntLen;
1494 * Replace the "*" (if present) in the pixel-size slot of each
1495 * alternative with the targetPxlSize.
1499 while ((p = strchr(p, ',')) != NULL) {
1503 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1504 strIntLen = strlen(strInt);
1505 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1509 while (alternatives--) {
1510 char *comma = strchr(p, ',');
1511 for (i=0; i<14; i++) {
1512 char *hyphen = strchr(p, '-');
1514 if (comma && hyphen > comma) break;
1515 len = hyphen + 1 - p;
1516 if (i == 7 && *p == '*' && len == 2) {
1518 memcpy(q, strInt, strIntLen);
1528 len = comma + 1 - p;
1535 return base_fnt_lst;
1539 CreateFontSet (char *base_fnt_lst)
1542 char **missing_list;
1546 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1547 &missing_list, &missing_count, &def_string);
1548 if (appData.debugMode) {
1550 XFontStruct **font_struct_list;
1551 char **font_name_list;
1552 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1554 fprintf(debugFP, " got list %s, locale %s\n",
1555 XBaseFontNameListOfFontSet(fntSet),
1556 XLocaleOfFontSet(fntSet));
1557 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1558 for (i = 0; i < count; i++) {
1559 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1562 for (i = 0; i < missing_count; i++) {
1563 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1566 if (fntSet == NULL) {
1567 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1572 #else // not ENABLE_NLS
1574 * Find a font that matches "pattern" that is as close as
1575 * possible to the targetPxlSize. Prefer fonts that are k
1576 * pixels smaller to fonts that are k pixels larger. The
1577 * pattern must be in the X Consortium standard format,
1578 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1579 * The return value should be freed with XtFree when no
1583 FindFont (char *pattern, int targetPxlSize)
1585 char **fonts, *p, *best, *scalable, *scalableTail;
1586 int i, j, nfonts, minerr, err, pxlSize;
1588 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1590 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1591 programName, pattern);
1598 for (i=0; i<nfonts; i++) {
1601 if (*p != '-') continue;
1603 if (*p == NULLCHAR) break;
1604 if (*p++ == '-') j++;
1606 if (j < 7) continue;
1609 scalable = fonts[i];
1612 err = pxlSize - targetPxlSize;
1613 if (Abs(err) < Abs(minerr) ||
1614 (minerr > 0 && err < 0 && -err == minerr)) {
1620 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1621 /* If the error is too big and there is a scalable font,
1622 use the scalable font. */
1623 int headlen = scalableTail - scalable;
1624 p = (char *) XtMalloc(strlen(scalable) + 10);
1625 while (isdigit(*scalableTail)) scalableTail++;
1626 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1628 p = (char *) XtMalloc(strlen(best) + 2);
1629 safeStrCpy(p, best, strlen(best)+1 );
1631 if (appData.debugMode) {
1632 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1633 pattern, targetPxlSize, p);
1635 XFreeFontNames(fonts);
1641 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1644 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1650 MarkMenuItem (char *menuRef, int state)
1652 MenuItem *item = MenuNameToItem(menuRef);
1656 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1657 XtSetValues(item->handle, args, 1);
1662 EnableNamedMenuItem (char *menuRef, int state)
1664 MenuItem *item = MenuNameToItem(menuRef);
1666 if(item) XtSetSensitive(item->handle, state);
1670 EnableButtonBar (int state)
1672 XtSetSensitive(optList[W_BUTTON].handle, state);
1677 SetMenuEnables (Enables *enab)
1679 while (enab->name != NULL) {
1680 EnableNamedMenuItem(enab->name, enab->value);
1686 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1687 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1689 if(*nprms == 0) return;
1690 item = MenuNameToItem(prms[0]);
1691 if(item) ((MenuProc *) item->proc) ();
1703 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1704 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1705 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1706 dmEnables[i].piece);
1707 XtSetSensitive(entry, p != NULL || !appData.testLegality
1708 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1709 && !appData.icsActive));
1711 while (p && *p++ == dmEnables[i].piece) count++;
1712 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1714 XtSetArg(args[j], XtNlabel, label); j++;
1715 XtSetValues(entry, args, j);
1720 do_flash_delay (unsigned long msec)
1726 FlashDelay (int flash_delay)
1728 XSync(xDisplay, False);
1729 if(flash_delay) do_flash_delay(flash_delay);
1733 Fraction (int x, int start, int stop)
1735 double f = ((double) x - start)/(stop - start);
1736 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1740 static WindowPlacement wpNew;
1743 CoDrag (Widget sh, WindowPlacement *wp)
1746 int j=0, touch=0, fudge = 2;
1747 GetActualPlacement(sh, wp);
1748 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1749 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1750 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1751 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1752 if(!touch ) return; // only windows that touch co-move
1753 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1754 int heightInc = wpNew.height - wpMain.height;
1755 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1756 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1757 wp->y += fracTop * heightInc;
1758 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1759 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1760 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1761 int widthInc = wpNew.width - wpMain.width;
1762 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1763 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1764 wp->y += fracLeft * widthInc;
1765 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1766 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1768 wp->x += wpNew.x - wpMain.x;
1769 wp->y += wpNew.y - wpMain.y;
1770 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1771 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1772 XtSetArg(args[j], XtNx, wp->x); j++;
1773 XtSetArg(args[j], XtNy, wp->y); j++;
1774 XtSetValues(sh, args, j);
1778 ReSize (WindowPlacement *wp)
1781 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1782 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1783 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1784 if(sqy < sqx) sqx = sqy;
1785 if(sqx != squareSize) {
1786 squareSize = sqx; // adopt new square size
1787 CreatePNGPieces(); // make newly scaled pieces
1788 InitDrawingSizes(0, 0); // creates grid etc.
1789 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1790 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1791 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1792 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1793 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1796 static XtIntervalId delayedDragID = 0;
1805 GetActualPlacement(shellWidget, &wpNew);
1806 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1807 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1808 busy = 0; return; // false alarm
1811 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1812 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1813 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1814 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1816 DrawPosition(True, NULL);
1817 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1825 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1827 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1831 EventProc (Widget widget, caddr_t unused, XEvent *event)
1833 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1834 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1838 * event handler for redrawing the board
1841 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1843 DrawPosition(True, NULL);
1848 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1849 { // [HGM] pv: walk PV
1850 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1853 extern int savedIndex; /* gross that this is global */
1856 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1859 XawTextPosition index, dummy;
1862 XawTextGetSelectionPos(w, &index, &dummy);
1863 XtSetArg(arg, XtNstring, &val);
1864 XtGetValues(w, &arg, 1);
1865 ReplaceComment(savedIndex, val);
1866 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1867 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1871 /* Disable all user input other than deleting the window */
1872 static int frozen = 0;
1878 /* Grab by a widget that doesn't accept input */
1879 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1883 /* Undo a FreezeUI */
1887 if (!frozen) return;
1888 XtRemoveGrab(optList[W_MESSG].handle);
1896 static int oldPausing = FALSE;
1897 static GameMode oldmode = (GameMode) -1;
1900 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1902 if (pausing != oldPausing) {
1903 oldPausing = pausing;
1904 MarkMenuItem("Mode.Pause", pausing);
1906 if (appData.showButtonBar) {
1907 /* Always toggle, don't set. Previous code messes up when
1908 invoked while the button is pressed, as releasing it
1909 toggles the state again. */
1912 XtSetArg(args[0], XtNbackground, &oldbg);
1913 XtSetArg(args[1], XtNforeground, &oldfg);
1914 XtGetValues(optList[W_PAUSE].handle,
1916 XtSetArg(args[0], XtNbackground, oldfg);
1917 XtSetArg(args[1], XtNforeground, oldbg);
1919 XtSetValues(optList[W_PAUSE].handle, args, 2);
1923 wname = ModeToWidgetName(oldmode);
1924 if (wname != NULL) {
1925 MarkMenuItem(wname, False);
1927 wname = ModeToWidgetName(gameMode);
1928 if (wname != NULL) {
1929 MarkMenuItem(wname, True);
1932 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1934 /* Maybe all the enables should be handled here, not just this one */
1935 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1937 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1942 * Button/menu procedures
1945 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1946 char *selected_fen_position=NULL;
1949 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1950 Atom *type_return, XtPointer *value_return,
1951 unsigned long *length_return, int *format_return)
1953 char *selection_tmp;
1955 // if (!selected_fen_position) return False; /* should never happen */
1956 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1957 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1958 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1961 if (f == NULL) return False;
1965 selection_tmp = XtMalloc(len + 1);
1966 count = fread(selection_tmp, 1, len, f);
1969 XtFree(selection_tmp);
1972 selection_tmp[len] = NULLCHAR;
1974 /* note: since no XtSelectionDoneProc was registered, Xt will
1975 * automatically call XtFree on the value returned. So have to
1976 * make a copy of it allocated with XtMalloc */
1977 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1978 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1981 *value_return=selection_tmp;
1982 *length_return=strlen(selection_tmp);
1983 *type_return=*target;
1984 *format_return = 8; /* bits per byte */
1986 } else if (*target == XA_TARGETS(xDisplay)) {
1987 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1988 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1989 targets_tmp[1] = XA_STRING;
1990 *value_return = targets_tmp;
1991 *type_return = XA_ATOM;
1994 // This code leads to a read of value_return out of bounds on 64-bit systems.
1995 // Other code which I have seen always sets *format_return to 32 independent of
1996 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1997 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1998 *format_return = 8 * sizeof(Atom);
1999 if (*format_return > 32) {
2000 *length_return *= *format_return / 32;
2001 *format_return = 32;
2004 *format_return = 32;
2012 /* note: when called from menu all parameters are NULL, so no clue what the
2013 * Widget which was clicked on was, or what the click event was
2016 CopySomething (char *src)
2018 selected_fen_position = src;
2020 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
2021 * have a notion of a position that is selected but not copied.
2022 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
2024 XtOwnSelection(menuBarWidget, XA_PRIMARY,
2026 SendPositionSelection,
2027 NULL/* lose_ownership_proc */ ,
2028 NULL/* transfer_done_proc */);
2029 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2031 SendPositionSelection,
2032 NULL/* lose_ownership_proc */ ,
2033 NULL/* transfer_done_proc */);
2036 /* function called when the data to Paste is ready */
2038 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2039 Atom *type, XtPointer value, unsigned long *len, int *format)
2042 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2043 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2044 EditPositionPasteFEN(fenstr);
2048 /* called when Paste Position button is pressed,
2049 * all parameters will be NULL */
2051 PastePositionProc ()
2053 XtGetSelectionValue(menuBarWidget,
2054 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2055 /* (XtSelectionCallbackProc) */ PastePositionCB,
2056 NULL, /* client_data passed to PastePositionCB */
2058 /* better to use the time field from the event that triggered the
2059 * call to this function, but that isn't trivial to get
2066 /* note: when called from menu all parameters are NULL, so no clue what the
2067 * Widget which was clicked on was, or what the click event was
2069 /* function called when the data to Paste is ready */
2071 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2072 Atom *type, XtPointer value, unsigned long *len, int *format)
2075 if (value == NULL || *len == 0) {
2076 return; /* nothing had been selected to copy */
2078 f = fopen(gamePasteFilename, "w");
2080 DisplayError(_("Can't open temp file"), errno);
2083 fwrite(value, 1, *len, f);
2086 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2089 /* called when Paste Game button is pressed,
2090 * all parameters will be NULL */
2094 XtGetSelectionValue(menuBarWidget,
2095 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2096 /* (XtSelectionCallbackProc) */ PasteGameCB,
2097 NULL, /* client_data passed to PasteGameCB */
2099 /* better to use the time field from the event that triggered the
2100 * call to this function, but that isn't trivial to get
2109 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2116 { // bassic primitive for determining if modifier keys are pressed
2117 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2120 XQueryKeymap(xDisplay,keys);
2121 for(i=0; i<6; i++) {
2123 j = XKeysymToKeycode(xDisplay, codes[i]);
2124 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2130 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2134 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2135 if ( n == 1 && *buf >= 32 // printable
2136 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2137 ) BoxAutoPopUp (buf);
2141 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2142 { // [HGM] input: let up-arrow recall previous line from history
2147 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2148 { // [HGM] input: let down-arrow recall next line from history
2153 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2159 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2161 if (!TempBackwardActive) {
2162 TempBackwardActive = True;
2168 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2170 /* Check to see if triggered by a key release event for a repeating key.
2171 * If so the next queued event will be a key press of the same key at the same time */
2172 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2174 XPeekEvent(xDisplay, &next);
2175 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2176 next.xkey.keycode == event->xkey.keycode)
2180 TempBackwardActive = False;
2184 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2185 { // called as key binding
2188 if (nprms && *nprms > 0)
2192 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2198 { // called from menu
2199 ManInner(NULL, NULL, NULL, NULL);
2203 SetWindowTitle (char *text, char *title, char *icon)
2207 if (appData.titleInWindow) {
2209 XtSetArg(args[i], XtNlabel, text); i++;
2210 XtSetValues(titleWidget, args, i);
2213 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2214 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2215 XtSetValues(shellWidget, args, i);
2216 XSync(xDisplay, False);
2221 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2227 DisplayIcsInteractionTitle (String message)
2229 if (oldICSInteractionTitle == NULL) {
2230 /* Magic to find the old window title, adapted from vim */
2231 char *wina = getenv("WINDOWID");
2233 Window win = (Window) atoi(wina);
2234 Window root, parent, *children;
2235 unsigned int nchildren;
2236 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2238 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2239 if (!XQueryTree(xDisplay, win, &root, &parent,
2240 &children, &nchildren)) break;
2241 if (children) XFree((void *)children);
2242 if (parent == root || parent == 0) break;
2245 XSetErrorHandler(oldHandler);
2247 if (oldICSInteractionTitle == NULL) {
2248 oldICSInteractionTitle = "xterm";
2251 printf("\033]0;%s\007", message);
2256 XtIntervalId delayedEventTimerXID = 0;
2257 DelayedEventCallback delayedEventCallback = 0;
2262 delayedEventTimerXID = 0;
2263 delayedEventCallback();
2267 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2269 if(delayedEventTimerXID && delayedEventCallback == cb)
2270 // [HGM] alive: replace, rather than add or flush identical event
2271 XtRemoveTimeOut(delayedEventTimerXID);
2272 delayedEventCallback = cb;
2273 delayedEventTimerXID =
2274 XtAppAddTimeOut(appContext, millisec,
2275 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2278 DelayedEventCallback
2281 if (delayedEventTimerXID) {
2282 return delayedEventCallback;
2289 CancelDelayedEvent ()
2291 if (delayedEventTimerXID) {
2292 XtRemoveTimeOut(delayedEventTimerXID);
2293 delayedEventTimerXID = 0;
2297 XtIntervalId loadGameTimerXID = 0;
2300 LoadGameTimerRunning ()
2302 return loadGameTimerXID != 0;
2306 StopLoadGameTimer ()
2308 if (loadGameTimerXID != 0) {
2309 XtRemoveTimeOut(loadGameTimerXID);
2310 loadGameTimerXID = 0;
2318 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2320 loadGameTimerXID = 0;
2325 StartLoadGameTimer (long millisec)
2328 XtAppAddTimeOut(appContext, millisec,
2329 (XtTimerCallbackProc) LoadGameTimerCallback,
2333 XtIntervalId analysisClockXID = 0;
2336 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2338 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2339 || appData.icsEngineAnalyze) { // [DM]
2340 AnalysisPeriodicEvent(0);
2341 StartAnalysisClock();
2346 StartAnalysisClock ()
2349 XtAppAddTimeOut(appContext, 2000,
2350 (XtTimerCallbackProc) AnalysisClockCallback,
2354 XtIntervalId clockTimerXID = 0;
2357 ClockTimerRunning ()
2359 return clockTimerXID != 0;
2365 if (clockTimerXID != 0) {
2366 XtRemoveTimeOut(clockTimerXID);
2375 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2382 StartClockTimer (long millisec)
2385 XtAppAddTimeOut(appContext, millisec,
2386 (XtTimerCallbackProc) ClockTimerCallback,
2391 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2395 Widget w = (Widget) opt->handle;
2397 /* check for low time warning */
2398 Pixel foregroundOrWarningColor = timerForegroundPixel;
2401 appData.lowTimeWarning &&
2402 (timer / 1000) < appData.icsAlarmTime)
2403 foregroundOrWarningColor = lowTimeWarningColor;
2405 if (appData.clockMode) {
2406 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2407 XtSetArg(args[0], XtNlabel, buf);
2409 snprintf(buf, MSG_SIZ, "%s ", color);
2410 XtSetArg(args[0], XtNlabel, buf);
2415 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2416 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2418 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2419 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2422 XtSetValues(w, args, 3);
2425 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2428 SetClockIcon (int color)
2431 Pixmap pm = *clockIcons[color];
2432 if (iconPixmap != pm) {
2434 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2435 XtSetValues(shellWidget, args, 1);
2439 #define INPUT_SOURCE_BUF_SIZE 8192
2448 char buf[INPUT_SOURCE_BUF_SIZE];
2453 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2455 InputSource *is = (InputSource *) closure;
2460 if (is->lineByLine) {
2461 count = read(is->fd, is->unused,
2462 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2464 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2467 is->unused += count;
2469 while (p < is->unused) {
2470 q = memchr(p, '\n', is->unused - p);
2471 if (q == NULL) break;
2473 (is->func)(is, is->closure, p, q - p, 0);
2477 while (p < is->unused) {
2482 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2487 (is->func)(is, is->closure, is->buf, count, error);
2492 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2495 ChildProc *cp = (ChildProc *) pr;
2497 is = (InputSource *) calloc(1, sizeof(InputSource));
2498 is->lineByLine = lineByLine;
2502 is->fd = fileno(stdin);
2504 is->kind = cp->kind;
2505 is->fd = cp->fdFrom;
2508 is->unused = is->buf;
2511 is->xid = XtAppAddInput(appContext, is->fd,
2512 (XtPointer) (XtInputReadMask),
2513 (XtInputCallbackProc) DoInputCallback,
2515 is->closure = closure;
2516 return (InputSourceRef) is;
2520 RemoveInputSource (InputSourceRef isr)
2522 InputSource *is = (InputSource *) isr;
2524 if (is->xid == 0) return;
2525 XtRemoveInput(is->xid);
2531 static Boolean frameWaiting;
2534 FrameAlarm (int sig)
2536 frameWaiting = False;
2537 /* In case System-V style signals. Needed?? */
2538 signal(SIGALRM, FrameAlarm);
2542 FrameDelay (int time)
2544 struct itimerval delay;
2546 XSync(xDisplay, False);
2549 frameWaiting = True;
2550 signal(SIGALRM, FrameAlarm);
2551 delay.it_interval.tv_sec =
2552 delay.it_value.tv_sec = time / 1000;
2553 delay.it_interval.tv_usec =
2554 delay.it_value.tv_usec = (time % 1000) * 1000;
2555 setitimer(ITIMER_REAL, &delay, NULL);
2556 while (frameWaiting) pause();
2557 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2558 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2559 setitimer(ITIMER_REAL, &delay, NULL);
2566 FrameDelay (int time)
2568 XSync(xDisplay, False);
2570 usleep(time * 1000);
2576 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2578 char buf[MSG_SIZ], *logoName = buf;
2579 if(appData.logo[n][0]) {
2580 logoName = appData.logo[n];
2581 } else if(appData.autoLogo) {
2582 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2583 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2584 } else if(appData.directory[n] && appData.directory[n][0]) {
2585 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2589 { ASSIGN(cps->programLogo, logoName); }
2593 UpdateLogos (int displ)
2595 if(optList[W_WHITE-1].handle == NULL) return;
2596 LoadLogo(&first, 0, 0);
2597 LoadLogo(&second, 1, appData.icsActive);
2598 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);