2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
64 #include <cairo/cairo.h>
65 #include <cairo/cairo-xlib.h>
68 # if HAVE_SYS_SOCKET_H
69 # include <sys/socket.h>
70 # include <netinet/in.h>
72 # else /* not HAVE_SYS_SOCKET_H */
73 # if HAVE_LAN_SOCKET_H
74 # include <lan/socket.h>
76 # include <lan/netdb.h>
77 # else /* not HAVE_LAN_SOCKET_H */
78 # define OMIT_SOCKETS 1
79 # endif /* not HAVE_LAN_SOCKET_H */
80 # endif /* not HAVE_SYS_SOCKET_H */
81 #endif /* !OMIT_SOCKETS */
86 #else /* not STDC_HEADERS */
87 extern char *getenv();
90 # else /* not HAVE_STRING_H */
92 # endif /* not HAVE_STRING_H */
93 #endif /* not STDC_HEADERS */
96 # include <sys/fcntl.h>
97 #else /* not HAVE_SYS_FCNTL_H */
100 # endif /* HAVE_FCNTL_H */
101 #endif /* not HAVE_SYS_FCNTL_H */
103 #if HAVE_SYS_SYSTEMINFO_H
104 # include <sys/systeminfo.h>
105 #endif /* HAVE_SYS_SYSTEMINFO_H */
107 #if TIME_WITH_SYS_TIME
108 # include <sys/time.h>
112 # include <sys/time.h>
123 # include <sys/wait.h>
128 # define NAMLEN(dirent) strlen((dirent)->d_name)
129 # define HAVE_DIR_STRUCT
131 # define dirent direct
132 # define NAMLEN(dirent) (dirent)->d_namlen
134 # include <sys/ndir.h>
135 # define HAVE_DIR_STRUCT
138 # include <sys/dir.h>
139 # define HAVE_DIR_STRUCT
143 # define HAVE_DIR_STRUCT
151 #include <X11/Intrinsic.h>
152 #include <X11/StringDefs.h>
153 #include <X11/Shell.h>
154 #include <X11/cursorfont.h>
155 #include <X11/Xatom.h>
156 #include <X11/Xmu/Atoms.h>
158 #include <X11/Xaw3d/Dialog.h>
159 #include <X11/Xaw3d/Form.h>
160 #include <X11/Xaw3d/List.h>
161 #include <X11/Xaw3d/Label.h>
162 #include <X11/Xaw3d/SimpleMenu.h>
163 #include <X11/Xaw3d/SmeBSB.h>
164 #include <X11/Xaw3d/SmeLine.h>
165 #include <X11/Xaw3d/Box.h>
166 #include <X11/Xaw3d/MenuButton.h>
167 #include <X11/Xaw3d/Text.h>
168 #include <X11/Xaw3d/AsciiText.h>
170 #include <X11/Xaw/Dialog.h>
171 #include <X11/Xaw/Form.h>
172 #include <X11/Xaw/List.h>
173 #include <X11/Xaw/Label.h>
174 #include <X11/Xaw/SimpleMenu.h>
175 #include <X11/Xaw/SmeBSB.h>
176 #include <X11/Xaw/SmeLine.h>
177 #include <X11/Xaw/Box.h>
178 #include <X11/Xaw/MenuButton.h>
179 #include <X11/Xaw/Text.h>
180 #include <X11/Xaw/AsciiText.h>
183 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
192 #include "backendz.h"
196 #include "xgamelist.h"
197 #include "xhistory.h"
201 #include "engineoutput.h"
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
223 int main P((int argc, char **argv));
224 RETSIGTYPE CmailSigHandler P((int sig));
225 RETSIGTYPE IntSigHandler P((int sig));
226 RETSIGTYPE TermSizeSigHandler P((int sig));
227 Widget CreateMenuBar P((Menu *mb, int boardWidth));
229 char *InsertPxlSize P((char *pattern, int targetPxlSize));
230 XFontSet CreateFontSet P((char *base_fnt_lst));
232 char *FindFont P((char *pattern, int targetPxlSize));
234 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
235 u_int wreq, u_int hreq));
236 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
237 void DelayedDrag P((void));
238 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
239 void HandlePV P((Widget w, XEvent * event,
240 String * params, Cardinal * nParams));
241 void DrawPositionProc P((Widget w, XEvent *event,
242 String *prms, Cardinal *nprms));
243 void CommentClick P((Widget w, XEvent * event,
244 String * params, Cardinal * nParams));
245 void ICSInputBoxPopUp P((void));
246 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
247 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
248 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
249 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
250 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
251 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
252 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
253 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
254 Boolean TempBackwardActive = False;
255 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 void DisplayMove P((int moveNumber));
257 void update_ics_width P(());
258 int CopyMemoProc P(());
261 * XBoard depends on Xt R4 or higher
263 int xtVersion = XtSpecificationRelease;
268 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
269 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
270 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
271 Option *optList; // contains all widgets of main window
273 XFontSet fontSet, clockFontSet;
276 XFontStruct *clockFontStruct;
278 Font coordFontID, countFontID;
279 XFontStruct *coordFontStruct, *countFontStruct;
280 XtAppContext appContext;
283 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
285 Position commentX = -1, commentY = -1;
286 Dimension commentW, commentH;
287 typedef unsigned int BoardSize;
289 Boolean chessProgram;
291 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
292 int smallLayout = 0, tinyLayout = 0,
293 marginW, marginH, // [HGM] for run-time resizing
294 fromX = -1, fromY = -1, toX, toY, commentUp = False,
295 errorExitStatus = -1, defaultLineGap;
296 Dimension textHeight;
297 Pixel timerForegroundPixel, timerBackgroundPixel;
298 Pixel buttonForegroundPixel, buttonBackgroundPixel;
299 char *chessDir, *programName, *programVersion;
300 Boolean alwaysOnTop = False;
301 char *icsTextMenuString;
303 char *firstChessProgramNames;
304 char *secondChessProgramNames;
306 WindowPlacement wpMain;
307 WindowPlacement wpConsole;
308 WindowPlacement wpComment;
309 WindowPlacement wpMoveHistory;
310 WindowPlacement wpEvalGraph;
311 WindowPlacement wpEngineOutput;
312 WindowPlacement wpGameList;
313 WindowPlacement wpTags;
314 WindowPlacement wpDualBoard;
317 /* This magic number is the number of intermediate frames used
318 in each half of the animation. For short moves it's reduced
319 by 1. The total number of frames will be factor * 2 + 1. */
322 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
329 DropMenuEnables dmEnables[] = {
346 XtResource clientResources[] = {
347 { "flashCount", "flashCount", XtRInt, sizeof(int),
348 XtOffset(AppDataPtr, flashCount), XtRImmediate,
349 (XtPointer) FLASH_COUNT },
352 XrmOptionDescRec shellOptions[] = {
353 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
354 { "-flash", "flashCount", XrmoptionNoArg, "3" },
355 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
358 XtActionsRec boardActions[] = {
359 { "DrawPosition", DrawPositionProc },
360 { "HandlePV", HandlePV },
361 { "SelectPV", SelectPV },
362 { "StopPV", StopPV },
363 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
364 { "QuitProc", QuitWrapper },
365 { "ManProc", ManInner },
366 { "TempBackwardProc", TempBackwardProc },
367 { "TempForwardProc", TempForwardProc },
368 { "CommentClick", (XtActionProc) CommentClick },
369 { "GenericPopDown", (XtActionProc) GenericPopDown },
370 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
371 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
372 { "SelectMove", (XtActionProc) SelectMoveX },
373 { "LoadSelectedProc", LoadSelectedProc },
374 { "SetFilterProc", SetFilterProc },
375 { "TypeInProc", TypeInProc },
376 { "EnterKeyProc", EnterKeyProc },
377 { "UpKeyProc", UpKeyProc },
378 { "DownKeyProc", DownKeyProc },
379 { "WheelProc", WheelProc },
380 { "TabProc", TabProc },
383 char globalTranslations[] =
384 ":Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
385 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
386 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
387 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
388 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
389 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
390 :<Key>Pause: MenuItem(Mode.Pause) \n \
391 :Ctrl<Key>d: MenuItem(DebugProc) \n \
392 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
393 :<Key>Left: MenuItem(Edit.Backward) \n \
394 :<Key>Right: MenuItem(Edit.Forward) \n \
395 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
396 #ifndef OPTIONSDIALOG
398 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
399 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
400 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
401 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
402 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
405 :<KeyDown>Return: TempBackwardProc() \n \
406 :<KeyUp>Return: TempForwardProc() \n";
408 char ICSInputTranslations[] =
409 "<Key>Up: UpKeyProc() \n "
410 "<Key>Down: DownKeyProc() \n "
411 "<Key>Return: EnterKeyProc() \n";
413 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
414 // as the widget is destroyed before the up-click can call extend-end
415 char commentTranslations[] = "<Btn3Down>: extend-end(PRIMARY) select-start() CommentClick() \n";
417 String xboardResources[] = {
418 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
423 /* Max possible square size */
424 #define MAXSQSIZE 256
426 /* Arrange to catch delete-window events */
427 Atom wm_delete_window;
429 CatchDeleteWindow (Widget w, String procname)
432 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
433 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
434 XtAugmentTranslations(w, XtParseTranslationTable(buf));
441 XtSetArg(args[0], XtNiconic, False);
442 XtSetValues(shellWidget, args, 1);
444 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
447 //---------------------------------------------------------------------------------------------------------
448 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
451 #define CW_USEDEFAULT (1<<31)
452 #define ICS_TEXT_MENU_SIZE 90
453 #define DEBUG_FILE "xboard.debug"
454 #define SetCurrentDirectory chdir
455 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
459 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
462 // front-end part of option handling
464 // [HGM] This platform-dependent table provides the location for storing the color info
465 extern char *crWhite, * crBlack;
469 &appData.whitePieceColor,
470 &appData.blackPieceColor,
471 &appData.lightSquareColor,
472 &appData.darkSquareColor,
473 &appData.highlightSquareColor,
474 &appData.premoveHighlightColor,
475 &appData.lowTimeWarningColor,
486 // [HGM] font: keep a font for each square size, even non-stndard ones
489 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
490 char *fontTable[NUM_FONTS][MAX_SIZE];
493 ParseFont (char *name, int number)
494 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
496 if(sscanf(name, "size%d:", &size)) {
497 // [HGM] font: font is meant for specific boardSize (likely from settings file);
498 // defer processing it until we know if it matches our board size
499 if(strstr(name, "-*-") && // only pay attention to things that look like X-fonts
500 size >= 0 && size<MAX_SIZE) { // for now, fixed limit
501 fontTable[number][size] = strdup(strchr(name, ':')+1);
502 fontValid[number][size] = True;
507 case 0: // CLOCK_FONT
508 appData.clockFont = strdup(name);
510 case 1: // MESSAGE_FONT
511 appData.font = strdup(name);
513 case 2: // COORD_FONT
514 appData.coordFont = strdup(name);
519 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
524 { // only 2 fonts currently
525 appData.clockFont = CLOCK_FONT_NAME;
526 appData.coordFont = COORD_FONT_NAME;
527 appData.font = DEFAULT_FONT_NAME;
532 { // no-op, until we identify the code for this already in XBoard and move it here
536 ParseColor (int n, char *name)
537 { // in XBoard, just copy the color-name string
538 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
544 return *(char**)colorVariable[n];
548 ParseTextAttribs (ColorClass cc, char *s)
550 (&appData.colorShout)[cc] = strdup(s);
554 ParseBoardSize (void *addr, char *name)
556 appData.boardSize = strdup(name);
561 { // In XBoard the sound-playing program takes care of obtaining the actual sound
565 SetCommPortDefaults ()
566 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
569 // [HGM] args: these three cases taken out to stay in front-end
571 SaveFontArg (FILE *f, ArgDescriptor *ad)
574 int i, n = (int)(intptr_t)ad->argLoc;
576 case 0: // CLOCK_FONT
577 name = appData.clockFont;
579 case 1: // MESSAGE_FONT
582 case 2: // COORD_FONT
583 name = appData.coordFont;
588 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
589 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
590 fontTable[n][squareSize] = strdup(name);
591 fontValid[n][squareSize] = True;
594 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
595 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
600 { // nothing to do, as the sounds are at all times represented by their text-string names already
604 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
605 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
606 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
610 SaveColor (FILE *f, ArgDescriptor *ad)
611 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
612 if(colorVariable[(int)(intptr_t)ad->argLoc])
613 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
617 SaveBoardSize (FILE *f, char *name, void *addr)
618 { // wrapper to shield back-end from BoardSize & sizeInfo
619 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
623 ParseCommPortSettings (char *s)
624 { // no such option in XBoard (yet)
630 GetActualPlacement (Widget wg, WindowPlacement *wp)
632 XWindowAttributes winAt;
639 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
640 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
641 wp->x = rx - winAt.x;
642 wp->y = ry - winAt.y;
643 wp->height = winAt.height;
644 wp->width = winAt.width;
645 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
649 GetPlacement (DialogClass dlg, WindowPlacement *wp)
650 { // wrapper to shield back-end from widget type
651 if(shellUp[dlg]) GetActualPlacement(shells[dlg], wp);
656 { // wrapper to shield use of window handles from back-end (make addressible by number?)
657 // In XBoard this will have to wait until awareness of window parameters is implemented
658 GetActualPlacement(shellWidget, &wpMain);
659 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
660 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
661 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
662 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
663 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
664 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
668 PrintCommPortSettings (FILE *f, char *name)
669 { // This option does not exist in XBoard
673 EnsureOnScreen (int *x, int *y, int minX, int minY)
680 { // [HGM] args: allows testing if main window is realized from back-end
681 return xBoardWindow != 0;
685 PopUpStartupDialog ()
686 { // start menu not implemented in XBoard
690 ConvertToLine (int argc, char **argv)
692 static char line[128*1024], buf[1024];
696 for(i=1; i<argc; i++)
698 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
699 && argv[i][0] != '{' )
700 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
702 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
703 strncat(line, buf, 128*1024 - strlen(line) - 1 );
706 line[strlen(line)-1] = NULLCHAR;
710 //--------------------------------------------------------------------------------------------
713 ResizeBoardWindow (int w, int h, int inhibit)
715 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
717 shellArgs[0].value = w;
718 shellArgs[1].value = h;
719 shellArgs[4].value = shellArgs[2].value = w;
720 shellArgs[5].value = shellArgs[3].value = h;
721 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
723 XSync(xDisplay, False);
727 MakeOneColor (char *name, Pixel *color)
730 if (!appData.monoMode) {
731 vFrom.addr = (caddr_t) name;
732 vFrom.size = strlen(name);
733 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
734 if (vTo.addr == NULL) {
735 appData.monoMode = True;
738 *color = *(Pixel *) vTo.addr;
746 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
747 int forceMono = False;
749 if (appData.lowTimeWarning)
750 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
751 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
752 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
758 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
759 { // detervtomine what fonts to use, and create them
763 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
764 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
765 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
766 appData.font = fontTable[MESSAGE_FONT][squareSize];
767 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
768 appData.coordFont = fontTable[COORD_FONT][squareSize];
771 appData.font = InsertPxlSize(appData.font, fontPxlSize);
772 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
773 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
774 fontSet = CreateFontSet(appData.font);
775 clockFontSet = CreateFontSet(appData.clockFont);
777 /* For the coordFont, use the 0th font of the fontset. */
778 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
779 XFontStruct **font_struct_list;
780 XFontSetExtents *fontSize;
781 char **font_name_list;
782 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
783 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
784 coordFontStruct = XQueryFont(xDisplay, coordFontID);
785 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
786 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
789 appData.font = FindFont(appData.font, fontPxlSize);
790 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
791 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
792 clockFontID = XLoadFont(xDisplay, appData.clockFont);
793 clockFontStruct = XQueryFont(xDisplay, clockFontID);
794 coordFontID = XLoadFont(xDisplay, appData.coordFont);
795 coordFontStruct = XQueryFont(xDisplay, coordFontID);
796 // textHeight in !NLS mode!
798 countFontID = coordFontID; // [HGM] holdings
799 countFontStruct = coordFontStruct;
801 xdb = XtDatabase(xDisplay);
803 XrmPutLineResource(&xdb, "*international: True");
804 vTo.size = sizeof(XFontSet);
805 vTo.addr = (XtPointer) &fontSet;
806 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
808 XrmPutStringResource(&xdb, "*font", appData.font);
818 case ArgInt: p = " N"; break;
819 case ArgString: p = " STR"; break;
820 case ArgBoolean: p = " TF"; break;
821 case ArgSettingsFilename:
822 case ArgBackupSettingsFile:
823 case ArgFilename: p = " FILE"; break;
824 case ArgX: p = " Nx"; break;
825 case ArgY: p = " Ny"; break;
826 case ArgAttribs: p = " TEXTCOL"; break;
827 case ArgColor: p = " COL"; break;
828 case ArgFont: p = " FONT"; break;
829 case ArgBoardSize: p = " SIZE"; break;
830 case ArgFloat: p = " FLOAT"; break;
835 case ArgCommSettings:
844 GenerateGlobalTranslationTable (void)
846 /* go through all menu items and extract the keyboard shortcuts, so that X11 can load them */
854 /* loop over all menu entries */
855 for( i=0; menuBar[i].mi ; i++)
858 for(j=0; mi[j].proc; j++)
866 char *key,*test, *mods;
868 /* check for Ctrl/Alt */
869 if( strstr(mi[j].accel, "<Ctrl>") ) ctrl = 1;
870 if( strstr(mi[j].accel, "<Shift>") ) shift = 1;
871 if( strstr(mi[j].accel, "<Alt>") ) alt = 1;
873 /* remove all <...> */
874 test = strrchr(mi[j].accel, '>');
876 key = strdup(mi[j].accel);
878 key = strdup(++test); // remove ">"
880 /* instead of shift X11 uses the uppercase letter directly*/
881 if (shift && strlen(key)==1 )
883 *key = toupper(*key);
887 /* handle some special cases which have different names in X11 */
888 if ( strncmp(key, "Page_Down", 9) == 0 )
893 else if ( strncmp(key, "Page_Up", 7) == 0 )
899 /* create string of mods */
901 mods = strdup("Ctrl ");
907 mods = realloc(mods, strlen(mods) + strlen("Meta ")+1);
908 strncat(mods, "Meta ", 5);
913 mods = realloc(mods, strlen(mods) + strlen("Shift ")+1);
914 strncat(mods, "Shift ", 6);
917 // remove trailing space
918 if( isspace(mods[strlen(mods)-1]) )
919 mods[strlen(mods)-1]='\0';
921 /* get the name for the callback, we can use MenuItem() here that will call KeyBindingProc */
922 size_t namesize = snprintf(NULL, 0, "%s.%s", menuBar[i].ref, mi[j].ref);
923 char *name = malloc(namesize+1);
924 snprintf(name, namesize+1, "%s.%s", menuBar[i].ref, mi[j].ref);
926 size_t buffersize = snprintf(NULL, 0, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
927 char *buffer = malloc(buffersize+1);
928 snprintf(buffer, buffersize+1, ":%s<Key>%s: MenuItem(%s) \n ", mods, key, name);
930 /* add string to the output */
931 output = realloc(output, strlen(output) + strlen(buffer)+1);
932 strncat(output, buffer, strlen(buffer));
951 ArgDescriptor *q, *p = argDescriptors+5;
952 printf("\nXBoard accepts the following options:\n"
953 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
954 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
955 " SIZE = board-size spec(s)\n"
956 " Within parentheses are short forms, or options to set to true or false.\n"
957 " Persistent options (saved in the settings file) are marked with *)\n\n");
959 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
960 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
961 if(p->save) strcat(buf+len, "*");
962 for(q=p+1; q->argLoc == p->argLoc; q++) {
963 if(q->argName[0] == '-') continue;
964 strcat(buf+len, q == p+1 ? " (" : " ");
965 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
967 if(q != p+1) strcat(buf+len, ")");
969 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
972 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
976 SlaveResize (Option *opt)
981 main (int argc, char **argv)
983 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
984 XSetWindowAttributes window_attributes;
986 Dimension boardWidth, boardHeight, w, h;
988 int forceMono = False;
990 srandom(time(0)); // [HGM] book: make random truly random
992 setbuf(stdout, NULL);
993 setbuf(stderr, NULL);
996 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
997 printf("%s version %s\n\n configure options: %s\n", PACKAGE_NAME, PACKAGE_VERSION, CONFIGURE_OPTIONS);
1001 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1006 if(argc > 1 && !strcmp(argv[1], "--show-config")) { // [HGM] install: called to print config info
1007 typedef struct {char *name, *value; } Config;
1008 static Config configList[] = {
1009 { "Datadir", DATADIR },
1010 { "Sysconfdir", SYSCONFDIR },
1015 for(i=0; configList[i].name; i++) {
1016 if(argc > 2 && strcmp(argv[2], configList[i].name)) continue;
1017 if(argc > 2) printf("%s", configList[i].value);
1018 else printf("%-12s: %s\n", configList[i].name, configList[i].value);
1023 programName = strrchr(argv[0], '/');
1024 if (programName == NULL)
1025 programName = argv[0];
1030 XtSetLanguageProc(NULL, NULL, NULL);
1031 if (appData.debugMode) {
1032 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1035 bindtextdomain(PACKAGE, LOCALEDIR);
1036 textdomain(PACKAGE);
1039 appData.boardSize = "";
1040 InitAppData(ConvertToLine(argc, argv));
1042 if (p == NULL) p = "/tmp";
1043 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1044 gameCopyFilename = (char*) malloc(i);
1045 gamePasteFilename = (char*) malloc(i);
1046 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1047 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1049 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1050 static char buf[MSG_SIZ];
1051 EscapeExpand(buf, appData.firstInitString);
1052 appData.firstInitString = strdup(buf);
1053 EscapeExpand(buf, appData.secondInitString);
1054 appData.secondInitString = strdup(buf);
1055 EscapeExpand(buf, appData.firstComputerString);
1056 appData.firstComputerString = strdup(buf);
1057 EscapeExpand(buf, appData.secondComputerString);
1058 appData.secondComputerString = strdup(buf);
1061 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1064 if (chdir(chessDir) != 0) {
1065 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1071 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1072 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1073 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1074 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1077 setbuf(debugFP, NULL);
1080 /* [HGM,HR] make sure board size is acceptable */
1081 if(appData.NrFiles > BOARD_FILES ||
1082 appData.NrRanks > BOARD_RANKS )
1083 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1086 /* This feature does not work; animation needs a rewrite */
1087 appData.highlightDragging = FALSE;
1091 gameInfo.variant = StringToVariant(appData.variant);
1092 InitPosition(FALSE);
1095 XtAppInitialize(&appContext, "XBoard", shellOptions,
1096 XtNumber(shellOptions),
1097 &argc, argv, xboardResources, NULL, 0);
1099 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1100 clientResources, XtNumber(clientResources),
1103 xDisplay = XtDisplay(shellWidget);
1104 xScreen = DefaultScreen(xDisplay);
1105 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1108 * determine size, based on supplied or remembered -size, or screen size
1110 if (isdigit(appData.boardSize[0])) {
1111 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1112 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1113 &fontPxlSize, &smallLayout, &tinyLayout);
1115 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1116 programName, appData.boardSize);
1120 squareSize = (squareSize*8 + BOARD_WIDTH/2)/BOARD_WIDTH; // scale height
1122 /* Find some defaults; use the nearest known size */
1123 SizeDefaults *szd, *nearest;
1124 int distance = 99999;
1125 nearest = szd = sizeDefaults;
1126 while (szd->name != NULL) {
1127 if (abs(szd->squareSize - squareSize) < distance) {
1129 distance = abs(szd->squareSize - squareSize);
1130 if (distance == 0) break;
1134 if (i < 2) lineGap = nearest->lineGap;
1135 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1136 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1137 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1138 if (i < 6) smallLayout = nearest->smallLayout;
1139 if (i < 7) tinyLayout = nearest->tinyLayout;
1142 SizeDefaults *szd = sizeDefaults;
1143 if (*appData.boardSize == NULLCHAR) {
1144 while (DisplayWidth(xDisplay, xScreen) < (szd->minScreenSize*BOARD_WIDTH + 4)/8 ||
1145 DisplayHeight(xDisplay, xScreen) < (szd->minScreenSize*BOARD_HEIGHT + 4)/8) {
1148 if (szd->name == NULL) szd--;
1149 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1151 while (szd->name != NULL &&
1152 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1153 if (szd->name == NULL) {
1154 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1155 programName, appData.boardSize);
1159 squareSize = szd->squareSize;
1160 lineGap = szd->lineGap;
1161 clockFontPxlSize = szd->clockFontPxlSize;
1162 coordFontPxlSize = szd->coordFontPxlSize;
1163 fontPxlSize = szd->fontPxlSize;
1164 smallLayout = szd->smallLayout;
1165 tinyLayout = szd->tinyLayout;
1166 // [HGM] font: use defaults from settings file if available and not overruled
1169 defaultLineGap = lineGap;
1170 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1172 /* [HR] height treated separately (hacked) */
1173 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1174 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1177 * Determine what fonts to use.
1179 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1182 * Detect if there are not enough colors available and adapt.
1184 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1185 appData.monoMode = True;
1188 forceMono = MakeColors();
1191 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1193 appData.monoMode = True;
1196 if (appData.monoMode && appData.debugMode) {
1197 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1198 (unsigned long) XWhitePixel(xDisplay, xScreen),
1199 (unsigned long) XBlackPixel(xDisplay, xScreen));
1202 ParseIcsTextColors();
1204 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1210 layoutName = "tinyLayout";
1211 } else if (smallLayout) {
1212 layoutName = "smallLayout";
1214 layoutName = "normalLayout";
1217 optList = BoardPopUp(squareSize, lineGap, (void*)
1223 InitDrawingHandle(optList + W_BOARD);
1224 currBoard = &optList[W_BOARD];
1225 boardWidget = optList[W_BOARD].handle;
1226 menuBarWidget = optList[W_MENU].handle;
1227 dropMenu = optList[W_DROP].handle;
1228 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1229 formWidget = XtParent(boardWidget);
1230 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1231 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1232 XtGetValues(optList[W_WHITE].handle, args, 2);
1233 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1234 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1235 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1236 XtGetValues(optList[W_PAUSE].handle, args, 2);
1239 xBoardWindow = XtWindow(boardWidget);
1241 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1242 // not need to go into InitDrawingSizes().
1245 * Create X checkmark bitmap and initialize option menu checks.
1247 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1248 checkmark_bits, checkmark_width, checkmark_height);
1254 ReadBitmap(&wIconPixmap, "icon_white.bm",
1255 icon_white_bits, icon_white_width, icon_white_height);
1256 ReadBitmap(&bIconPixmap, "icon_black.bm",
1257 icon_black_bits, icon_black_width, icon_black_height);
1258 iconPixmap = wIconPixmap;
1260 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1261 XtSetValues(shellWidget, args, i);
1264 * Create a cursor for the board widget.
1266 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1267 XChangeWindowAttributes(xDisplay, xBoardWindow,
1268 CWCursor, &window_attributes);
1271 * Inhibit shell resizing.
1273 shellArgs[0].value = (XtArgVal) &w;
1274 shellArgs[1].value = (XtArgVal) &h;
1275 XtGetValues(shellWidget, shellArgs, 2);
1276 shellArgs[4].value = shellArgs[2].value = w;
1277 shellArgs[5].value = shellArgs[3].value = h;
1278 // XtSetValues(shellWidget, &shellArgs[2], 4);
1279 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1280 marginH = h - boardHeight;
1282 CatchDeleteWindow(shellWidget, "QuitProc");
1287 if(appData.logoSize)
1288 { // locate and read user logo
1290 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1291 ASSIGN(userLogo, buf);
1294 if (appData.animate || appData.animateDragging)
1298 char *TranslationsTableMenus=GenerateGlobalTranslationTable ();
1300 XtAugmentTranslations(formWidget,
1301 XtParseTranslationTable(globalTranslations));
1302 XtAugmentTranslations(formWidget,
1303 XtParseTranslationTable(TranslationsTableMenus));
1305 XtAddEventHandler(formWidget, KeyPressMask, False,
1306 (XtEventHandler) MoveTypeInProc, NULL);
1307 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1308 (XtEventHandler) EventProc, NULL);
1310 /* [AS] Restore layout */
1311 if( wpMoveHistory.visible ) {
1315 if( wpEvalGraph.visible )
1320 if( wpEngineOutput.visible ) {
1321 EngineOutputPopUp();
1324 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1329 if (errorExitStatus == -1) {
1330 if (appData.icsActive) {
1331 /* We now wait until we see "login:" from the ICS before
1332 sending the logon script (problems with timestamp otherwise) */
1333 /*ICSInitScript();*/
1334 if (appData.icsInputBox) ICSInputBoxPopUp();
1338 signal(SIGWINCH, TermSizeSigHandler);
1340 signal(SIGINT, IntSigHandler);
1341 signal(SIGTERM, IntSigHandler);
1342 if (*appData.cmailGameName != NULLCHAR) {
1343 signal(SIGUSR1, CmailSigHandler);
1348 // XtSetKeyboardFocus(shellWidget, formWidget);
1349 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1351 XtAppMainLoop(appContext);
1352 if (appData.debugMode) fclose(debugFP); // [DM] debug
1360 while((m = XtAppPending(appContext))) XtAppProcessEvent(appContext, m);
1364 TermSizeSigHandler (int sig)
1370 IntSigHandler (int sig)
1376 CmailSigHandler (int sig)
1381 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1383 /* Activate call-back function CmailSigHandlerCallBack() */
1384 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1386 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1390 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1393 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1395 /**** end signal code ****/
1398 #define Abs(n) ((n)<0 ? -(n) : (n))
1402 InsertPxlSize (char *pattern, int targetPxlSize)
1404 char *base_fnt_lst, strInt[12], *p, *q;
1405 int alternatives, i, len, strIntLen;
1408 * Replace the "*" (if present) in the pixel-size slot of each
1409 * alternative with the targetPxlSize.
1413 while ((p = strchr(p, ',')) != NULL) {
1417 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1418 strIntLen = strlen(strInt);
1419 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1423 while (alternatives--) {
1424 char *comma = strchr(p, ',');
1425 for (i=0; i<14; i++) {
1426 char *hyphen = strchr(p, '-');
1428 if (comma && hyphen > comma) break;
1429 len = hyphen + 1 - p;
1430 if (i == 7 && *p == '*' && len == 2) {
1432 memcpy(q, strInt, strIntLen);
1442 len = comma + 1 - p;
1449 return base_fnt_lst;
1453 CreateFontSet (char *base_fnt_lst)
1456 char **missing_list;
1460 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1461 &missing_list, &missing_count, &def_string);
1462 if (appData.debugMode) {
1464 XFontStruct **font_struct_list;
1465 char **font_name_list;
1466 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1468 fprintf(debugFP, " got list %s, locale %s\n",
1469 XBaseFontNameListOfFontSet(fntSet),
1470 XLocaleOfFontSet(fntSet));
1471 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1472 for (i = 0; i < count; i++) {
1473 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1476 for (i = 0; i < missing_count; i++) {
1477 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1480 if (fntSet == NULL) {
1481 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1486 #else // not ENABLE_NLS
1488 * Find a font that matches "pattern" that is as close as
1489 * possible to the targetPxlSize. Prefer fonts that are k
1490 * pixels smaller to fonts that are k pixels larger. The
1491 * pattern must be in the X Consortium standard format,
1492 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1493 * The return value should be freed with XtFree when no
1497 FindFont (char *pattern, int targetPxlSize)
1499 char **fonts, *p, *best, *scalable, *scalableTail;
1500 int i, j, nfonts, minerr, err, pxlSize;
1502 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1504 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1505 programName, pattern);
1512 for (i=0; i<nfonts; i++) {
1515 if (*p != '-') continue;
1517 if (*p == NULLCHAR) break;
1518 if (*p++ == '-') j++;
1520 if (j < 7) continue;
1523 scalable = fonts[i];
1526 err = pxlSize - targetPxlSize;
1527 if (Abs(err) < Abs(minerr) ||
1528 (minerr > 0 && err < 0 && -err == minerr)) {
1534 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1535 /* If the error is too big and there is a scalable font,
1536 use the scalable font. */
1537 int headlen = scalableTail - scalable;
1538 p = (char *) XtMalloc(strlen(scalable) + 10);
1539 while (isdigit(*scalableTail)) scalableTail++;
1540 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1542 p = (char *) XtMalloc(strlen(best) + 2);
1543 safeStrCpy(p, best, strlen(best)+1 );
1545 if (appData.debugMode) {
1546 fprintf(debugFP, "resolved %s at pixel size %d\n to %s\n",
1547 pattern, targetPxlSize, p);
1549 XFreeFontNames(fonts);
1555 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1558 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1564 MarkMenuItem (char *menuRef, int state)
1566 MenuItem *item = MenuNameToItem(menuRef);
1570 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1571 XtSetValues(item->handle, args, 1);
1576 EnableNamedMenuItem (char *menuRef, int state)
1578 MenuItem *item = MenuNameToItem(menuRef);
1580 if(item) XtSetSensitive(item->handle, state);
1584 EnableButtonBar (int state)
1586 XtSetSensitive(optList[W_BUTTON].handle, state);
1591 SetMenuEnables (Enables *enab)
1593 while (enab->name != NULL) {
1594 EnableNamedMenuItem(enab->name, enab->value);
1600 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1601 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1603 if(*nprms == 0) return;
1604 item = MenuNameToItem(prms[0]);
1605 if(item) ((MenuProc *) item->proc) ();
1617 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1618 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1619 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1620 dmEnables[i].piece);
1621 XtSetSensitive(entry, p != NULL || !appData.testLegality
1622 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1623 && !appData.icsActive));
1625 while (p && *p++ == dmEnables[i].piece) count++;
1626 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1628 XtSetArg(args[j], XtNlabel, label); j++;
1629 XtSetValues(entry, args, j);
1634 do_flash_delay (unsigned long msec)
1640 FlashDelay (int flash_delay)
1642 XSync(xDisplay, False);
1643 if(flash_delay) do_flash_delay(flash_delay);
1647 Fraction (int x, int start, int stop)
1649 double f = ((double) x - start)/(stop - start);
1650 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1654 static WindowPlacement wpNew;
1657 CoDrag (Widget sh, WindowPlacement *wp)
1660 int j=0, touch=0, fudge = 2;
1661 GetActualPlacement(sh, wp);
1662 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1663 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1664 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1665 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1666 if(!touch ) return; // only windows that touch co-move
1667 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1668 int heightInc = wpNew.height - wpMain.height;
1669 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1670 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1671 wp->y += fracTop * heightInc;
1672 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1673 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1674 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1675 int widthInc = wpNew.width - wpMain.width;
1676 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1677 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1678 wp->y += fracLeft * widthInc;
1679 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1680 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1682 wp->x += wpNew.x - wpMain.x;
1683 wp->y += wpNew.y - wpMain.y;
1684 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1685 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1686 XtSetArg(args[j], XtNx, wp->x); j++;
1687 XtSetArg(args[j], XtNy, wp->y); j++;
1688 XtSetValues(sh, args, j);
1692 ReSize (WindowPlacement *wp)
1695 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1696 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1697 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1698 if(sqy < sqx) sqx = sqy;
1699 if(sqx != squareSize) {
1700 squareSize = sqx; // adopt new square size
1701 CreatePNGPieces(); // make newly scaled pieces
1702 InitDrawingSizes(0, 0); // creates grid etc.
1703 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1704 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1705 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1706 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1707 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1710 static XtIntervalId delayedDragID = 0;
1719 GetActualPlacement(shellWidget, &wpNew);
1720 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1721 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1722 busy = 0; return; // false alarm
1725 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1726 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1727 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1728 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1730 DrawPosition(True, NULL);
1731 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1739 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1741 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1745 EventProc (Widget widget, caddr_t unused, XEvent *event)
1747 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1748 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1752 * event handler for redrawing the board
1755 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1757 DrawPosition(True, NULL);
1762 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1763 { // [HGM] pv: walk PV
1764 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1767 extern int savedIndex; /* gross that this is global */
1770 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1773 XawTextPosition index, dummy;
1776 XawTextGetSelectionPos(w, &index, &dummy);
1777 XtSetArg(arg, XtNstring, &val);
1778 XtGetValues(w, &arg, 1);
1779 ReplaceComment(savedIndex, val);
1780 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1781 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1785 /* Disable all user input other than deleting the window */
1786 static int frozen = 0;
1792 /* Grab by a widget that doesn't accept input */
1793 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1797 /* Undo a FreezeUI */
1801 if (!frozen) return;
1802 XtRemoveGrab(optList[W_MESSG].handle);
1810 static int oldPausing = FALSE;
1811 static GameMode oldmode = (GameMode) -1;
1814 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1816 if (pausing != oldPausing) {
1817 oldPausing = pausing;
1818 MarkMenuItem("Mode.Pause", pausing);
1820 if (appData.showButtonBar) {
1821 /* Always toggle, don't set. Previous code messes up when
1822 invoked while the button is pressed, as releasing it
1823 toggles the state again. */
1826 XtSetArg(args[0], XtNbackground, &oldbg);
1827 XtSetArg(args[1], XtNforeground, &oldfg);
1828 XtGetValues(optList[W_PAUSE].handle,
1830 XtSetArg(args[0], XtNbackground, oldfg);
1831 XtSetArg(args[1], XtNforeground, oldbg);
1833 XtSetValues(optList[W_PAUSE].handle, args, 2);
1837 wname = ModeToWidgetName(oldmode);
1838 if (wname != NULL) {
1839 MarkMenuItem(wname, False);
1841 wname = ModeToWidgetName(gameMode);
1842 if (wname != NULL) {
1843 MarkMenuItem(wname, True);
1846 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1848 /* Maybe all the enables should be handled here, not just this one */
1849 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1851 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1856 * Button/menu procedures
1859 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1860 char *selected_fen_position=NULL;
1863 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1864 Atom *type_return, XtPointer *value_return,
1865 unsigned long *length_return, int *format_return)
1867 char *selection_tmp;
1869 // if (!selected_fen_position) return False; /* should never happen */
1870 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1871 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1872 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1875 if (f == NULL) return False;
1879 selection_tmp = XtMalloc(len + 1);
1880 count = fread(selection_tmp, 1, len, f);
1883 XtFree(selection_tmp);
1886 selection_tmp[len] = NULLCHAR;
1888 /* note: since no XtSelectionDoneProc was registered, Xt will
1889 * automatically call XtFree on the value returned. So have to
1890 * make a copy of it allocated with XtMalloc */
1891 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1892 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1895 *value_return=selection_tmp;
1896 *length_return=strlen(selection_tmp);
1897 *type_return=*target;
1898 *format_return = 8; /* bits per byte */
1900 } else if (*target == XA_TARGETS(xDisplay)) {
1901 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1902 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1903 targets_tmp[1] = XA_STRING;
1904 *value_return = targets_tmp;
1905 *type_return = XA_ATOM;
1908 // This code leads to a read of value_return out of bounds on 64-bit systems.
1909 // Other code which I have seen always sets *format_return to 32 independent of
1910 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1911 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1912 *format_return = 8 * sizeof(Atom);
1913 if (*format_return > 32) {
1914 *length_return *= *format_return / 32;
1915 *format_return = 32;
1918 *format_return = 32;
1926 /* note: when called from menu all parameters are NULL, so no clue what the
1927 * Widget which was clicked on was, or what the click event was
1930 CopySomething (char *src)
1932 selected_fen_position = src;
1934 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1935 * have a notion of a position that is selected but not copied.
1936 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1938 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1940 SendPositionSelection,
1941 NULL/* lose_ownership_proc */ ,
1942 NULL/* transfer_done_proc */);
1943 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1945 SendPositionSelection,
1946 NULL/* lose_ownership_proc */ ,
1947 NULL/* transfer_done_proc */);
1950 /* function called when the data to Paste is ready */
1952 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1953 Atom *type, XtPointer value, unsigned long *len, int *format)
1956 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1957 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
1958 EditPositionPasteFEN(fenstr);
1962 /* called when Paste Position button is pressed,
1963 * all parameters will be NULL */
1965 PastePositionProc ()
1967 XtGetSelectionValue(menuBarWidget,
1968 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
1969 /* (XtSelectionCallbackProc) */ PastePositionCB,
1970 NULL, /* client_data passed to PastePositionCB */
1972 /* better to use the time field from the event that triggered the
1973 * call to this function, but that isn't trivial to get
1980 /* note: when called from menu all parameters are NULL, so no clue what the
1981 * Widget which was clicked on was, or what the click event was
1983 /* function called when the data to Paste is ready */
1985 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
1986 Atom *type, XtPointer value, unsigned long *len, int *format)
1989 if (value == NULL || *len == 0) {
1990 return; /* nothing had been selected to copy */
1992 f = fopen(gamePasteFilename, "w");
1994 DisplayError(_("Can't open temp file"), errno);
1997 fwrite(value, 1, *len, f);
2000 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2003 /* called when Paste Game button is pressed,
2004 * all parameters will be NULL */
2008 XtGetSelectionValue(menuBarWidget,
2009 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2010 /* (XtSelectionCallbackProc) */ PasteGameCB,
2011 NULL, /* client_data passed to PasteGameCB */
2013 /* better to use the time field from the event that triggered the
2014 * call to this function, but that isn't trivial to get
2023 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2030 { // bassic primitive for determining if modifier keys are pressed
2031 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2034 XQueryKeymap(xDisplay,keys);
2035 for(i=0; i<6; i++) {
2037 j = XKeysymToKeycode(xDisplay, codes[i]);
2038 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2044 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2048 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2049 if ( n == 1 && *buf >= 32 // printable
2050 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2051 ) BoxAutoPopUp (buf);
2055 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2056 { // [HGM] input: let up-arrow recall previous line from history
2061 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2062 { // [HGM] input: let down-arrow recall next line from history
2067 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2073 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2075 if (!TempBackwardActive) {
2076 TempBackwardActive = True;
2082 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2084 /* Check to see if triggered by a key release event for a repeating key.
2085 * If so the next queued event will be a key press of the same key at the same time */
2086 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2088 XPeekEvent(xDisplay, &next);
2089 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2090 next.xkey.keycode == event->xkey.keycode)
2094 TempBackwardActive = False;
2098 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2099 { // called as key binding
2102 if (nprms && *nprms > 0)
2106 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2112 { // called from menu
2113 ManInner(NULL, NULL, NULL, NULL);
2117 SetWindowTitle (char *text, char *title, char *icon)
2121 if (appData.titleInWindow) {
2123 XtSetArg(args[i], XtNlabel, text); i++;
2124 XtSetValues(titleWidget, args, i);
2127 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2128 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2129 XtSetValues(shellWidget, args, i);
2130 XSync(xDisplay, False);
2135 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2141 DisplayIcsInteractionTitle (String message)
2143 if (oldICSInteractionTitle == NULL) {
2144 /* Magic to find the old window title, adapted from vim */
2145 char *wina = getenv("WINDOWID");
2147 Window win = (Window) atoi(wina);
2148 Window root, parent, *children;
2149 unsigned int nchildren;
2150 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2152 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2153 if (!XQueryTree(xDisplay, win, &root, &parent,
2154 &children, &nchildren)) break;
2155 if (children) XFree((void *)children);
2156 if (parent == root || parent == 0) break;
2159 XSetErrorHandler(oldHandler);
2161 if (oldICSInteractionTitle == NULL) {
2162 oldICSInteractionTitle = "xterm";
2165 printf("\033]0;%s\007", message);
2170 XtIntervalId delayedEventTimerXID = 0;
2171 DelayedEventCallback delayedEventCallback = 0;
2176 delayedEventTimerXID = 0;
2177 delayedEventCallback();
2181 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2183 if(delayedEventTimerXID && delayedEventCallback == cb)
2184 // [HGM] alive: replace, rather than add or flush identical event
2185 XtRemoveTimeOut(delayedEventTimerXID);
2186 delayedEventCallback = cb;
2187 delayedEventTimerXID =
2188 XtAppAddTimeOut(appContext, millisec,
2189 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2192 DelayedEventCallback
2195 if (delayedEventTimerXID) {
2196 return delayedEventCallback;
2203 CancelDelayedEvent ()
2205 if (delayedEventTimerXID) {
2206 XtRemoveTimeOut(delayedEventTimerXID);
2207 delayedEventTimerXID = 0;
2211 XtIntervalId loadGameTimerXID = 0;
2214 LoadGameTimerRunning ()
2216 return loadGameTimerXID != 0;
2220 StopLoadGameTimer ()
2222 if (loadGameTimerXID != 0) {
2223 XtRemoveTimeOut(loadGameTimerXID);
2224 loadGameTimerXID = 0;
2232 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2234 loadGameTimerXID = 0;
2239 StartLoadGameTimer (long millisec)
2242 XtAppAddTimeOut(appContext, millisec,
2243 (XtTimerCallbackProc) LoadGameTimerCallback,
2247 XtIntervalId analysisClockXID = 0;
2250 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2252 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2253 || appData.icsEngineAnalyze) { // [DM]
2254 AnalysisPeriodicEvent(0);
2255 StartAnalysisClock();
2260 StartAnalysisClock ()
2263 XtAppAddTimeOut(appContext, 2000,
2264 (XtTimerCallbackProc) AnalysisClockCallback,
2268 XtIntervalId clockTimerXID = 0;
2271 ClockTimerRunning ()
2273 return clockTimerXID != 0;
2279 if (clockTimerXID != 0) {
2280 XtRemoveTimeOut(clockTimerXID);
2289 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2296 StartClockTimer (long millisec)
2299 XtAppAddTimeOut(appContext, millisec,
2300 (XtTimerCallbackProc) ClockTimerCallback,
2305 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2309 Widget w = (Widget) opt->handle;
2311 /* check for low time warning */
2312 Pixel foregroundOrWarningColor = timerForegroundPixel;
2315 appData.lowTimeWarning &&
2316 (timer / 1000) < appData.icsAlarmTime)
2317 foregroundOrWarningColor = lowTimeWarningColor;
2319 if (appData.clockMode) {
2320 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2321 XtSetArg(args[0], XtNlabel, buf);
2323 snprintf(buf, MSG_SIZ, "%s ", color);
2324 XtSetArg(args[0], XtNlabel, buf);
2329 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2330 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2332 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2333 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2336 XtSetValues(w, args, 3);
2339 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2342 SetClockIcon (int color)
2345 Pixmap pm = *clockIcons[color];
2346 if (iconPixmap != pm) {
2348 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2349 XtSetValues(shellWidget, args, 1);
2353 #define INPUT_SOURCE_BUF_SIZE 8192
2362 char buf[INPUT_SOURCE_BUF_SIZE];
2367 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2369 InputSource *is = (InputSource *) closure;
2374 if (is->lineByLine) {
2375 count = read(is->fd, is->unused,
2376 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2378 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2381 is->unused += count;
2383 while (p < is->unused) {
2384 q = memchr(p, '\n', is->unused - p);
2385 if (q == NULL) break;
2387 (is->func)(is, is->closure, p, q - p, 0);
2391 while (p < is->unused) {
2396 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2401 (is->func)(is, is->closure, is->buf, count, error);
2406 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2409 ChildProc *cp = (ChildProc *) pr;
2411 is = (InputSource *) calloc(1, sizeof(InputSource));
2412 is->lineByLine = lineByLine;
2416 is->fd = fileno(stdin);
2418 is->kind = cp->kind;
2419 is->fd = cp->fdFrom;
2422 is->unused = is->buf;
2425 is->xid = XtAppAddInput(appContext, is->fd,
2426 (XtPointer) (XtInputReadMask),
2427 (XtInputCallbackProc) DoInputCallback,
2429 is->closure = closure;
2430 return (InputSourceRef) is;
2434 RemoveInputSource (InputSourceRef isr)
2436 InputSource *is = (InputSource *) isr;
2438 if (is->xid == 0) return;
2439 XtRemoveInput(is->xid);
2445 static Boolean frameWaiting;
2448 FrameAlarm (int sig)
2450 frameWaiting = False;
2451 /* In case System-V style signals. Needed?? */
2452 signal(SIGALRM, FrameAlarm);
2456 FrameDelay (int time)
2458 struct itimerval delay;
2460 XSync(xDisplay, False);
2463 frameWaiting = True;
2464 signal(SIGALRM, FrameAlarm);
2465 delay.it_interval.tv_sec =
2466 delay.it_value.tv_sec = time / 1000;
2467 delay.it_interval.tv_usec =
2468 delay.it_value.tv_usec = (time % 1000) * 1000;
2469 setitimer(ITIMER_REAL, &delay, NULL);
2470 while (frameWaiting) pause();
2471 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2472 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2473 setitimer(ITIMER_REAL, &delay, NULL);
2480 FrameDelay (int time)
2482 XSync(xDisplay, False);
2484 usleep(time * 1000);
2490 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2492 char buf[MSG_SIZ], *logoName = buf;
2493 if(appData.logo[n][0]) {
2494 logoName = appData.logo[n];
2495 } else if(appData.autoLogo) {
2496 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2497 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2498 } else if(appData.directory[n] && appData.directory[n][0]) {
2499 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2503 { ASSIGN(cps->programLogo, logoName); }
2507 UpdateLogos (int displ)
2509 if(optList[W_WHITE-1].handle == NULL) return;
2510 LoadLogo(&first, 0, 0);
2511 LoadLogo(&second, 1, appData.icsActive);
2512 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);