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 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"
204 #include "xgamelist.h"
205 #include "xhistory.h"
209 #include "engineoutput.h"
219 #define usleep(t) _sleep2(((t)+500)/1000)
223 # define _(s) gettext (s)
224 # define N_(s) gettext_noop (s)
230 int main P((int argc, char **argv));
231 RETSIGTYPE CmailSigHandler P((int sig));
232 RETSIGTYPE IntSigHandler P((int sig));
233 RETSIGTYPE TermSizeSigHandler P((int sig));
234 Widget CreateMenuBar P((Menu *mb, int boardWidth));
236 char *InsertPxlSize P((char *pattern, int targetPxlSize));
237 XFontSet CreateFontSet P((char *base_fnt_lst));
239 char *FindFont P((char *pattern, int targetPxlSize));
241 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
242 u_int wreq, u_int hreq));
243 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
244 void DelayedDrag P((void));
245 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
246 void HandlePV P((Widget w, XEvent * event,
247 String * params, Cardinal * nParams));
248 void DrawPositionProc P((Widget w, XEvent *event,
249 String *prms, Cardinal *nprms));
250 void CommentClick P((Widget w, XEvent * event,
251 String * params, Cardinal * nParams));
252 void ICSInputBoxPopUp P((void));
253 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
254 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
255 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
257 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
258 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
259 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
260 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
261 Boolean TempBackwardActive = False;
262 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
263 void DisplayMove P((int moveNumber));
264 void ICSInitScript P((void));
265 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
266 void update_ics_width P(());
267 int CopyMemoProc P(());
270 * XBoard depends on Xt R4 or higher
272 int xtVersion = XtSpecificationRelease;
278 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
279 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
280 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
282 XFontSet fontSet, clockFontSet;
285 XFontStruct *clockFontStruct;
287 Font coordFontID, countFontID;
288 XFontStruct *coordFontStruct, *countFontStruct;
289 XtAppContext appContext;
291 void *shellWidget, *formWidget, *boardWidget, *titleWidget, *dropMenu, *menuBarWidget;
294 Option *optList; // contains all widgets of main window
297 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
299 Position commentX = -1, commentY = -1;
300 Dimension commentW, commentH;
301 typedef unsigned int BoardSize;
303 Boolean chessProgram;
305 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
306 int smallLayout = 0, tinyLayout = 0,
307 marginW, marginH, // [HGM] for run-time resizing
308 fromX = -1, fromY = -1, toX, toY, commentUp = False,
309 errorExitStatus = -1, defaultLineGap;
310 Dimension textHeight;
311 Pixel timerForegroundPixel, timerBackgroundPixel;
312 Pixel buttonForegroundPixel, buttonBackgroundPixel;
313 char *chessDir, *programName, *programVersion;
314 Boolean alwaysOnTop = False;
315 char *icsTextMenuString;
317 char *firstChessProgramNames;
318 char *secondChessProgramNames;
320 WindowPlacement wpMain;
321 WindowPlacement wpConsole;
322 WindowPlacement wpComment;
323 WindowPlacement wpMoveHistory;
324 WindowPlacement wpEvalGraph;
325 WindowPlacement wpEngineOutput;
326 WindowPlacement wpGameList;
327 WindowPlacement wpTags;
329 #define INPUT_SOURCE_BUF_SIZE 8192
338 char buf[INPUT_SOURCE_BUF_SIZE];
343 /* This magic number is the number of intermediate frames used
344 in each half of the animation. For short moves it's reduced
345 by 1. The total number of frames will be factor * 2 + 1. */
348 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
355 DropMenuEnables dmEnables[] = {
373 XtResource clientResources[] = {
374 { "flashCount", "flashCount", XtRInt, sizeof(int),
375 XtOffset(AppDataPtr, flashCount), XtRImmediate,
376 (XtPointer) FLASH_COUNT },
379 XrmOptionDescRec shellOptions[] = {
380 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
381 { "-flash", "flashCount", XrmoptionNoArg, "3" },
382 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
385 XtActionsRec boardActions[] = {
386 { "DrawPosition", DrawPositionProc },
387 { "HandlePV", HandlePV },
388 { "SelectPV", SelectPV },
389 { "StopPV", StopPV },
390 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
391 { "QuitProc", QuitWrapper },
392 { "ManProc", ManInner },
393 { "TempBackwardProc", TempBackwardProc },
394 { "TempForwardProc", TempForwardProc },
395 { "CommentClick", (XtActionProc) CommentClick },
396 { "GenericPopDown", (XtActionProc) GenericPopDown },
397 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
398 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
399 { "SelectMove", (XtActionProc) SelectMove },
400 { "LoadSelectedProc", LoadSelectedProc },
401 { "SetFilterProc", SetFilterProc },
402 { "TypeInProc", TypeInProc },
403 { "EnterKeyProc", EnterKeyProc },
404 { "UpKeyProc", UpKeyProc },
405 { "DownKeyProc", DownKeyProc },
406 { "WheelProc", WheelProc },
407 { "TabProc", TabProc },
411 char globalTranslations[] =
412 ":<Key>F9: MenuItem(Actions.Resign) \n \
413 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
414 :Meta<Key>V: MenuItem(File.NewVariant) \n \
415 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
416 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
417 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
418 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
419 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
420 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
421 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
422 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
423 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
424 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
425 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
426 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
427 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
428 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
429 :Ctrl<Key>q: MenuItem(File.Quit) \n \
430 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
431 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
432 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
433 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
434 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
435 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
436 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
437 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
438 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
439 :Meta<Key>G: MenuItem(View.GameList) \n \
440 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
441 :<Key>Pause: MenuItem(Mode.Pause) \n \
442 :<Key>F3: MenuItem(Action.Accept) \n \
443 :<Key>F4: MenuItem(Action.Decline) \n \
444 :<Key>F12: MenuItem(Action.Rematch) \n \
445 :<Key>F5: MenuItem(Action.CallFlag) \n \
446 :<Key>F6: MenuItem(Action.Draw) \n \
447 :<Key>F7: MenuItem(Action.Adjourn) \n \
448 :<Key>F8: MenuItem(Action.Abort) \n \
449 :<Key>F10: MenuItem(Action.StopObserving) \n \
450 :<Key>F11: MenuItem(Action.StopExamining) \n \
451 :Ctrl<Key>d: MenuItem(DebugProc) \n \
452 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
453 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
454 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
455 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
456 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
457 :<Key>Left: MenuItem(Edit.Backward) \n \
458 :<Key>Right: MenuItem(Edit.Forward) \n \
459 :<Key>Home: MenuItem(Edit.Revert) \n \
460 :<Key>End: MenuItem(Edit.TruncateGame) \n \
461 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
462 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
463 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
464 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
465 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
466 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
467 #ifndef OPTIONSDIALOG
469 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
470 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
471 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
472 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
473 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
476 :<Key>F1: MenuItem(Help.ManXBoard) \n \
477 :<Key>F2: MenuItem(View.FlipView) \n \
478 :<KeyDown>Return: TempBackwardProc() \n \
479 :<KeyUp>Return: TempForwardProc() \n";
481 char ICSInputTranslations[] =
482 "<Key>Up: UpKeyProc() \n "
483 "<Key>Down: DownKeyProc() \n "
484 "<Key>Return: EnterKeyProc() \n";
486 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
487 // as the widget is destroyed before the up-click can call extend-end
488 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
491 String xboardResources[] = {
492 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
497 /* Max possible square size */
498 #define MAXSQSIZE 256
500 static int xpm_avail[MAXSQSIZE];
502 #ifdef HAVE_DIR_STRUCT
504 /* Extract piece size from filename */
506 xpm_getsize (char *name, int len, char *ext)
514 if ((p=strchr(name, '.')) == NULL ||
515 StrCaseCmp(p+1, ext) != 0)
521 while (*p && isdigit(*p))
528 /* Setup xpm_avail */
530 xpm_getavail (char *dirname, char *ext)
536 for (i=0; i<MAXSQSIZE; ++i)
539 if (appData.debugMode)
540 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
542 dir = opendir(dirname);
545 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
546 programName, dirname);
550 while ((ent=readdir(dir)) != NULL) {
551 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
552 if (i > 0 && i < MAXSQSIZE)
562 xpm_print_avail (FILE *fp, char *ext)
566 fprintf(fp, _("Available `%s' sizes:\n"), ext);
567 for (i=1; i<MAXSQSIZE; ++i) {
573 /* Return XPM piecesize closest to size */
575 xpm_closest_to (char *dirname, int size, char *ext)
578 int sm_diff = MAXSQSIZE;
582 xpm_getavail(dirname, ext);
584 if (appData.debugMode)
585 xpm_print_avail(stderr, ext);
587 for (i=1; i<MAXSQSIZE; ++i) {
590 diff = (diff<0) ? -diff : diff;
591 if (diff < sm_diff) {
599 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
605 #else /* !HAVE_DIR_STRUCT */
606 /* If we are on a system without a DIR struct, we can't
607 read the directory, so we can't collect a list of
608 filenames, etc., so we can't do any size-fitting. */
610 xpm_closest_to (char *dirname, int size, char *ext)
613 Warning: No DIR structure found on this system --\n\
614 Unable to autosize for XPM/XIM pieces.\n\
615 Please report this error to %s.\n\
616 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
619 #endif /* HAVE_DIR_STRUCT */
623 /* Arrange to catch delete-window events */
624 Atom wm_delete_window;
626 CatchDeleteWindow (Widget w, String procname)
629 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
630 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
631 XtAugmentTranslations(w, XtParseTranslationTable(buf));
640 XtSetArg(args[0], XtNiconic, False);
641 XtSetValues(shellWidget, args, 1);
643 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
647 //---------------------------------------------------------------------------------------------------------
648 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
651 #define CW_USEDEFAULT (1<<31)
652 #define ICS_TEXT_MENU_SIZE 90
653 #define DEBUG_FILE "xboard.debug"
654 #define SetCurrentDirectory chdir
655 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
659 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
662 // front-end part of option handling
664 // [HGM] This platform-dependent table provides the location for storing the color info
665 extern char *crWhite, * crBlack;
669 &appData.whitePieceColor,
670 &appData.blackPieceColor,
671 &appData.lightSquareColor,
672 &appData.darkSquareColor,
673 &appData.highlightSquareColor,
674 &appData.premoveHighlightColor,
675 &appData.lowTimeWarningColor,
686 // [HGM] font: keep a font for each square size, even non-stndard ones
689 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
690 char *fontTable[NUM_FONTS][MAX_SIZE];
693 ParseFont (char *name, int number)
694 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
696 if(sscanf(name, "size%d:", &size)) {
697 // [HGM] font: font is meant for specific boardSize (likely from settings file);
698 // defer processing it until we know if it matches our board size
699 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
700 fontTable[number][size] = strdup(strchr(name, ':')+1);
701 fontValid[number][size] = True;
706 case 0: // CLOCK_FONT
707 appData.clockFont = strdup(name);
709 case 1: // MESSAGE_FONT
710 appData.font = strdup(name);
712 case 2: // COORD_FONT
713 appData.coordFont = strdup(name);
718 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
723 { // only 2 fonts currently
724 appData.clockFont = CLOCK_FONT_NAME;
725 appData.coordFont = COORD_FONT_NAME;
726 appData.font = DEFAULT_FONT_NAME;
731 { // no-op, until we identify the code for this already in XBoard and move it here
735 ParseColor (int n, char *name)
736 { // in XBoard, just copy the color-name string
737 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
741 ParseTextAttribs (ColorClass cc, char *s)
743 (&appData.colorShout)[cc] = strdup(s);
747 ParseBoardSize (void *addr, char *name)
749 appData.boardSize = strdup(name);
754 { // In XBoard the sound-playing program takes care of obtaining the actual sound
758 SetCommPortDefaults ()
759 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
762 // [HGM] args: these three cases taken out to stay in front-end
764 SaveFontArg (FILE *f, ArgDescriptor *ad)
767 int i, n = (int)(intptr_t)ad->argLoc;
769 case 0: // CLOCK_FONT
770 name = appData.clockFont;
772 case 1: // MESSAGE_FONT
775 case 2: // COORD_FONT
776 name = appData.coordFont;
781 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
782 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
783 fontTable[n][squareSize] = strdup(name);
784 fontValid[n][squareSize] = True;
787 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
788 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
793 { // nothing to do, as the sounds are at all times represented by their text-string names already
797 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
798 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
799 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
803 SaveColor (FILE *f, ArgDescriptor *ad)
804 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
805 if(colorVariable[(int)(intptr_t)ad->argLoc])
806 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
810 SaveBoardSize (FILE *f, char *name, void *addr)
811 { // wrapper to shield back-end from BoardSize & sizeInfo
812 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
816 ParseCommPortSettings (char *s)
817 { // no such option in XBoard (yet)
824 GetActualPlacement (Widget wg, WindowPlacement *wp)
826 XWindowAttributes winAt;
833 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
834 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
835 wp->x = rx - winAt.x;
836 wp->y = ry - winAt.y;
837 wp->height = winAt.height;
838 wp->width = winAt.width;
839 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
845 { // wrapper to shield use of window handles from back-end (make addressible by number?)
846 // In XBoard this will have to wait until awareness of window parameters is implemented
848 GetActualPlacement(shellWidget, &wpMain);
849 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
850 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
851 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
852 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
853 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
854 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
859 PrintCommPortSettings (FILE *f, char *name)
860 { // This option does not exist in XBoard
864 EnsureOnScreen (int *x, int *y, int minX, int minY)
871 { // [HGM] args: allows testing if main window is realized from back-end
873 return xBoardWindow != 0;
880 PopUpStartupDialog ()
881 { // start menu not implemented in XBoard
885 ConvertToLine (int argc, char **argv)
887 static char line[128*1024], buf[1024];
891 for(i=1; i<argc; i++)
893 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
894 && argv[i][0] != '{' )
895 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
897 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
898 strncat(line, buf, 128*1024 - strlen(line) - 1 );
901 line[strlen(line)-1] = NULLCHAR;
905 //--------------------------------------------------------------------------------------------
908 ResizeBoardWindow (int w, int h, int inhibit)
911 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
913 shellArgs[0].value = w;
914 shellArgs[1].value = h;
915 shellArgs[4].value = shellArgs[2].value = w;
916 shellArgs[5].value = shellArgs[3].value = h;
917 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
919 XSync(xDisplay, False);
925 MakeOneColor (char *name, Pixel *color)
928 if (!appData.monoMode) {
929 vFrom.addr = (caddr_t) name;
930 vFrom.size = strlen(name);
931 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
932 if (vTo.addr == NULL) {
933 appData.monoMode = True;
936 *color = *(Pixel *) vTo.addr;
945 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
946 int forceMono = False;
949 if (appData.lowTimeWarning)
950 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
951 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
952 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
959 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
960 { // detervtomine what fonts to use, and create them
965 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
966 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
967 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
968 appData.font = fontTable[MESSAGE_FONT][squareSize];
969 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
970 appData.coordFont = fontTable[COORD_FONT][squareSize];
973 appData.font = InsertPxlSize(appData.font, fontPxlSize);
974 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
975 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
976 fontSet = CreateFontSet(appData.font);
977 clockFontSet = CreateFontSet(appData.clockFont);
979 /* For the coordFont, use the 0th font of the fontset. */
980 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
981 XFontStruct **font_struct_list;
982 XFontSetExtents *fontSize;
983 char **font_name_list;
984 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
985 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
986 coordFontStruct = XQueryFont(xDisplay, coordFontID);
987 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
988 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
991 appData.font = FindFont(appData.font, fontPxlSize);
992 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
993 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
994 clockFontID = XLoadFont(xDisplay, appData.clockFont);
995 clockFontStruct = XQueryFont(xDisplay, clockFontID);
996 coordFontID = XLoadFont(xDisplay, appData.coordFont);
997 coordFontStruct = XQueryFont(xDisplay, coordFontID);
998 // textHeight in !NLS mode!
1000 countFontID = coordFontID; // [HGM] holdings
1001 countFontStruct = coordFontStruct;
1003 xdb = XtDatabase(xDisplay);
1005 XrmPutLineResource(&xdb, "*international: True");
1006 vTo.size = sizeof(XFontSet);
1007 vTo.addr = (XtPointer) &fontSet;
1008 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
1010 XrmPutStringResource(&xdb, "*font", appData.font);
1016 PrintArg (ArgType t)
1021 case ArgInt: p = " N"; break;
1022 case ArgString: p = " STR"; break;
1023 case ArgBoolean: p = " TF"; break;
1024 case ArgSettingsFilename:
1025 case ArgFilename: p = " FILE"; break;
1026 case ArgX: p = " Nx"; break;
1027 case ArgY: p = " Ny"; break;
1028 case ArgAttribs: p = " TEXTCOL"; break;
1029 case ArgColor: p = " COL"; break;
1030 case ArgFont: p = " FONT"; break;
1031 case ArgBoardSize: p = " SIZE"; break;
1032 case ArgFloat: p = " FLOAT"; break;
1037 case ArgCommSettings:
1048 ArgDescriptor *q, *p = argDescriptors+5;
1049 printf("\nXBoard accepts the following options:\n"
1050 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1051 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1052 " SIZE = board-size spec(s)\n"
1053 " Within parentheses are short forms, or options to set to true or false.\n"
1054 " Persistent options (saved in the settings file) are marked with *)\n\n");
1056 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1057 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1058 if(p->save) strcat(buf+len, "*");
1059 for(q=p+1; q->argLoc == p->argLoc; q++) {
1060 if(q->argName[0] == '-') continue;
1061 strcat(buf+len, q == p+1 ? " (" : " ");
1062 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1064 if(q != p+1) strcat(buf+len, ")");
1066 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1069 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1073 main (int argc, char **argv)
1075 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1077 XSetWindowAttributes window_attributes;
1079 Dimension boardWidth, boardHeight, w, h;
1081 int boardWidth, boardHeight, w, h;
1084 int forceMono = False;
1086 srandom(time(0)); // [HGM] book: make random truly random
1088 setbuf(stdout, NULL);
1089 setbuf(stderr, NULL);
1092 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1093 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1097 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1102 programName = strrchr(argv[0], '/');
1103 if (programName == NULL)
1104 programName = argv[0];
1109 XtSetLanguageProc(NULL, NULL, NULL);
1110 if (appData.debugMode) {
1111 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1114 bindtextdomain(PACKAGE, LOCALEDIR);
1115 textdomain(PACKAGE);
1118 appData.boardSize = "";
1119 InitAppData(ConvertToLine(argc, argv));
1121 if (p == NULL) p = "/tmp";
1122 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1123 gameCopyFilename = (char*) malloc(i);
1124 gamePasteFilename = (char*) malloc(i);
1125 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1126 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1128 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1129 static char buf[MSG_SIZ];
1130 EscapeExpand(buf, appData.firstInitString);
1131 appData.firstInitString = strdup(buf);
1132 EscapeExpand(buf, appData.secondInitString);
1133 appData.secondInitString = strdup(buf);
1134 EscapeExpand(buf, appData.firstComputerString);
1135 appData.firstComputerString = strdup(buf);
1136 EscapeExpand(buf, appData.secondComputerString);
1137 appData.secondComputerString = strdup(buf);
1140 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1143 if (chdir(chessDir) != 0) {
1144 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1150 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1151 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1152 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1153 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1156 setbuf(debugFP, NULL);
1159 /* [HGM,HR] make sure board size is acceptable */
1160 if(appData.NrFiles > BOARD_FILES ||
1161 appData.NrRanks > BOARD_RANKS )
1162 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1165 /* This feature does not work; animation needs a rewrite */
1166 appData.highlightDragging = FALSE;
1170 gameInfo.variant = StringToVariant(appData.variant);
1171 InitPosition(FALSE);
1175 XtAppInitialize(&appContext, "XBoard", shellOptions,
1176 XtNumber(shellOptions),
1177 &argc, argv, xboardResources, NULL, 0);
1179 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1180 clientResources, XtNumber(clientResources),
1183 xDisplay = XtDisplay(shellWidget);
1184 xScreen = DefaultScreen(xDisplay);
1185 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1189 * determine size, based on supplied or remembered -size, or screen size
1191 if (isdigit(appData.boardSize[0])) {
1192 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1193 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1194 &fontPxlSize, &smallLayout, &tinyLayout);
1196 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1197 programName, appData.boardSize);
1201 /* Find some defaults; use the nearest known size */
1202 SizeDefaults *szd, *nearest;
1203 int distance = 99999;
1204 nearest = szd = sizeDefaults;
1205 while (szd->name != NULL) {
1206 if (abs(szd->squareSize - squareSize) < distance) {
1208 distance = abs(szd->squareSize - squareSize);
1209 if (distance == 0) break;
1213 if (i < 2) lineGap = nearest->lineGap;
1214 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1215 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1216 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1217 if (i < 6) smallLayout = nearest->smallLayout;
1218 if (i < 7) tinyLayout = nearest->tinyLayout;
1221 SizeDefaults *szd = sizeDefaults;
1222 if (*appData.boardSize == NULLCHAR) {
1224 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1225 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1229 if (szd->name == NULL) szd--;
1230 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1232 while (szd->name != NULL &&
1233 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1234 if (szd->name == NULL) {
1235 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1236 programName, appData.boardSize);
1240 squareSize = szd->squareSize;
1241 lineGap = szd->lineGap;
1242 clockFontPxlSize = szd->clockFontPxlSize;
1243 coordFontPxlSize = szd->coordFontPxlSize;
1244 fontPxlSize = szd->fontPxlSize;
1245 smallLayout = szd->smallLayout;
1246 tinyLayout = szd->tinyLayout;
1247 // [HGM] font: use defaults from settings file if available and not overruled
1250 defaultLineGap = lineGap;
1251 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1253 /* [HR] height treated separately (hacked) */
1254 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1255 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1258 * Determine what fonts to use.
1261 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1265 * Detect if there are not enough colors available and adapt.
1268 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1269 appData.monoMode = True;
1273 forceMono = MakeColors();
1276 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1278 appData.monoMode = True;
1281 if (appData.monoMode && appData.debugMode) {
1283 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1284 (unsigned long) XWhitePixel(xDisplay, xScreen),
1285 (unsigned long) XBlackPixel(xDisplay, xScreen));
1289 ParseIcsTextColors();
1292 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1299 layoutName = "tinyLayout";
1300 } else if (smallLayout) {
1301 layoutName = "smallLayout";
1303 layoutName = "normalLayout";
1306 optList = BoardPopUp(squareSize, lineGap, (void*)
1316 InitDrawingHandle(optList + W_BOARD);
1317 currBoard = &optList[W_BOARD];
1318 boardWidget = optList[W_BOARD].handle;
1319 menuBarWidget = optList[W_MENU].handle;
1320 dropMenu = optList[W_DROP].handle;
1321 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1322 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 AppendEnginesToMenu(appData.recentEngineList);
1336 xBoardWindow = XtWindow(boardWidget);
1339 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1340 // not need to go into InitDrawingSizes().
1343 * Create X checkmark bitmap and initialize option menu checks.
1346 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1347 checkmark_bits, checkmark_width, checkmark_height);
1355 ReadBitmap(&wIconPixmap, "icon_white.bm",
1356 icon_white_bits, icon_white_width, icon_white_height);
1357 ReadBitmap(&bIconPixmap, "icon_black.bm",
1358 icon_black_bits, icon_black_width, icon_black_height);
1359 iconPixmap = wIconPixmap;
1361 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1362 XtSetValues(shellWidget, args, i);
1366 * Create a cursor for the board widget.
1369 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1370 XChangeWindowAttributes(xDisplay, xBoardWindow,
1371 CWCursor, &window_attributes);
1375 * Inhibit shell resizing.
1378 shellArgs[0].value = (XtArgVal) &w;
1379 shellArgs[1].value = (XtArgVal) &h;
1380 XtGetValues(shellWidget, shellArgs, 2);
1381 shellArgs[4].value = shellArgs[2].value = w;
1382 shellArgs[5].value = shellArgs[3].value = h;
1383 // XtSetValues(shellWidget, &shellArgs[2], 4);
1385 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1386 marginH = h - boardHeight;
1389 CatchDeleteWindow(shellWidget, "QuitProc");
1395 if(appData.logoSize)
1396 { // locate and read user logo
1398 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1399 ASSIGN(userLogo, buf);
1402 if (appData.animate || appData.animateDragging)
1406 XtAugmentTranslations(formWidget,
1407 XtParseTranslationTable(globalTranslations));
1409 XtAddEventHandler(formWidget, KeyPressMask, False,
1410 (XtEventHandler) MoveTypeInProc, NULL);
1411 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1412 (XtEventHandler) EventProc, NULL);
1415 /* [AS] Restore layout */
1416 if( wpMoveHistory.visible ) {
1420 if( wpEvalGraph.visible )
1425 if( wpEngineOutput.visible ) {
1426 EngineOutputPopUp();
1431 if (errorExitStatus == -1) {
1432 if (appData.icsActive) {
1433 /* We now wait until we see "login:" from the ICS before
1434 sending the logon script (problems with timestamp otherwise) */
1435 /*ICSInitScript();*/
1436 if (appData.icsInputBox) ICSInputBoxPopUp();
1440 signal(SIGWINCH, TermSizeSigHandler);
1442 signal(SIGINT, IntSigHandler);
1443 signal(SIGTERM, IntSigHandler);
1444 if (*appData.cmailGameName != NULLCHAR) {
1445 signal(SIGUSR1, CmailSigHandler);
1449 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1452 // XtSetKeyboardFocus(shellWidget, formWidget);
1454 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1456 XtAppMainLoop(appContext);
1458 if (appData.debugMode) fclose(debugFP); // [DM] debug
1463 TermSizeSigHandler (int sig)
1469 IntSigHandler (int sig)
1475 CmailSigHandler (int sig)
1480 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1482 /* Activate call-back function CmailSigHandlerCallBack() */
1483 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1485 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1489 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1492 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1494 /**** end signal code ****/
1497 #define Abs(n) ((n)<0 ? -(n) : (n))
1501 InsertPxlSize (char *pattern, int targetPxlSize)
1503 char *base_fnt_lst, strInt[12], *p, *q;
1504 int alternatives, i, len, strIntLen;
1507 * Replace the "*" (if present) in the pixel-size slot of each
1508 * alternative with the targetPxlSize.
1512 while ((p = strchr(p, ',')) != NULL) {
1516 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1517 strIntLen = strlen(strInt);
1518 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1522 while (alternatives--) {
1523 char *comma = strchr(p, ',');
1524 for (i=0; i<14; i++) {
1525 char *hyphen = strchr(p, '-');
1527 if (comma && hyphen > comma) break;
1528 len = hyphen + 1 - p;
1529 if (i == 7 && *p == '*' && len == 2) {
1531 memcpy(q, strInt, strIntLen);
1541 len = comma + 1 - p;
1548 return base_fnt_lst;
1553 CreateFontSet (char *base_fnt_lst)
1556 char **missing_list;
1560 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1561 &missing_list, &missing_count, &def_string);
1562 if (appData.debugMode) {
1564 XFontStruct **font_struct_list;
1565 char **font_name_list;
1566 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1568 fprintf(debugFP, " got list %s, locale %s\n",
1569 XBaseFontNameListOfFontSet(fntSet),
1570 XLocaleOfFontSet(fntSet));
1571 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1572 for (i = 0; i < count; i++) {
1573 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1576 for (i = 0; i < missing_count; i++) {
1577 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1580 if (fntSet == NULL) {
1581 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1587 #else // not ENABLE_NLS
1589 * Find a font that matches "pattern" that is as close as
1590 * possible to the targetPxlSize. Prefer fonts that are k
1591 * pixels smaller to fonts that are k pixels larger. The
1592 * pattern must be in the X Consortium standard format,
1593 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1594 * The return value should be freed with XtFree when no
1598 FindFont (char *pattern, int targetPxlSize)
1600 char **fonts, *p, *best, *scalable, *scalableTail;
1601 int i, j, nfonts, minerr, err, pxlSize;
1604 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1606 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1607 programName, pattern);
1614 for (i=0; i<nfonts; i++) {
1617 if (*p != '-') continue;
1619 if (*p == NULLCHAR) break;
1620 if (*p++ == '-') j++;
1622 if (j < 7) continue;
1625 scalable = fonts[i];
1628 err = pxlSize - targetPxlSize;
1629 if (Abs(err) < Abs(minerr) ||
1630 (minerr > 0 && err < 0 && -err == minerr)) {
1636 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1637 /* If the error is too big and there is a scalable font,
1638 use the scalable font. */
1639 int headlen = scalableTail - scalable;
1640 p = (char *) XtMalloc(strlen(scalable) + 10);
1641 while (isdigit(*scalableTail)) scalableTail++;
1642 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1644 p = (char *) XtMalloc(strlen(best) + 2);
1645 safeStrCpy(p, best, strlen(best)+1 );
1647 if (appData.debugMode) {
1648 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1649 pattern, targetPxlSize, p);
1651 XFreeFontNames(fonts);
1658 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1662 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1669 EnableNamedMenuItem (char *menuRef, int state)
1671 MenuItem *item = MenuNameToItem(menuRef);
1674 if(item) XtSetSensitive(item->handle, state);
1679 EnableButtonBar (int state)
1682 XtSetSensitive(optList[W_BUTTON].handle, state);
1688 SetMenuEnables (Enables *enab)
1690 while (enab->name != NULL) {
1691 EnableNamedMenuItem(enab->name, enab->value);
1698 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1699 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1701 if(*nprms == 0) return;
1702 item = MenuNameToItem(prms[0]);
1703 if(item) ((MenuProc *) item->proc) ();
1709 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1711 RecentEngineEvent((int) (intptr_t) addr);
1716 AppendMenuItem (char *msg, int n)
1719 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1733 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1734 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1735 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1736 dmEnables[i].piece);
1737 XtSetSensitive(entry, p != NULL || !appData.testLegality
1738 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1739 && !appData.icsActive));
1741 while (p && *p++ == dmEnables[i].piece) count++;
1742 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1744 XtSetArg(args[j], XtNlabel, label); j++;
1745 XtSetValues(entry, args, j);
1751 do_flash_delay (unsigned long msec)
1757 FlashDelay (int flash_delay)
1760 XSync(xDisplay, False);
1761 if(flash_delay) do_flash_delay(flash_delay);
1766 Fraction (int x, int start, int stop)
1768 double f = ((double) x - start)/(stop - start);
1769 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1773 static WindowPlacement wpNew;
1777 CoDrag (Widget sh, WindowPlacement *wp)
1780 int j=0, touch=0, fudge = 2;
1781 GetActualPlacement(sh, wp);
1782 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1783 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1784 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1785 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1786 if(!touch ) return; // only windows that touch co-move
1787 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1788 int heightInc = wpNew.height - wpMain.height;
1789 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1790 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1791 wp->y += fracTop * heightInc;
1792 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1793 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1794 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1795 int widthInc = wpNew.width - wpMain.width;
1796 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1797 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1798 wp->y += fracLeft * widthInc;
1799 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1800 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1802 wp->x += wpNew.x - wpMain.x;
1803 wp->y += wpNew.y - wpMain.y;
1804 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1805 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1807 XtSetArg(args[j], XtNx, wp->x); j++;
1808 XtSetArg(args[j], XtNy, wp->y); j++;
1809 XtSetValues(sh, args, j);
1814 ReSize (WindowPlacement *wp)
1817 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1818 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1819 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1820 if(sqy < sqx) sqx = sqy;
1821 if(sqx != squareSize) {
1822 squareSize = sqx; // adopt new square size
1823 CreatePNGPieces(); // make newly scaled pieces
1824 InitDrawingSizes(0, 0); // creates grid etc.
1825 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1826 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1827 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1828 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1829 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1833 static XtIntervalId delayedDragID = 0;
1835 static int delayedDragID = 0;
1845 GetActualPlacement(shellWidget, &wpNew);
1846 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1847 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1848 busy = 0; return; // false alarm
1851 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1852 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1853 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1854 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1856 DrawPosition(True, NULL);
1857 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1866 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1868 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1873 EventProc (Widget widget, caddr_t unused, XEvent *event)
1876 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1877 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1882 * event handler for redrawing the board
1885 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1887 DrawPosition(True, NULL);
1893 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1894 { // [HGM] pv: walk PV
1895 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1899 static int savedIndex; /* gross that this is global */
1902 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1906 XawTextPosition index, dummy;
1909 XawTextGetSelectionPos(w, &index, &dummy);
1910 XtSetArg(arg, XtNstring, &val);
1911 XtGetValues(w, &arg, 1);
1912 ReplaceComment(savedIndex, val);
1913 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1914 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1919 EditCommentPopUp (int index, char *title, char *text)
1922 if (text == NULL) text = "";
1923 NewCommentPopup(title, text, index);
1927 CommentPopUp (char *title, char *text)
1929 savedIndex = currentMove; // [HGM] vari
1930 NewCommentPopup(title, text, currentMove);
1936 PopDown(CommentDlg);
1940 /* Disable all user input other than deleting the window */
1941 static int frozen = 0;
1947 /* Grab by a widget that doesn't accept input */
1948 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1952 /* Undo a FreezeUI */
1956 if (!frozen) return;
1958 XtRemoveGrab(optList[W_MESSG].handle);
1966 static int oldPausing = FALSE;
1967 static GameMode oldmode = (GameMode) -1;
1972 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1974 if (pausing != oldPausing) {
1975 oldPausing = pausing;
1976 MarkMenuItem("Mode.Pause", pausing);
1978 if (appData.showButtonBar) {
1979 /* Always toggle, don't set. Previous code messes up when
1980 invoked while the button is pressed, as releasing it
1981 toggles the state again. */
1984 XtSetArg(args[0], XtNbackground, &oldbg);
1985 XtSetArg(args[1], XtNforeground, &oldfg);
1986 XtGetValues(optList[W_PAUSE].handle,
1988 XtSetArg(args[0], XtNbackground, oldfg);
1989 XtSetArg(args[1], XtNforeground, oldbg);
1991 XtSetValues(optList[W_PAUSE].handle, args, 2);
1996 wname = ModeToWidgetName(oldmode);
1997 if (wname != NULL) {
1998 MarkMenuItem(wname, False);
2000 wname = ModeToWidgetName(gameMode);
2001 if (wname != NULL) {
2002 MarkMenuItem(wname, True);
2005 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
2007 /* Maybe all the enables should be handled here, not just this one */
2008 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
2010 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
2015 * Button/menu procedures
2019 /* this variable is shared between CopyPositionProc and SendPositionSelection */
2020 char *selected_fen_position=NULL;
2023 SendPositionSelection (Widget w, Atom *selection, Atom *target,
2024 Atom *type_return, XtPointer *value_return,
2025 unsigned long *length_return, int *format_return)
2027 char *selection_tmp;
2029 // if (!selected_fen_position) return False; /* should never happen */
2030 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
2031 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
2032 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
2035 if (f == NULL) return False;
2039 selection_tmp = XtMalloc(len + 1);
2040 count = fread(selection_tmp, 1, len, f);
2043 XtFree(selection_tmp);
2046 selection_tmp[len] = NULLCHAR;
2048 /* note: since no XtSelectionDoneProc was registered, Xt will
2049 * automatically call XtFree on the value returned. So have to
2050 * make a copy of it allocated with XtMalloc */
2051 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
2052 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
2055 *value_return=selection_tmp;
2056 *length_return=strlen(selection_tmp);
2057 *type_return=*target;
2058 *format_return = 8; /* bits per byte */
2060 } else if (*target == XA_TARGETS(xDisplay)) {
2061 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
2062 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
2063 targets_tmp[1] = XA_STRING;
2064 *value_return = targets_tmp;
2065 *type_return = XA_ATOM;
2068 // This code leads to a read of value_return out of bounds on 64-bit systems.
2069 // Other code which I have seen always sets *format_return to 32 independent of
2070 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
2071 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
2072 *format_return = 8 * sizeof(Atom);
2073 if (*format_return > 32) {
2074 *length_return *= *format_return / 32;
2075 *format_return = 32;
2078 *format_return = 32;
2087 /* note: when called from menu all parameters are NULL, so no clue what the
2088 * Widget which was clicked on was, or what the click event was
2091 CopySomething (char *src)
2094 selected_fen_position = src;
2096 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
2097 * have a notion of a position that is selected but not copied.
2098 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
2100 XtOwnSelection(menuBarWidget, XA_PRIMARY,
2102 SendPositionSelection,
2103 NULL/* lose_ownership_proc */ ,
2104 NULL/* transfer_done_proc */);
2105 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2107 SendPositionSelection,
2108 NULL/* lose_ownership_proc */ ,
2109 NULL/* transfer_done_proc */);
2114 /* function called when the data to Paste is ready */
2116 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2117 Atom *type, XtPointer value, unsigned long *len, int *format)
2120 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2121 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2122 EditPositionPasteFEN(fenstr);
2127 /* called when Paste Position button is pressed,
2128 * all parameters will be NULL */
2130 PastePositionProc ()
2133 XtGetSelectionValue(menuBarWidget,
2134 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2135 /* (XtSelectionCallbackProc) */ PastePositionCB,
2136 NULL, /* client_data passed to PastePositionCB */
2138 /* better to use the time field from the event that triggered the
2139 * call to this function, but that isn't trivial to get
2148 /* note: when called from menu all parameters are NULL, so no clue what the
2149 * Widget which was clicked on was, or what the click event was
2151 /* function called when the data to Paste is ready */
2153 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2154 Atom *type, XtPointer value, unsigned long *len, int *format)
2157 if (value == NULL || *len == 0) {
2158 return; /* nothing had been selected to copy */
2160 f = fopen(gamePasteFilename, "w");
2162 DisplayError(_("Can't open temp file"), errno);
2165 fwrite(value, 1, *len, f);
2168 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2172 /* called when Paste Game button is pressed,
2173 * all parameters will be NULL */
2178 XtGetSelectionValue(menuBarWidget,
2179 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2180 /* (XtSelectionCallbackProc) */ PasteGameCB,
2181 NULL, /* client_data passed to PasteGameCB */
2183 /* better to use the time field from the event that triggered the
2184 * call to this function, but that isn't trivial to get
2194 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2201 { // bassic primitive for determining if modifier keys are pressed
2204 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2206 XQueryKeymap(xDisplay,keys);
2207 for(i=0; i<6; i++) {
2209 j = XKeysymToKeycode(xDisplay, codes[i]);
2210 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2217 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2222 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2223 if ( n == 1 && *buf >= 32 // printable
2224 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2225 ) BoxAutoPopUp (buf);
2231 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2232 { // [HGM] input: let up-arrow recall previous line from history
2237 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2238 { // [HGM] input: let down-arrow recall next line from history
2243 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2250 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2252 if (!TempBackwardActive) {
2253 TempBackwardActive = True;
2259 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2261 /* Check to see if triggered by a key release event for a repeating key.
2262 * If so the next queued event will be a key press of the same key at the same time */
2263 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2265 XPeekEvent(xDisplay, &next);
2266 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2267 next.xkey.keycode == event->xkey.keycode)
2271 TempBackwardActive = False;
2275 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2276 { // called as key binding
2279 if (nprms && *nprms > 0)
2283 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2290 { // called from menu
2292 ManInner(NULL, NULL, NULL, NULL);
2297 SetWindowTitle (char *text, char *title, char *icon)
2302 if (appData.titleInWindow) {
2304 XtSetArg(args[i], XtNlabel, text); i++;
2305 XtSetValues(titleWidget, args, i);
2308 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2309 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2310 XtSetValues(shellWidget, args, i);
2311 XSync(xDisplay, False);
2317 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2323 DisplayIcsInteractionTitle (String message)
2326 if (oldICSInteractionTitle == NULL) {
2327 /* Magic to find the old window title, adapted from vim */
2328 char *wina = getenv("WINDOWID");
2330 Window win = (Window) atoi(wina);
2331 Window root, parent, *children;
2332 unsigned int nchildren;
2333 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2335 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2336 if (!XQueryTree(xDisplay, win, &root, &parent,
2337 &children, &nchildren)) break;
2338 if (children) XFree((void *)children);
2339 if (parent == root || parent == 0) break;
2342 XSetErrorHandler(oldHandler);
2344 if (oldICSInteractionTitle == NULL) {
2345 oldICSInteractionTitle = "xterm";
2348 printf("\033]0;%s\007", message);
2355 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2360 Widget w = (Widget) opt->handle;
2362 /* check for low time warning */
2363 Pixel foregroundOrWarningColor = timerForegroundPixel;
2366 appData.lowTimeWarning &&
2367 (timer / 1000) < appData.icsAlarmTime)
2368 foregroundOrWarningColor = lowTimeWarningColor;
2370 if (appData.clockMode) {
2371 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2372 XtSetArg(args[0], XtNlabel, buf);
2374 snprintf(buf, MSG_SIZ, "%s ", color);
2375 XtSetArg(args[0], XtNlabel, buf);
2380 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2381 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2383 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2384 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2387 XtSetValues(w, args, 3);
2392 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2396 SetClockIcon (int color)
2400 Pixmap pm = *clockIcons[color];
2401 if (iconPixmap != pm) {
2403 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2404 XtSetValues(shellWidget, args, 1);
2411 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2413 InputSource *is = (InputSource *) closure;
2418 if (is->lineByLine) {
2419 count = read(is->fd, is->unused,
2420 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2422 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2425 is->unused += count;
2427 while (p < is->unused) {
2428 q = memchr(p, '\n', is->unused - p);
2429 if (q == NULL) break;
2431 (is->func)(is, is->closure, p, q - p, 0);
2435 while (p < is->unused) {
2440 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2445 (is->func)(is, is->closure, is->buf, count, error);
2451 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2455 ChildProc *cp = (ChildProc *) pr;
2457 is = (InputSource *) calloc(1, sizeof(InputSource));
2458 is->lineByLine = lineByLine;
2462 is->fd = fileno(stdin);
2464 is->kind = cp->kind;
2465 is->fd = cp->fdFrom;
2468 is->unused = is->buf;
2471 is->xid = XtAppAddInput(appContext, is->fd,
2472 (XtPointer) (XtInputReadMask),
2473 (XtInputCallbackProc) DoInputCallback,
2475 is->closure = closure;
2476 return (InputSourceRef) is;
2478 return (InputSourceRef) 0;
2483 RemoveInputSource (InputSourceRef isr)
2486 InputSource *is = (InputSource *) isr;
2488 if (is->xid == 0) return;
2489 XtRemoveInput(is->xid);
2496 static Boolean frameWaiting;
2499 FrameAlarm (int sig)
2501 frameWaiting = False;
2502 /* In case System-V style signals. Needed?? */
2503 signal(SIGALRM, FrameAlarm);
2507 FrameDelay (int time)
2510 struct itimerval delay;
2512 XSync(xDisplay, False);
2515 frameWaiting = True;
2516 signal(SIGALRM, FrameAlarm);
2517 delay.it_interval.tv_sec =
2518 delay.it_value.tv_sec = time / 1000;
2519 delay.it_interval.tv_usec =
2520 delay.it_value.tv_usec = (time % 1000) * 1000;
2521 setitimer(ITIMER_REAL, &delay, NULL);
2522 while (frameWaiting) pause();
2523 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2524 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2525 setitimer(ITIMER_REAL, &delay, NULL);
2533 FrameDelay (int time)
2536 XSync(xDisplay, False);
2539 usleep(time * 1000);
2545 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2547 char buf[MSG_SIZ], *logoName = buf;
2548 if(appData.logo[n][0]) {
2549 logoName = appData.logo[n];
2550 } else if(appData.autoLogo) {
2551 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2552 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2553 } else if(appData.directory[n] && appData.directory[n][0]) {
2554 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2558 { ASSIGN(cps->programLogo, logoName); }
2562 UpdateLogos (int displ)
2564 if(optList[W_WHITE-1].handle == NULL) return;
2565 LoadLogo(&first, 0, 0);
2566 LoadLogo(&second, 1, appData.icsActive);
2567 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);