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"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xevalgraph.h"
206 #include "xedittags.h"
210 #include "engineoutput.h"
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
231 int main P((int argc, char **argv));
232 RETSIGTYPE CmailSigHandler P((int sig));
233 RETSIGTYPE IntSigHandler P((int sig));
234 RETSIGTYPE TermSizeSigHandler P((int sig));
235 Widget CreateMenuBar P((Menu *mb, int boardWidth));
237 char *InsertPxlSize P((char *pattern, int targetPxlSize));
238 XFontSet CreateFontSet P((char *base_fnt_lst));
240 char *FindFont P((char *pattern, int targetPxlSize));
242 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
243 u_int wreq, u_int hreq));
244 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
245 void DelayedDrag P((void));
246 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
247 void HandlePV P((Widget w, XEvent * event,
248 String * params, Cardinal * nParams));
249 void DrawPositionProc P((Widget w, XEvent *event,
250 String *prms, Cardinal *nprms));
251 void CommentClick P((Widget w, XEvent * event,
252 String * params, Cardinal * nParams));
253 void ICSInputBoxPopUp P((void));
254 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
255 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
257 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
258 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
259 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
260 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
261 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
262 Boolean TempBackwardActive = False;
263 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
264 void DisplayMove P((int moveNumber));
265 void ICSInitScript P((void));
266 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
267 void update_ics_width P(());
268 int CopyMemoProc P(());
271 * XBoard depends on Xt R4 or higher
273 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;
281 Option *optList; // contains all widgets of main window
283 XFontSet fontSet, clockFontSet;
286 XFontStruct *clockFontStruct;
288 Font coordFontID, countFontID;
289 XFontStruct *coordFontStruct, *countFontStruct;
290 XtAppContext appContext;
293 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
295 Position commentX = -1, commentY = -1;
296 Dimension commentW, commentH;
297 typedef unsigned int BoardSize;
299 Boolean chessProgram;
301 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
302 int smallLayout = 0, tinyLayout = 0,
303 marginW, marginH, // [HGM] for run-time resizing
304 fromX = -1, fromY = -1, toX, toY, commentUp = False,
305 errorExitStatus = -1, defaultLineGap;
306 Dimension textHeight;
307 Pixel timerForegroundPixel, timerBackgroundPixel;
308 Pixel buttonForegroundPixel, buttonBackgroundPixel;
309 char *chessDir, *programName, *programVersion;
310 Boolean alwaysOnTop = False;
311 char *icsTextMenuString;
313 char *firstChessProgramNames;
314 char *secondChessProgramNames;
316 WindowPlacement wpMain;
317 WindowPlacement wpConsole;
318 WindowPlacement wpComment;
319 WindowPlacement wpMoveHistory;
320 WindowPlacement wpEvalGraph;
321 WindowPlacement wpEngineOutput;
322 WindowPlacement wpGameList;
323 WindowPlacement wpTags;
326 /* This magic number is the number of intermediate frames used
327 in each half of the animation. For short moves it's reduced
328 by 1. The total number of frames will be factor * 2 + 1. */
331 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
338 DropMenuEnables dmEnables[] = {
355 XtResource clientResources[] = {
356 { "flashCount", "flashCount", XtRInt, sizeof(int),
357 XtOffset(AppDataPtr, flashCount), XtRImmediate,
358 (XtPointer) FLASH_COUNT },
361 XrmOptionDescRec shellOptions[] = {
362 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
363 { "-flash", "flashCount", XrmoptionNoArg, "3" },
364 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
367 XtActionsRec boardActions[] = {
368 { "DrawPosition", DrawPositionProc },
369 { "HandlePV", HandlePV },
370 { "SelectPV", SelectPV },
371 { "StopPV", StopPV },
372 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
373 { "QuitProc", QuitWrapper },
374 { "ManProc", ManInner },
375 { "TempBackwardProc", TempBackwardProc },
376 { "TempForwardProc", TempForwardProc },
377 { "CommentClick", (XtActionProc) CommentClick },
378 { "GenericPopDown", (XtActionProc) GenericPopDown },
379 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
380 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
381 { "SelectMove", (XtActionProc) SelectMove },
382 { "LoadSelectedProc", LoadSelectedProc },
383 { "SetFilterProc", SetFilterProc },
384 { "TypeInProc", TypeInProc },
385 { "EnterKeyProc", EnterKeyProc },
386 { "UpKeyProc", UpKeyProc },
387 { "DownKeyProc", DownKeyProc },
388 { "WheelProc", WheelProc },
389 { "TabProc", TabProc },
392 char globalTranslations[] =
393 ":<Key>F9: MenuItem(Actions.Resign) \n \
394 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
395 :Meta<Key>V: MenuItem(File.NewVariant) \n \
396 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
397 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
398 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
399 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
400 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
401 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
402 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
403 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
404 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
405 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
406 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
407 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
408 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
409 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
410 :Ctrl<Key>q: MenuItem(File.Quit) \n \
411 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
412 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
413 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
414 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
415 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
416 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
417 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
418 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
419 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
420 :Meta<Key>G: MenuItem(View.GameList) \n \
421 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
422 :<Key>Pause: MenuItem(Mode.Pause) \n \
423 :<Key>F3: MenuItem(Action.Accept) \n \
424 :<Key>F4: MenuItem(Action.Decline) \n \
425 :<Key>F12: MenuItem(Action.Rematch) \n \
426 :<Key>F5: MenuItem(Action.CallFlag) \n \
427 :<Key>F6: MenuItem(Action.Draw) \n \
428 :<Key>F7: MenuItem(Action.Adjourn) \n \
429 :<Key>F8: MenuItem(Action.Abort) \n \
430 :<Key>F10: MenuItem(Action.StopObserving) \n \
431 :<Key>F11: MenuItem(Action.StopExamining) \n \
432 :Ctrl<Key>d: MenuItem(DebugProc) \n \
433 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
434 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
435 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
436 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
437 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
438 :<Key>Left: MenuItem(Edit.Backward) \n \
439 :<Key>Right: MenuItem(Edit.Forward) \n \
440 :<Key>Home: MenuItem(Edit.Revert) \n \
441 :<Key>End: MenuItem(Edit.TruncateGame) \n \
442 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
443 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
444 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
445 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
446 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
447 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
448 #ifndef OPTIONSDIALOG
450 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
451 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
452 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
453 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
454 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
457 :<Key>F1: MenuItem(Help.ManXBoard) \n \
458 :<Key>F2: MenuItem(View.FlipView) \n \
459 :<KeyDown>Return: TempBackwardProc() \n \
460 :<KeyUp>Return: TempForwardProc() \n";
462 char ICSInputTranslations[] =
463 "<Key>Up: UpKeyProc() \n "
464 "<Key>Down: DownKeyProc() \n "
465 "<Key>Return: EnterKeyProc() \n";
467 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
468 // as the widget is destroyed before the up-click can call extend-end
469 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
471 String xboardResources[] = {
472 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
477 /* Max possible square size */
478 #define MAXSQSIZE 256
480 static int xpm_avail[MAXSQSIZE];
482 #ifdef HAVE_DIR_STRUCT
484 /* Extract piece size from filename */
486 xpm_getsize (char *name, int len, char *ext)
494 if ((p=strchr(name, '.')) == NULL ||
495 StrCaseCmp(p+1, ext) != 0)
501 while (*p && isdigit(*p))
508 /* Setup xpm_avail */
510 xpm_getavail (char *dirname, char *ext)
516 for (i=0; i<MAXSQSIZE; ++i)
519 if (appData.debugMode)
520 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
522 dir = opendir(dirname);
525 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
526 programName, dirname);
530 while ((ent=readdir(dir)) != NULL) {
531 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
532 if (i > 0 && i < MAXSQSIZE)
542 xpm_print_avail (FILE *fp, char *ext)
546 fprintf(fp, _("Available `%s' sizes:\n"), ext);
547 for (i=1; i<MAXSQSIZE; ++i) {
553 /* Return XPM piecesize closest to size */
555 xpm_closest_to (char *dirname, int size, char *ext)
558 int sm_diff = MAXSQSIZE;
562 xpm_getavail(dirname, ext);
564 if (appData.debugMode)
565 xpm_print_avail(stderr, ext);
567 for (i=1; i<MAXSQSIZE; ++i) {
570 diff = (diff<0) ? -diff : diff;
571 if (diff < sm_diff) {
579 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
585 #else /* !HAVE_DIR_STRUCT */
586 /* If we are on a system without a DIR struct, we can't
587 read the directory, so we can't collect a list of
588 filenames, etc., so we can't do any size-fitting. */
590 xpm_closest_to (char *dirname, int size, char *ext)
593 Warning: No DIR structure found on this system --\n\
594 Unable to autosize for XPM/XIM pieces.\n\
595 Please report this error to %s.\n\
596 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
599 #endif /* HAVE_DIR_STRUCT */
602 /* Arrange to catch delete-window events */
603 Atom wm_delete_window;
605 CatchDeleteWindow (Widget w, String procname)
608 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
609 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
610 XtAugmentTranslations(w, XtParseTranslationTable(buf));
617 XtSetArg(args[0], XtNiconic, False);
618 XtSetValues(shellWidget, args, 1);
620 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
623 //---------------------------------------------------------------------------------------------------------
624 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
627 #define CW_USEDEFAULT (1<<31)
628 #define ICS_TEXT_MENU_SIZE 90
629 #define DEBUG_FILE "xboard.debug"
630 #define SetCurrentDirectory chdir
631 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
635 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
638 // front-end part of option handling
640 // [HGM] This platform-dependent table provides the location for storing the color info
641 extern char *crWhite, * crBlack;
645 &appData.whitePieceColor,
646 &appData.blackPieceColor,
647 &appData.lightSquareColor,
648 &appData.darkSquareColor,
649 &appData.highlightSquareColor,
650 &appData.premoveHighlightColor,
651 &appData.lowTimeWarningColor,
662 // [HGM] font: keep a font for each square size, even non-stndard ones
665 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
666 char *fontTable[NUM_FONTS][MAX_SIZE];
669 ParseFont (char *name, int number)
670 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
672 if(sscanf(name, "size%d:", &size)) {
673 // [HGM] font: font is meant for specific boardSize (likely from settings file);
674 // defer processing it until we know if it matches our board size
675 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
676 fontTable[number][size] = strdup(strchr(name, ':')+1);
677 fontValid[number][size] = True;
682 case 0: // CLOCK_FONT
683 appData.clockFont = strdup(name);
685 case 1: // MESSAGE_FONT
686 appData.font = strdup(name);
688 case 2: // COORD_FONT
689 appData.coordFont = strdup(name);
694 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
699 { // only 2 fonts currently
700 appData.clockFont = CLOCK_FONT_NAME;
701 appData.coordFont = COORD_FONT_NAME;
702 appData.font = DEFAULT_FONT_NAME;
707 { // no-op, until we identify the code for this already in XBoard and move it here
711 ParseColor (int n, char *name)
712 { // in XBoard, just copy the color-name string
713 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
717 ParseTextAttribs (ColorClass cc, char *s)
719 (&appData.colorShout)[cc] = strdup(s);
723 ParseBoardSize (void *addr, char *name)
725 appData.boardSize = strdup(name);
730 { // In XBoard the sound-playing program takes care of obtaining the actual sound
734 SetCommPortDefaults ()
735 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
738 // [HGM] args: these three cases taken out to stay in front-end
740 SaveFontArg (FILE *f, ArgDescriptor *ad)
743 int i, n = (int)(intptr_t)ad->argLoc;
745 case 0: // CLOCK_FONT
746 name = appData.clockFont;
748 case 1: // MESSAGE_FONT
751 case 2: // COORD_FONT
752 name = appData.coordFont;
757 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
758 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
759 fontTable[n][squareSize] = strdup(name);
760 fontValid[n][squareSize] = True;
763 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
764 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
769 { // nothing to do, as the sounds are at all times represented by their text-string names already
773 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
774 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
775 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
779 SaveColor (FILE *f, ArgDescriptor *ad)
780 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
781 if(colorVariable[(int)(intptr_t)ad->argLoc])
782 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
786 SaveBoardSize (FILE *f, char *name, void *addr)
787 { // wrapper to shield back-end from BoardSize & sizeInfo
788 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
792 ParseCommPortSettings (char *s)
793 { // no such option in XBoard (yet)
799 GetActualPlacement (Widget wg, WindowPlacement *wp)
801 XWindowAttributes winAt;
808 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
809 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
810 wp->x = rx - winAt.x;
811 wp->y = ry - winAt.y;
812 wp->height = winAt.height;
813 wp->width = winAt.width;
814 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
819 { // wrapper to shield use of window handles from back-end (make addressible by number?)
820 // In XBoard this will have to wait until awareness of window parameters is implemented
821 GetActualPlacement(shellWidget, &wpMain);
822 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
823 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
824 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
825 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
826 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
827 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
831 PrintCommPortSettings (FILE *f, char *name)
832 { // This option does not exist in XBoard
836 EnsureOnScreen (int *x, int *y, int minX, int minY)
843 { // [HGM] args: allows testing if main window is realized from back-end
844 return xBoardWindow != 0;
848 PopUpStartupDialog ()
849 { // start menu not implemented in XBoard
853 ConvertToLine (int argc, char **argv)
855 static char line[128*1024], buf[1024];
859 for(i=1; i<argc; i++)
861 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
862 && argv[i][0] != '{' )
863 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
865 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
866 strncat(line, buf, 128*1024 - strlen(line) - 1 );
869 line[strlen(line)-1] = NULLCHAR;
873 //--------------------------------------------------------------------------------------------
876 ResizeBoardWindow (int w, int h, int inhibit)
878 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
880 shellArgs[0].value = w;
881 shellArgs[1].value = h;
882 shellArgs[4].value = shellArgs[2].value = w;
883 shellArgs[5].value = shellArgs[3].value = h;
884 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
886 XSync(xDisplay, False);
890 MakeOneColor (char *name, Pixel *color)
893 if (!appData.monoMode) {
894 vFrom.addr = (caddr_t) name;
895 vFrom.size = strlen(name);
896 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
897 if (vTo.addr == NULL) {
898 appData.monoMode = True;
901 *color = *(Pixel *) vTo.addr;
909 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
910 int forceMono = False;
912 if (appData.lowTimeWarning)
913 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
914 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
915 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
921 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
922 { // detervtomine what fonts to use, and create them
926 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
927 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
928 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
929 appData.font = fontTable[MESSAGE_FONT][squareSize];
930 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
931 appData.coordFont = fontTable[COORD_FONT][squareSize];
934 appData.font = InsertPxlSize(appData.font, fontPxlSize);
935 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
936 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
937 fontSet = CreateFontSet(appData.font);
938 clockFontSet = CreateFontSet(appData.clockFont);
940 /* For the coordFont, use the 0th font of the fontset. */
941 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
942 XFontStruct **font_struct_list;
943 XFontSetExtents *fontSize;
944 char **font_name_list;
945 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
946 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
947 coordFontStruct = XQueryFont(xDisplay, coordFontID);
948 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
949 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
952 appData.font = FindFont(appData.font, fontPxlSize);
953 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
954 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
955 clockFontID = XLoadFont(xDisplay, appData.clockFont);
956 clockFontStruct = XQueryFont(xDisplay, clockFontID);
957 coordFontID = XLoadFont(xDisplay, appData.coordFont);
958 coordFontStruct = XQueryFont(xDisplay, coordFontID);
959 // textHeight in !NLS mode!
961 countFontID = coordFontID; // [HGM] holdings
962 countFontStruct = coordFontStruct;
964 xdb = XtDatabase(xDisplay);
966 XrmPutLineResource(&xdb, "*international: True");
967 vTo.size = sizeof(XFontSet);
968 vTo.addr = (XtPointer) &fontSet;
969 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
971 XrmPutStringResource(&xdb, "*font", appData.font);
981 case ArgInt: p = " N"; break;
982 case ArgString: p = " STR"; break;
983 case ArgBoolean: p = " TF"; break;
984 case ArgSettingsFilename:
985 case ArgFilename: p = " FILE"; break;
986 case ArgX: p = " Nx"; break;
987 case ArgY: p = " Ny"; break;
988 case ArgAttribs: p = " TEXTCOL"; break;
989 case ArgColor: p = " COL"; break;
990 case ArgFont: p = " FONT"; break;
991 case ArgBoardSize: p = " SIZE"; break;
992 case ArgFloat: p = " FLOAT"; break;
997 case ArgCommSettings:
1008 ArgDescriptor *q, *p = argDescriptors+5;
1009 printf("\nXBoard accepts the following options:\n"
1010 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1011 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1012 " SIZE = board-size spec(s)\n"
1013 " Within parentheses are short forms, or options to set to true or false.\n"
1014 " Persistent options (saved in the settings file) are marked with *)\n\n");
1016 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1017 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1018 if(p->save) strcat(buf+len, "*");
1019 for(q=p+1; q->argLoc == p->argLoc; q++) {
1020 if(q->argName[0] == '-') continue;
1021 strcat(buf+len, q == p+1 ? " (" : " ");
1022 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1024 if(q != p+1) strcat(buf+len, ")");
1026 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1029 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1033 main (int argc, char **argv)
1035 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1036 XSetWindowAttributes window_attributes;
1038 Dimension boardWidth, boardHeight, w, h;
1040 int forceMono = False;
1042 srandom(time(0)); // [HGM] book: make random truly random
1044 setbuf(stdout, NULL);
1045 setbuf(stderr, NULL);
1048 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1049 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1053 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1058 programName = strrchr(argv[0], '/');
1059 if (programName == NULL)
1060 programName = argv[0];
1065 XtSetLanguageProc(NULL, NULL, NULL);
1066 if (appData.debugMode) {
1067 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1070 bindtextdomain(PACKAGE, LOCALEDIR);
1071 textdomain(PACKAGE);
1074 appData.boardSize = "";
1075 InitAppData(ConvertToLine(argc, argv));
1077 if (p == NULL) p = "/tmp";
1078 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1079 gameCopyFilename = (char*) malloc(i);
1080 gamePasteFilename = (char*) malloc(i);
1081 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1082 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1084 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1085 static char buf[MSG_SIZ];
1086 EscapeExpand(buf, appData.firstInitString);
1087 appData.firstInitString = strdup(buf);
1088 EscapeExpand(buf, appData.secondInitString);
1089 appData.secondInitString = strdup(buf);
1090 EscapeExpand(buf, appData.firstComputerString);
1091 appData.firstComputerString = strdup(buf);
1092 EscapeExpand(buf, appData.secondComputerString);
1093 appData.secondComputerString = strdup(buf);
1096 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1099 if (chdir(chessDir) != 0) {
1100 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1106 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1107 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1108 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1109 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1112 setbuf(debugFP, NULL);
1115 /* [HGM,HR] make sure board size is acceptable */
1116 if(appData.NrFiles > BOARD_FILES ||
1117 appData.NrRanks > BOARD_RANKS )
1118 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1121 /* This feature does not work; animation needs a rewrite */
1122 appData.highlightDragging = FALSE;
1126 gameInfo.variant = StringToVariant(appData.variant);
1127 InitPosition(FALSE);
1130 XtAppInitialize(&appContext, "XBoard", shellOptions,
1131 XtNumber(shellOptions),
1132 &argc, argv, xboardResources, NULL, 0);
1134 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1135 clientResources, XtNumber(clientResources),
1138 xDisplay = XtDisplay(shellWidget);
1139 xScreen = DefaultScreen(xDisplay);
1140 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1143 * determine size, based on supplied or remembered -size, or screen size
1145 if (isdigit(appData.boardSize[0])) {
1146 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1147 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1148 &fontPxlSize, &smallLayout, &tinyLayout);
1150 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1151 programName, appData.boardSize);
1155 /* Find some defaults; use the nearest known size */
1156 SizeDefaults *szd, *nearest;
1157 int distance = 99999;
1158 nearest = szd = sizeDefaults;
1159 while (szd->name != NULL) {
1160 if (abs(szd->squareSize - squareSize) < distance) {
1162 distance = abs(szd->squareSize - squareSize);
1163 if (distance == 0) break;
1167 if (i < 2) lineGap = nearest->lineGap;
1168 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1169 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1170 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1171 if (i < 6) smallLayout = nearest->smallLayout;
1172 if (i < 7) tinyLayout = nearest->tinyLayout;
1175 SizeDefaults *szd = sizeDefaults;
1176 if (*appData.boardSize == NULLCHAR) {
1177 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1178 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1181 if (szd->name == NULL) szd--;
1182 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1184 while (szd->name != NULL &&
1185 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1186 if (szd->name == NULL) {
1187 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1188 programName, appData.boardSize);
1192 squareSize = szd->squareSize;
1193 lineGap = szd->lineGap;
1194 clockFontPxlSize = szd->clockFontPxlSize;
1195 coordFontPxlSize = szd->coordFontPxlSize;
1196 fontPxlSize = szd->fontPxlSize;
1197 smallLayout = szd->smallLayout;
1198 tinyLayout = szd->tinyLayout;
1199 // [HGM] font: use defaults from settings file if available and not overruled
1202 defaultLineGap = lineGap;
1203 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1205 /* [HR] height treated separately (hacked) */
1206 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1207 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1210 * Determine what fonts to use.
1212 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1215 * Detect if there are not enough colors available and adapt.
1217 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1218 appData.monoMode = True;
1221 forceMono = MakeColors();
1224 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1226 appData.monoMode = True;
1229 if (appData.monoMode && appData.debugMode) {
1230 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1231 (unsigned long) XWhitePixel(xDisplay, xScreen),
1232 (unsigned long) XBlackPixel(xDisplay, xScreen));
1235 ParseIcsTextColors();
1237 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1243 layoutName = "tinyLayout";
1244 } else if (smallLayout) {
1245 layoutName = "smallLayout";
1247 layoutName = "normalLayout";
1250 optList = BoardPopUp(squareSize, lineGap, (void*)
1256 InitDrawingHandle(optList + W_BOARD);
1257 currBoard = &optList[W_BOARD];
1258 boardWidget = optList[W_BOARD].handle;
1259 menuBarWidget = optList[W_MENU].handle;
1260 dropMenu = optList[W_DROP].handle;
1261 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1262 formWidget = XtParent(boardWidget);
1263 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1264 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1265 XtGetValues(optList[W_WHITE].handle, args, 2);
1266 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1267 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1268 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1269 XtGetValues(optList[W_PAUSE].handle, args, 2);
1271 AppendEnginesToMenu(appData.recentEngineList);
1273 xBoardWindow = XtWindow(boardWidget);
1275 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1276 // not need to go into InitDrawingSizes().
1279 * Create X checkmark bitmap and initialize option menu checks.
1281 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1282 checkmark_bits, checkmark_width, checkmark_height);
1288 ReadBitmap(&wIconPixmap, "icon_white.bm",
1289 icon_white_bits, icon_white_width, icon_white_height);
1290 ReadBitmap(&bIconPixmap, "icon_black.bm",
1291 icon_black_bits, icon_black_width, icon_black_height);
1292 iconPixmap = wIconPixmap;
1294 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1295 XtSetValues(shellWidget, args, i);
1298 * Create a cursor for the board widget.
1300 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1301 XChangeWindowAttributes(xDisplay, xBoardWindow,
1302 CWCursor, &window_attributes);
1305 * Inhibit shell resizing.
1307 shellArgs[0].value = (XtArgVal) &w;
1308 shellArgs[1].value = (XtArgVal) &h;
1309 XtGetValues(shellWidget, shellArgs, 2);
1310 shellArgs[4].value = shellArgs[2].value = w;
1311 shellArgs[5].value = shellArgs[3].value = h;
1312 // XtSetValues(shellWidget, &shellArgs[2], 4);
1313 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1314 marginH = h - boardHeight;
1316 CatchDeleteWindow(shellWidget, "QuitProc");
1321 if(appData.logoSize)
1322 { // locate and read user logo
1324 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1325 ASSIGN(userLogo, buf);
1328 if (appData.animate || appData.animateDragging)
1331 XtAugmentTranslations(formWidget,
1332 XtParseTranslationTable(globalTranslations));
1334 XtAddEventHandler(formWidget, KeyPressMask, False,
1335 (XtEventHandler) MoveTypeInProc, NULL);
1336 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1337 (XtEventHandler) EventProc, NULL);
1339 /* [AS] Restore layout */
1340 if( wpMoveHistory.visible ) {
1344 if( wpEvalGraph.visible )
1349 if( wpEngineOutput.visible ) {
1350 EngineOutputPopUp();
1355 if (errorExitStatus == -1) {
1356 if (appData.icsActive) {
1357 /* We now wait until we see "login:" from the ICS before
1358 sending the logon script (problems with timestamp otherwise) */
1359 /*ICSInitScript();*/
1360 if (appData.icsInputBox) ICSInputBoxPopUp();
1364 signal(SIGWINCH, TermSizeSigHandler);
1366 signal(SIGINT, IntSigHandler);
1367 signal(SIGTERM, IntSigHandler);
1368 if (*appData.cmailGameName != NULLCHAR) {
1369 signal(SIGUSR1, CmailSigHandler);
1373 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1376 // XtSetKeyboardFocus(shellWidget, formWidget);
1377 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1379 XtAppMainLoop(appContext);
1380 if (appData.debugMode) fclose(debugFP); // [DM] debug
1385 TermSizeSigHandler (int sig)
1391 IntSigHandler (int sig)
1397 CmailSigHandler (int sig)
1402 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1404 /* Activate call-back function CmailSigHandlerCallBack() */
1405 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1407 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1411 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1414 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1416 /**** end signal code ****/
1419 #define Abs(n) ((n)<0 ? -(n) : (n))
1423 InsertPxlSize (char *pattern, int targetPxlSize)
1425 char *base_fnt_lst, strInt[12], *p, *q;
1426 int alternatives, i, len, strIntLen;
1429 * Replace the "*" (if present) in the pixel-size slot of each
1430 * alternative with the targetPxlSize.
1434 while ((p = strchr(p, ',')) != NULL) {
1438 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1439 strIntLen = strlen(strInt);
1440 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1444 while (alternatives--) {
1445 char *comma = strchr(p, ',');
1446 for (i=0; i<14; i++) {
1447 char *hyphen = strchr(p, '-');
1449 if (comma && hyphen > comma) break;
1450 len = hyphen + 1 - p;
1451 if (i == 7 && *p == '*' && len == 2) {
1453 memcpy(q, strInt, strIntLen);
1463 len = comma + 1 - p;
1470 return base_fnt_lst;
1474 CreateFontSet (char *base_fnt_lst)
1477 char **missing_list;
1481 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1482 &missing_list, &missing_count, &def_string);
1483 if (appData.debugMode) {
1485 XFontStruct **font_struct_list;
1486 char **font_name_list;
1487 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1489 fprintf(debugFP, " got list %s, locale %s\n",
1490 XBaseFontNameListOfFontSet(fntSet),
1491 XLocaleOfFontSet(fntSet));
1492 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1493 for (i = 0; i < count; i++) {
1494 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1497 for (i = 0; i < missing_count; i++) {
1498 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1501 if (fntSet == NULL) {
1502 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1507 #else // not ENABLE_NLS
1509 * Find a font that matches "pattern" that is as close as
1510 * possible to the targetPxlSize. Prefer fonts that are k
1511 * pixels smaller to fonts that are k pixels larger. The
1512 * pattern must be in the X Consortium standard format,
1513 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1514 * The return value should be freed with XtFree when no
1518 FindFont (char *pattern, int targetPxlSize)
1520 char **fonts, *p, *best, *scalable, *scalableTail;
1521 int i, j, nfonts, minerr, err, pxlSize;
1523 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1525 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1526 programName, pattern);
1533 for (i=0; i<nfonts; i++) {
1536 if (*p != '-') continue;
1538 if (*p == NULLCHAR) break;
1539 if (*p++ == '-') j++;
1541 if (j < 7) continue;
1544 scalable = fonts[i];
1547 err = pxlSize - targetPxlSize;
1548 if (Abs(err) < Abs(minerr) ||
1549 (minerr > 0 && err < 0 && -err == minerr)) {
1555 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1556 /* If the error is too big and there is a scalable font,
1557 use the scalable font. */
1558 int headlen = scalableTail - scalable;
1559 p = (char *) XtMalloc(strlen(scalable) + 10);
1560 while (isdigit(*scalableTail)) scalableTail++;
1561 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1563 p = (char *) XtMalloc(strlen(best) + 2);
1564 safeStrCpy(p, best, strlen(best)+1 );
1566 if (appData.debugMode) {
1567 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1568 pattern, targetPxlSize, p);
1570 XFreeFontNames(fonts);
1576 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1579 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1585 EnableNamedMenuItem (char *menuRef, int state)
1587 MenuItem *item = MenuNameToItem(menuRef);
1589 if(item) XtSetSensitive(item->handle, state);
1593 EnableButtonBar (int state)
1595 XtSetSensitive(optList[W_BUTTON].handle, state);
1600 SetMenuEnables (Enables *enab)
1602 while (enab->name != NULL) {
1603 EnableNamedMenuItem(enab->name, enab->value);
1609 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1610 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1612 if(*nprms == 0) return;
1613 item = MenuNameToItem(prms[0]);
1614 if(item) ((MenuProc *) item->proc) ();
1618 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1620 RecentEngineEvent((int) (intptr_t) addr);
1624 AppendMenuItem (char *msg, int n)
1626 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1638 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1639 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1640 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1641 dmEnables[i].piece);
1642 XtSetSensitive(entry, p != NULL || !appData.testLegality
1643 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1644 && !appData.icsActive));
1646 while (p && *p++ == dmEnables[i].piece) count++;
1647 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1649 XtSetArg(args[j], XtNlabel, label); j++;
1650 XtSetValues(entry, args, j);
1655 do_flash_delay (unsigned long msec)
1661 FlashDelay (int flash_delay)
1663 XSync(xDisplay, False);
1664 if(flash_delay) do_flash_delay(flash_delay);
1668 Fraction (int x, int start, int stop)
1670 double f = ((double) x - start)/(stop - start);
1671 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1675 static WindowPlacement wpNew;
1678 CoDrag (Widget sh, WindowPlacement *wp)
1681 int j=0, touch=0, fudge = 2;
1682 GetActualPlacement(sh, wp);
1683 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1684 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1685 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1686 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1687 if(!touch ) return; // only windows that touch co-move
1688 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1689 int heightInc = wpNew.height - wpMain.height;
1690 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1691 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1692 wp->y += fracTop * heightInc;
1693 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1694 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1695 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1696 int widthInc = wpNew.width - wpMain.width;
1697 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1698 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1699 wp->y += fracLeft * widthInc;
1700 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1701 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1703 wp->x += wpNew.x - wpMain.x;
1704 wp->y += wpNew.y - wpMain.y;
1705 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1706 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1707 XtSetArg(args[j], XtNx, wp->x); j++;
1708 XtSetArg(args[j], XtNy, wp->y); j++;
1709 XtSetValues(sh, args, j);
1713 ReSize (WindowPlacement *wp)
1716 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1717 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1718 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1719 if(sqy < sqx) sqx = sqy;
1720 if(sqx != squareSize) {
1721 squareSize = sqx; // adopt new square size
1722 CreatePNGPieces(); // make newly scaled pieces
1723 InitDrawingSizes(0, 0); // creates grid etc.
1724 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1725 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1726 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1727 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1728 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1731 static XtIntervalId delayedDragID = 0;
1740 GetActualPlacement(shellWidget, &wpNew);
1741 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1742 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1743 busy = 0; return; // false alarm
1746 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1747 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1748 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1749 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1751 DrawPosition(True, NULL);
1752 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1760 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1762 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1766 EventProc (Widget widget, caddr_t unused, XEvent *event)
1768 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1769 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1773 * event handler for redrawing the board
1776 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1778 DrawPosition(True, NULL);
1783 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1784 { // [HGM] pv: walk PV
1785 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1788 static int savedIndex; /* gross that this is global */
1791 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1794 XawTextPosition index, dummy;
1797 XawTextGetSelectionPos(w, &index, &dummy);
1798 XtSetArg(arg, XtNstring, &val);
1799 XtGetValues(w, &arg, 1);
1800 ReplaceComment(savedIndex, val);
1801 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1802 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1806 EditCommentPopUp (int index, char *title, char *text)
1809 if (text == NULL) text = "";
1810 NewCommentPopup(title, text, index);
1814 CommentPopUp (char *title, char *text)
1816 savedIndex = currentMove; // [HGM] vari
1817 NewCommentPopup(title, text, currentMove);
1823 PopDown(CommentDlg);
1827 /* Disable all user input other than deleting the window */
1828 static int frozen = 0;
1834 /* Grab by a widget that doesn't accept input */
1835 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1839 /* Undo a FreezeUI */
1843 if (!frozen) return;
1844 XtRemoveGrab(optList[W_MESSG].handle);
1852 static int oldPausing = FALSE;
1853 static GameMode oldmode = (GameMode) -1;
1856 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1858 if (pausing != oldPausing) {
1859 oldPausing = pausing;
1860 MarkMenuItem("Mode.Pause", pausing);
1862 if (appData.showButtonBar) {
1863 /* Always toggle, don't set. Previous code messes up when
1864 invoked while the button is pressed, as releasing it
1865 toggles the state again. */
1868 XtSetArg(args[0], XtNbackground, &oldbg);
1869 XtSetArg(args[1], XtNforeground, &oldfg);
1870 XtGetValues(optList[W_PAUSE].handle,
1872 XtSetArg(args[0], XtNbackground, oldfg);
1873 XtSetArg(args[1], XtNforeground, oldbg);
1875 XtSetValues(optList[W_PAUSE].handle, args, 2);
1879 wname = ModeToWidgetName(oldmode);
1880 if (wname != NULL) {
1881 MarkMenuItem(wname, False);
1883 wname = ModeToWidgetName(gameMode);
1884 if (wname != NULL) {
1885 MarkMenuItem(wname, True);
1888 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1890 /* Maybe all the enables should be handled here, not just this one */
1891 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1893 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1898 * Button/menu procedures
1901 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1902 char *selected_fen_position=NULL;
1905 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1906 Atom *type_return, XtPointer *value_return,
1907 unsigned long *length_return, int *format_return)
1909 char *selection_tmp;
1911 // if (!selected_fen_position) return False; /* should never happen */
1912 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1913 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1914 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1917 if (f == NULL) return False;
1921 selection_tmp = XtMalloc(len + 1);
1922 count = fread(selection_tmp, 1, len, f);
1925 XtFree(selection_tmp);
1928 selection_tmp[len] = NULLCHAR;
1930 /* note: since no XtSelectionDoneProc was registered, Xt will
1931 * automatically call XtFree on the value returned. So have to
1932 * make a copy of it allocated with XtMalloc */
1933 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1934 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1937 *value_return=selection_tmp;
1938 *length_return=strlen(selection_tmp);
1939 *type_return=*target;
1940 *format_return = 8; /* bits per byte */
1942 } else if (*target == XA_TARGETS(xDisplay)) {
1943 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1944 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1945 targets_tmp[1] = XA_STRING;
1946 *value_return = targets_tmp;
1947 *type_return = XA_ATOM;
1950 // This code leads to a read of value_return out of bounds on 64-bit systems.
1951 // Other code which I have seen always sets *format_return to 32 independent of
1952 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1953 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1954 *format_return = 8 * sizeof(Atom);
1955 if (*format_return > 32) {
1956 *length_return *= *format_return / 32;
1957 *format_return = 32;
1960 *format_return = 32;
1968 /* note: when called from menu all parameters are NULL, so no clue what the
1969 * Widget which was clicked on was, or what the click event was
1972 CopySomething (char *src)
1974 selected_fen_position = src;
1976 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1977 * have a notion of a position that is selected but not copied.
1978 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1980 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1982 SendPositionSelection,
1983 NULL/* lose_ownership_proc */ ,
1984 NULL/* transfer_done_proc */);
1985 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1987 SendPositionSelection,
1988 NULL/* lose_ownership_proc */ ,
1989 NULL/* transfer_done_proc */);
1992 /* function called when the data to Paste is ready */
1994 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
1995 Atom *type, XtPointer value, unsigned long *len, int *format)
1998 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
1999 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2000 EditPositionPasteFEN(fenstr);
2004 /* called when Paste Position button is pressed,
2005 * all parameters will be NULL */
2007 PastePositionProc ()
2009 XtGetSelectionValue(menuBarWidget,
2010 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2011 /* (XtSelectionCallbackProc) */ PastePositionCB,
2012 NULL, /* client_data passed to PastePositionCB */
2014 /* better to use the time field from the event that triggered the
2015 * call to this function, but that isn't trivial to get
2022 /* note: when called from menu all parameters are NULL, so no clue what the
2023 * Widget which was clicked on was, or what the click event was
2025 /* function called when the data to Paste is ready */
2027 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2028 Atom *type, XtPointer value, unsigned long *len, int *format)
2031 if (value == NULL || *len == 0) {
2032 return; /* nothing had been selected to copy */
2034 f = fopen(gamePasteFilename, "w");
2036 DisplayError(_("Can't open temp file"), errno);
2039 fwrite(value, 1, *len, f);
2042 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2045 /* called when Paste Game button is pressed,
2046 * all parameters will be NULL */
2050 XtGetSelectionValue(menuBarWidget,
2051 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2052 /* (XtSelectionCallbackProc) */ PasteGameCB,
2053 NULL, /* client_data passed to PasteGameCB */
2055 /* better to use the time field from the event that triggered the
2056 * call to this function, but that isn't trivial to get
2065 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2072 { // bassic primitive for determining if modifier keys are pressed
2073 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2076 XQueryKeymap(xDisplay,keys);
2077 for(i=0; i<6; i++) {
2079 j = XKeysymToKeycode(xDisplay, codes[i]);
2080 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2086 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2090 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2091 if ( n == 1 && *buf >= 32 // printable
2092 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2093 ) BoxAutoPopUp (buf);
2097 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2098 { // [HGM] input: let up-arrow recall previous line from history
2103 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2104 { // [HGM] input: let down-arrow recall next line from history
2109 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2115 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2117 if (!TempBackwardActive) {
2118 TempBackwardActive = True;
2124 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2126 /* Check to see if triggered by a key release event for a repeating key.
2127 * If so the next queued event will be a key press of the same key at the same time */
2128 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2130 XPeekEvent(xDisplay, &next);
2131 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2132 next.xkey.keycode == event->xkey.keycode)
2136 TempBackwardActive = False;
2140 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2141 { // called as key binding
2144 if (nprms && *nprms > 0)
2148 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2154 { // called from menu
2155 ManInner(NULL, NULL, NULL, NULL);
2159 SetWindowTitle (char *text, char *title, char *icon)
2163 if (appData.titleInWindow) {
2165 XtSetArg(args[i], XtNlabel, text); i++;
2166 XtSetValues(titleWidget, args, i);
2169 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2170 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2171 XtSetValues(shellWidget, args, i);
2172 XSync(xDisplay, False);
2177 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2183 DisplayIcsInteractionTitle (String message)
2185 if (oldICSInteractionTitle == NULL) {
2186 /* Magic to find the old window title, adapted from vim */
2187 char *wina = getenv("WINDOWID");
2189 Window win = (Window) atoi(wina);
2190 Window root, parent, *children;
2191 unsigned int nchildren;
2192 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2194 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2195 if (!XQueryTree(xDisplay, win, &root, &parent,
2196 &children, &nchildren)) break;
2197 if (children) XFree((void *)children);
2198 if (parent == root || parent == 0) break;
2201 XSetErrorHandler(oldHandler);
2203 if (oldICSInteractionTitle == NULL) {
2204 oldICSInteractionTitle = "xterm";
2207 printf("\033]0;%s\007", message);
2212 XtIntervalId delayedEventTimerXID = 0;
2213 DelayedEventCallback delayedEventCallback = 0;
2218 delayedEventTimerXID = 0;
2219 delayedEventCallback();
2223 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2225 if(delayedEventTimerXID && delayedEventCallback == cb)
2226 // [HGM] alive: replace, rather than add or flush identical event
2227 XtRemoveTimeOut(delayedEventTimerXID);
2228 delayedEventCallback = cb;
2229 delayedEventTimerXID =
2230 XtAppAddTimeOut(appContext, millisec,
2231 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2234 DelayedEventCallback
2237 if (delayedEventTimerXID) {
2238 return delayedEventCallback;
2245 CancelDelayedEvent ()
2247 if (delayedEventTimerXID) {
2248 XtRemoveTimeOut(delayedEventTimerXID);
2249 delayedEventTimerXID = 0;
2253 XtIntervalId loadGameTimerXID = 0;
2256 LoadGameTimerRunning ()
2258 return loadGameTimerXID != 0;
2262 StopLoadGameTimer ()
2264 if (loadGameTimerXID != 0) {
2265 XtRemoveTimeOut(loadGameTimerXID);
2266 loadGameTimerXID = 0;
2274 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2276 loadGameTimerXID = 0;
2281 StartLoadGameTimer (long millisec)
2284 XtAppAddTimeOut(appContext, millisec,
2285 (XtTimerCallbackProc) LoadGameTimerCallback,
2289 XtIntervalId analysisClockXID = 0;
2292 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2294 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2295 || appData.icsEngineAnalyze) { // [DM]
2296 AnalysisPeriodicEvent(0);
2297 StartAnalysisClock();
2302 StartAnalysisClock ()
2305 XtAppAddTimeOut(appContext, 2000,
2306 (XtTimerCallbackProc) AnalysisClockCallback,
2310 XtIntervalId clockTimerXID = 0;
2313 ClockTimerRunning ()
2315 return clockTimerXID != 0;
2321 if (clockTimerXID != 0) {
2322 XtRemoveTimeOut(clockTimerXID);
2331 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2338 StartClockTimer (long millisec)
2341 XtAppAddTimeOut(appContext, millisec,
2342 (XtTimerCallbackProc) ClockTimerCallback,
2347 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2351 Widget w = (Widget) opt->handle;
2353 /* check for low time warning */
2354 Pixel foregroundOrWarningColor = timerForegroundPixel;
2357 appData.lowTimeWarning &&
2358 (timer / 1000) < appData.icsAlarmTime)
2359 foregroundOrWarningColor = lowTimeWarningColor;
2361 if (appData.clockMode) {
2362 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2363 XtSetArg(args[0], XtNlabel, buf);
2365 snprintf(buf, MSG_SIZ, "%s ", color);
2366 XtSetArg(args[0], XtNlabel, buf);
2371 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2372 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2374 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2375 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2378 XtSetValues(w, args, 3);
2381 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2384 SetClockIcon (int color)
2387 Pixmap pm = *clockIcons[color];
2388 if (iconPixmap != pm) {
2390 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2391 XtSetValues(shellWidget, args, 1);
2396 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2398 InputSource *is = (InputSource *) closure;
2403 if (is->lineByLine) {
2404 count = read(is->fd, is->unused,
2405 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2407 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2410 is->unused += count;
2412 while (p < is->unused) {
2413 q = memchr(p, '\n', is->unused - p);
2414 if (q == NULL) break;
2416 (is->func)(is, is->closure, p, q - p, 0);
2420 while (p < is->unused) {
2425 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2430 (is->func)(is, is->closure, is->buf, count, error);
2435 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2438 ChildProc *cp = (ChildProc *) pr;
2440 is = (InputSource *) calloc(1, sizeof(InputSource));
2441 is->lineByLine = lineByLine;
2445 is->fd = fileno(stdin);
2447 is->kind = cp->kind;
2448 is->fd = cp->fdFrom;
2451 is->unused = is->buf;
2454 is->xid = XtAppAddInput(appContext, is->fd,
2455 (XtPointer) (XtInputReadMask),
2456 (XtInputCallbackProc) DoInputCallback,
2458 is->closure = closure;
2459 return (InputSourceRef) is;
2463 RemoveInputSource (InputSourceRef isr)
2465 InputSource *is = (InputSource *) isr;
2467 if (is->xid == 0) return;
2468 XtRemoveInput(is->xid);
2474 static Boolean frameWaiting;
2477 FrameAlarm (int sig)
2479 frameWaiting = False;
2480 /* In case System-V style signals. Needed?? */
2481 signal(SIGALRM, FrameAlarm);
2485 FrameDelay (int time)
2487 struct itimerval delay;
2489 XSync(xDisplay, False);
2492 frameWaiting = True;
2493 signal(SIGALRM, FrameAlarm);
2494 delay.it_interval.tv_sec =
2495 delay.it_value.tv_sec = time / 1000;
2496 delay.it_interval.tv_usec =
2497 delay.it_value.tv_usec = (time % 1000) * 1000;
2498 setitimer(ITIMER_REAL, &delay, NULL);
2499 while (frameWaiting) pause();
2500 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2501 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2502 setitimer(ITIMER_REAL, &delay, NULL);
2509 FrameDelay (int time)
2511 XSync(xDisplay, False);
2513 usleep(time * 1000);
2519 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2521 char buf[MSG_SIZ], *logoName = buf;
2522 if(appData.logo[n][0]) {
2523 logoName = appData.logo[n];
2524 } else if(appData.autoLogo) {
2525 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2526 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2527 } else if(appData.directory[n] && appData.directory[n][0]) {
2528 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2532 { ASSIGN(cps->programLogo, logoName); }
2536 UpdateLogos (int displ)
2538 if(optList[W_WHITE-1].handle == NULL) return;
2539 LoadLogo(&first, 0, 0);
2540 LoadLogo(&second, 1, appData.icsActive);
2541 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);