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;
277 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
278 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
279 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
280 Option *optList; // contains all widgets of main window
282 XFontSet fontSet, clockFontSet;
285 XFontStruct *clockFontStruct;
287 Font coordFontID, countFontID;
288 XFontStruct *coordFontStruct, *countFontStruct;
289 XtAppContext appContext;
292 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
294 Position commentX = -1, commentY = -1;
295 Dimension commentW, commentH;
296 typedef unsigned int BoardSize;
298 Boolean chessProgram;
300 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
301 int smallLayout = 0, tinyLayout = 0,
302 marginW, marginH, // [HGM] for run-time resizing
303 fromX = -1, fromY = -1, toX, toY, commentUp = False,
304 errorExitStatus = -1, defaultLineGap;
305 Dimension textHeight;
306 Pixel timerForegroundPixel, timerBackgroundPixel;
307 Pixel buttonForegroundPixel, buttonBackgroundPixel;
308 char *chessDir, *programName, *programVersion;
309 Boolean alwaysOnTop = False;
310 char *icsTextMenuString;
312 char *firstChessProgramNames;
313 char *secondChessProgramNames;
315 WindowPlacement wpMain;
316 WindowPlacement wpConsole;
317 WindowPlacement wpComment;
318 WindowPlacement wpMoveHistory;
319 WindowPlacement wpEvalGraph;
320 WindowPlacement wpEngineOutput;
321 WindowPlacement wpGameList;
322 WindowPlacement wpTags;
324 #define INPUT_SOURCE_BUF_SIZE 8192
333 char buf[INPUT_SOURCE_BUF_SIZE];
338 /* This magic number is the number of intermediate frames used
339 in each half of the animation. For short moves it's reduced
340 by 1. The total number of frames will be factor * 2 + 1. */
343 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
350 DropMenuEnables dmEnables[] = {
367 XtResource clientResources[] = {
368 { "flashCount", "flashCount", XtRInt, sizeof(int),
369 XtOffset(AppDataPtr, flashCount), XtRImmediate,
370 (XtPointer) FLASH_COUNT },
373 XrmOptionDescRec shellOptions[] = {
374 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
375 { "-flash", "flashCount", XrmoptionNoArg, "3" },
376 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
379 XtActionsRec boardActions[] = {
380 { "DrawPosition", DrawPositionProc },
381 { "HandlePV", HandlePV },
382 { "SelectPV", SelectPV },
383 { "StopPV", StopPV },
384 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
385 { "QuitProc", QuitWrapper },
386 { "ManProc", ManInner },
387 { "TempBackwardProc", TempBackwardProc },
388 { "TempForwardProc", TempForwardProc },
389 { "CommentClick", (XtActionProc) CommentClick },
390 { "GenericPopDown", (XtActionProc) GenericPopDown },
391 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
392 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
393 { "SelectMove", (XtActionProc) SelectMove },
394 { "LoadSelectedProc", LoadSelectedProc },
395 { "SetFilterProc", SetFilterProc },
396 { "TypeInProc", TypeInProc },
397 { "EnterKeyProc", EnterKeyProc },
398 { "UpKeyProc", UpKeyProc },
399 { "DownKeyProc", DownKeyProc },
400 { "WheelProc", WheelProc },
401 { "TabProc", TabProc },
404 char globalTranslations[] =
405 ":<Key>F9: MenuItem(Actions.Resign) \n \
406 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
407 :Meta<Key>V: MenuItem(File.NewVariant) \n \
408 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
409 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
410 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
411 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
412 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
413 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
414 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
415 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
416 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
417 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
418 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
419 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
420 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
421 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
422 :Ctrl<Key>q: MenuItem(File.Quit) \n \
423 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
424 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
425 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
426 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
427 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
428 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
429 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
430 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
431 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
432 :Meta<Key>G: MenuItem(View.GameList) \n \
433 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
434 :<Key>Pause: MenuItem(Mode.Pause) \n \
435 :<Key>F3: MenuItem(Action.Accept) \n \
436 :<Key>F4: MenuItem(Action.Decline) \n \
437 :<Key>F12: MenuItem(Action.Rematch) \n \
438 :<Key>F5: MenuItem(Action.CallFlag) \n \
439 :<Key>F6: MenuItem(Action.Draw) \n \
440 :<Key>F7: MenuItem(Action.Adjourn) \n \
441 :<Key>F8: MenuItem(Action.Abort) \n \
442 :<Key>F10: MenuItem(Action.StopObserving) \n \
443 :<Key>F11: MenuItem(Action.StopExamining) \n \
444 :Ctrl<Key>d: MenuItem(DebugProc) \n \
445 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
446 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
447 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
448 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
449 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
450 :<Key>Left: MenuItem(Edit.Backward) \n \
451 :<Key>Right: MenuItem(Edit.Forward) \n \
452 :<Key>Home: MenuItem(Edit.Revert) \n \
453 :<Key>End: MenuItem(Edit.TruncateGame) \n \
454 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
455 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
456 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
457 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
458 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
459 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
460 #ifndef OPTIONSDIALOG
462 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
463 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
464 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
465 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
466 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
469 :<Key>F1: MenuItem(Help.ManXBoard) \n \
470 :<Key>F2: MenuItem(View.FlipView) \n \
471 :<KeyDown>Return: TempBackwardProc() \n \
472 :<KeyUp>Return: TempForwardProc() \n";
474 char ICSInputTranslations[] =
475 "<Key>Up: UpKeyProc() \n "
476 "<Key>Down: DownKeyProc() \n "
477 "<Key>Return: EnterKeyProc() \n";
479 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
480 // as the widget is destroyed before the up-click can call extend-end
481 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
483 String xboardResources[] = {
484 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
489 /* Max possible square size */
490 #define MAXSQSIZE 256
492 static int xpm_avail[MAXSQSIZE];
494 #ifdef HAVE_DIR_STRUCT
496 /* Extract piece size from filename */
498 xpm_getsize (char *name, int len, char *ext)
506 if ((p=strchr(name, '.')) == NULL ||
507 StrCaseCmp(p+1, ext) != 0)
513 while (*p && isdigit(*p))
520 /* Setup xpm_avail */
522 xpm_getavail (char *dirname, char *ext)
528 for (i=0; i<MAXSQSIZE; ++i)
531 if (appData.debugMode)
532 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
534 dir = opendir(dirname);
537 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
538 programName, dirname);
542 while ((ent=readdir(dir)) != NULL) {
543 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
544 if (i > 0 && i < MAXSQSIZE)
554 xpm_print_avail (FILE *fp, char *ext)
558 fprintf(fp, _("Available `%s' sizes:\n"), ext);
559 for (i=1; i<MAXSQSIZE; ++i) {
565 /* Return XPM piecesize closest to size */
567 xpm_closest_to (char *dirname, int size, char *ext)
570 int sm_diff = MAXSQSIZE;
574 xpm_getavail(dirname, ext);
576 if (appData.debugMode)
577 xpm_print_avail(stderr, ext);
579 for (i=1; i<MAXSQSIZE; ++i) {
582 diff = (diff<0) ? -diff : diff;
583 if (diff < sm_diff) {
591 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
597 #else /* !HAVE_DIR_STRUCT */
598 /* If we are on a system without a DIR struct, we can't
599 read the directory, so we can't collect a list of
600 filenames, etc., so we can't do any size-fitting. */
602 xpm_closest_to (char *dirname, int size, char *ext)
605 Warning: No DIR structure found on this system --\n\
606 Unable to autosize for XPM/XIM pieces.\n\
607 Please report this error to %s.\n\
608 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
611 #endif /* HAVE_DIR_STRUCT */
614 /* Arrange to catch delete-window events */
615 Atom wm_delete_window;
617 CatchDeleteWindow (Widget w, String procname)
620 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
621 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
622 XtAugmentTranslations(w, XtParseTranslationTable(buf));
629 XtSetArg(args[0], XtNiconic, False);
630 XtSetValues(shellWidget, args, 1);
632 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
635 //---------------------------------------------------------------------------------------------------------
636 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
639 #define CW_USEDEFAULT (1<<31)
640 #define ICS_TEXT_MENU_SIZE 90
641 #define DEBUG_FILE "xboard.debug"
642 #define SetCurrentDirectory chdir
643 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
647 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
650 // front-end part of option handling
652 // [HGM] This platform-dependent table provides the location for storing the color info
653 extern char *crWhite, * crBlack;
657 &appData.whitePieceColor,
658 &appData.blackPieceColor,
659 &appData.lightSquareColor,
660 &appData.darkSquareColor,
661 &appData.highlightSquareColor,
662 &appData.premoveHighlightColor,
663 &appData.lowTimeWarningColor,
674 // [HGM] font: keep a font for each square size, even non-stndard ones
677 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
678 char *fontTable[NUM_FONTS][MAX_SIZE];
681 ParseFont (char *name, int number)
682 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
684 if(sscanf(name, "size%d:", &size)) {
685 // [HGM] font: font is meant for specific boardSize (likely from settings file);
686 // defer processing it until we know if it matches our board size
687 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
688 fontTable[number][size] = strdup(strchr(name, ':')+1);
689 fontValid[number][size] = True;
694 case 0: // CLOCK_FONT
695 appData.clockFont = strdup(name);
697 case 1: // MESSAGE_FONT
698 appData.font = strdup(name);
700 case 2: // COORD_FONT
701 appData.coordFont = strdup(name);
706 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
711 { // only 2 fonts currently
712 appData.clockFont = CLOCK_FONT_NAME;
713 appData.coordFont = COORD_FONT_NAME;
714 appData.font = DEFAULT_FONT_NAME;
719 { // no-op, until we identify the code for this already in XBoard and move it here
723 ParseColor (int n, char *name)
724 { // in XBoard, just copy the color-name string
725 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
729 ParseTextAttribs (ColorClass cc, char *s)
731 (&appData.colorShout)[cc] = strdup(s);
735 ParseBoardSize (void *addr, char *name)
737 appData.boardSize = strdup(name);
742 { // In XBoard the sound-playing program takes care of obtaining the actual sound
746 SetCommPortDefaults ()
747 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
750 // [HGM] args: these three cases taken out to stay in front-end
752 SaveFontArg (FILE *f, ArgDescriptor *ad)
755 int i, n = (int)(intptr_t)ad->argLoc;
757 case 0: // CLOCK_FONT
758 name = appData.clockFont;
760 case 1: // MESSAGE_FONT
763 case 2: // COORD_FONT
764 name = appData.coordFont;
769 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
770 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
771 fontTable[n][squareSize] = strdup(name);
772 fontValid[n][squareSize] = True;
775 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
776 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
781 { // nothing to do, as the sounds are at all times represented by their text-string names already
785 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
786 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
787 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
791 SaveColor (FILE *f, ArgDescriptor *ad)
792 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
793 if(colorVariable[(int)(intptr_t)ad->argLoc])
794 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
798 SaveBoardSize (FILE *f, char *name, void *addr)
799 { // wrapper to shield back-end from BoardSize & sizeInfo
800 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
804 ParseCommPortSettings (char *s)
805 { // no such option in XBoard (yet)
811 GetActualPlacement (Widget wg, WindowPlacement *wp)
813 XWindowAttributes winAt;
820 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
821 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
822 wp->x = rx - winAt.x;
823 wp->y = ry - winAt.y;
824 wp->height = winAt.height;
825 wp->width = winAt.width;
826 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
831 { // wrapper to shield use of window handles from back-end (make addressible by number?)
832 // In XBoard this will have to wait until awareness of window parameters is implemented
833 GetActualPlacement(shellWidget, &wpMain);
834 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
835 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
836 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
837 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
838 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
839 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
843 PrintCommPortSettings (FILE *f, char *name)
844 { // This option does not exist in XBoard
848 EnsureOnScreen (int *x, int *y, int minX, int minY)
855 { // [HGM] args: allows testing if main window is realized from back-end
856 return xBoardWindow != 0;
860 PopUpStartupDialog ()
861 { // start menu not implemented in XBoard
865 ConvertToLine (int argc, char **argv)
867 static char line[128*1024], buf[1024];
871 for(i=1; i<argc; i++)
873 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
874 && argv[i][0] != '{' )
875 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
877 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
878 strncat(line, buf, 128*1024 - strlen(line) - 1 );
881 line[strlen(line)-1] = NULLCHAR;
885 //--------------------------------------------------------------------------------------------
888 ResizeBoardWindow (int w, int h, int inhibit)
890 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
892 shellArgs[0].value = w;
893 shellArgs[1].value = h;
894 shellArgs[4].value = shellArgs[2].value = w;
895 shellArgs[5].value = shellArgs[3].value = h;
896 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
898 XSync(xDisplay, False);
902 MakeOneColor (char *name, Pixel *color)
905 if (!appData.monoMode) {
906 vFrom.addr = (caddr_t) name;
907 vFrom.size = strlen(name);
908 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
909 if (vTo.addr == NULL) {
910 appData.monoMode = True;
913 *color = *(Pixel *) vTo.addr;
921 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
922 int forceMono = False;
924 if (appData.lowTimeWarning)
925 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
926 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
927 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
933 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
934 { // detervtomine what fonts to use, and create them
938 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
939 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
940 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
941 appData.font = fontTable[MESSAGE_FONT][squareSize];
942 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
943 appData.coordFont = fontTable[COORD_FONT][squareSize];
946 appData.font = InsertPxlSize(appData.font, fontPxlSize);
947 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
948 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
949 fontSet = CreateFontSet(appData.font);
950 clockFontSet = CreateFontSet(appData.clockFont);
952 /* For the coordFont, use the 0th font of the fontset. */
953 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
954 XFontStruct **font_struct_list;
955 XFontSetExtents *fontSize;
956 char **font_name_list;
957 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
958 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
959 coordFontStruct = XQueryFont(xDisplay, coordFontID);
960 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
961 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
964 appData.font = FindFont(appData.font, fontPxlSize);
965 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
966 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
967 clockFontID = XLoadFont(xDisplay, appData.clockFont);
968 clockFontStruct = XQueryFont(xDisplay, clockFontID);
969 coordFontID = XLoadFont(xDisplay, appData.coordFont);
970 coordFontStruct = XQueryFont(xDisplay, coordFontID);
971 // textHeight in !NLS mode!
973 countFontID = coordFontID; // [HGM] holdings
974 countFontStruct = coordFontStruct;
976 xdb = XtDatabase(xDisplay);
978 XrmPutLineResource(&xdb, "*international: True");
979 vTo.size = sizeof(XFontSet);
980 vTo.addr = (XtPointer) &fontSet;
981 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
983 XrmPutStringResource(&xdb, "*font", appData.font);
993 case ArgInt: p = " N"; break;
994 case ArgString: p = " STR"; break;
995 case ArgBoolean: p = " TF"; break;
996 case ArgSettingsFilename:
997 case ArgFilename: p = " FILE"; break;
998 case ArgX: p = " Nx"; break;
999 case ArgY: p = " Ny"; break;
1000 case ArgAttribs: p = " TEXTCOL"; break;
1001 case ArgColor: p = " COL"; break;
1002 case ArgFont: p = " FONT"; break;
1003 case ArgBoardSize: p = " SIZE"; break;
1004 case ArgFloat: p = " FLOAT"; break;
1009 case ArgCommSettings:
1020 ArgDescriptor *q, *p = argDescriptors+5;
1021 printf("\nXBoard accepts the following options:\n"
1022 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1023 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1024 " SIZE = board-size spec(s)\n"
1025 " Within parentheses are short forms, or options to set to true or false.\n"
1026 " Persistent options (saved in the settings file) are marked with *)\n\n");
1028 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1029 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1030 if(p->save) strcat(buf+len, "*");
1031 for(q=p+1; q->argLoc == p->argLoc; q++) {
1032 if(q->argName[0] == '-') continue;
1033 strcat(buf+len, q == p+1 ? " (" : " ");
1034 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1036 if(q != p+1) strcat(buf+len, ")");
1038 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1041 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1045 main (int argc, char **argv)
1047 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1048 XSetWindowAttributes window_attributes;
1050 Dimension boardWidth, boardHeight, w, h;
1052 int forceMono = False;
1054 srandom(time(0)); // [HGM] book: make random truly random
1056 setbuf(stdout, NULL);
1057 setbuf(stderr, NULL);
1060 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1061 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1065 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1070 programName = strrchr(argv[0], '/');
1071 if (programName == NULL)
1072 programName = argv[0];
1077 XtSetLanguageProc(NULL, NULL, NULL);
1078 if (appData.debugMode) {
1079 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1082 bindtextdomain(PACKAGE, LOCALEDIR);
1083 textdomain(PACKAGE);
1086 appData.boardSize = "";
1087 InitAppData(ConvertToLine(argc, argv));
1089 if (p == NULL) p = "/tmp";
1090 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1091 gameCopyFilename = (char*) malloc(i);
1092 gamePasteFilename = (char*) malloc(i);
1093 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1094 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1096 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1097 static char buf[MSG_SIZ];
1098 EscapeExpand(buf, appData.firstInitString);
1099 appData.firstInitString = strdup(buf);
1100 EscapeExpand(buf, appData.secondInitString);
1101 appData.secondInitString = strdup(buf);
1102 EscapeExpand(buf, appData.firstComputerString);
1103 appData.firstComputerString = strdup(buf);
1104 EscapeExpand(buf, appData.secondComputerString);
1105 appData.secondComputerString = strdup(buf);
1108 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1111 if (chdir(chessDir) != 0) {
1112 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1118 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1119 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1120 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1121 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1124 setbuf(debugFP, NULL);
1127 /* [HGM,HR] make sure board size is acceptable */
1128 if(appData.NrFiles > BOARD_FILES ||
1129 appData.NrRanks > BOARD_RANKS )
1130 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1133 /* This feature does not work; animation needs a rewrite */
1134 appData.highlightDragging = FALSE;
1138 gameInfo.variant = StringToVariant(appData.variant);
1139 InitPosition(FALSE);
1142 XtAppInitialize(&appContext, "XBoard", shellOptions,
1143 XtNumber(shellOptions),
1144 &argc, argv, xboardResources, NULL, 0);
1146 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1147 clientResources, XtNumber(clientResources),
1150 xDisplay = XtDisplay(shellWidget);
1151 xScreen = DefaultScreen(xDisplay);
1152 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1155 * determine size, based on supplied or remembered -size, or screen size
1157 if (isdigit(appData.boardSize[0])) {
1158 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1159 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1160 &fontPxlSize, &smallLayout, &tinyLayout);
1162 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1163 programName, appData.boardSize);
1167 /* Find some defaults; use the nearest known size */
1168 SizeDefaults *szd, *nearest;
1169 int distance = 99999;
1170 nearest = szd = sizeDefaults;
1171 while (szd->name != NULL) {
1172 if (abs(szd->squareSize - squareSize) < distance) {
1174 distance = abs(szd->squareSize - squareSize);
1175 if (distance == 0) break;
1179 if (i < 2) lineGap = nearest->lineGap;
1180 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1181 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1182 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1183 if (i < 6) smallLayout = nearest->smallLayout;
1184 if (i < 7) tinyLayout = nearest->tinyLayout;
1187 SizeDefaults *szd = sizeDefaults;
1188 if (*appData.boardSize == NULLCHAR) {
1189 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1190 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1193 if (szd->name == NULL) szd--;
1194 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1196 while (szd->name != NULL &&
1197 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1198 if (szd->name == NULL) {
1199 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1200 programName, appData.boardSize);
1204 squareSize = szd->squareSize;
1205 lineGap = szd->lineGap;
1206 clockFontPxlSize = szd->clockFontPxlSize;
1207 coordFontPxlSize = szd->coordFontPxlSize;
1208 fontPxlSize = szd->fontPxlSize;
1209 smallLayout = szd->smallLayout;
1210 tinyLayout = szd->tinyLayout;
1211 // [HGM] font: use defaults from settings file if available and not overruled
1214 defaultLineGap = lineGap;
1215 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1217 /* [HR] height treated separately (hacked) */
1218 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1219 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1222 * Determine what fonts to use.
1224 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1227 * Detect if there are not enough colors available and adapt.
1229 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1230 appData.monoMode = True;
1233 forceMono = MakeColors();
1236 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1238 appData.monoMode = True;
1241 if (appData.monoMode && appData.debugMode) {
1242 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1243 (unsigned long) XWhitePixel(xDisplay, xScreen),
1244 (unsigned long) XBlackPixel(xDisplay, xScreen));
1247 ParseIcsTextColors();
1249 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1255 layoutName = "tinyLayout";
1256 } else if (smallLayout) {
1257 layoutName = "smallLayout";
1259 layoutName = "normalLayout";
1262 optList = BoardPopUp(squareSize, lineGap, (void*)
1268 InitDrawingHandle(optList + W_BOARD);
1269 currBoard = &optList[W_BOARD];
1270 boardWidget = optList[W_BOARD].handle;
1271 menuBarWidget = optList[W_MENU].handle;
1272 dropMenu = optList[W_DROP].handle;
1273 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1274 formWidget = XtParent(boardWidget);
1275 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1276 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1277 XtGetValues(optList[W_WHITE].handle, args, 2);
1278 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1279 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1280 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1281 XtGetValues(optList[W_PAUSE].handle, args, 2);
1283 AppendEnginesToMenu(appData.recentEngineList);
1285 xBoardWindow = XtWindow(boardWidget);
1287 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1288 // not need to go into InitDrawingSizes().
1291 * Create X checkmark bitmap and initialize option menu checks.
1293 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1294 checkmark_bits, checkmark_width, checkmark_height);
1300 ReadBitmap(&wIconPixmap, "icon_white.bm",
1301 icon_white_bits, icon_white_width, icon_white_height);
1302 ReadBitmap(&bIconPixmap, "icon_black.bm",
1303 icon_black_bits, icon_black_width, icon_black_height);
1304 iconPixmap = wIconPixmap;
1306 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1307 XtSetValues(shellWidget, args, i);
1310 * Create a cursor for the board widget.
1312 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1313 XChangeWindowAttributes(xDisplay, xBoardWindow,
1314 CWCursor, &window_attributes);
1317 * Inhibit shell resizing.
1319 shellArgs[0].value = (XtArgVal) &w;
1320 shellArgs[1].value = (XtArgVal) &h;
1321 XtGetValues(shellWidget, shellArgs, 2);
1322 shellArgs[4].value = shellArgs[2].value = w;
1323 shellArgs[5].value = shellArgs[3].value = h;
1324 // XtSetValues(shellWidget, &shellArgs[2], 4);
1325 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1326 marginH = h - boardHeight;
1328 CatchDeleteWindow(shellWidget, "QuitProc");
1333 if(appData.logoSize)
1334 { // locate and read user logo
1336 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1337 ASSIGN(userLogo, buf);
1340 if (appData.animate || appData.animateDragging)
1343 XtAugmentTranslations(formWidget,
1344 XtParseTranslationTable(globalTranslations));
1346 XtAddEventHandler(formWidget, KeyPressMask, False,
1347 (XtEventHandler) MoveTypeInProc, NULL);
1348 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1349 (XtEventHandler) EventProc, NULL);
1351 /* [AS] Restore layout */
1352 if( wpMoveHistory.visible ) {
1356 if( wpEvalGraph.visible )
1361 if( wpEngineOutput.visible ) {
1362 EngineOutputPopUp();
1367 if (errorExitStatus == -1) {
1368 if (appData.icsActive) {
1369 /* We now wait until we see "login:" from the ICS before
1370 sending the logon script (problems with timestamp otherwise) */
1371 /*ICSInitScript();*/
1372 if (appData.icsInputBox) ICSInputBoxPopUp();
1376 signal(SIGWINCH, TermSizeSigHandler);
1378 signal(SIGINT, IntSigHandler);
1379 signal(SIGTERM, IntSigHandler);
1380 if (*appData.cmailGameName != NULLCHAR) {
1381 signal(SIGUSR1, CmailSigHandler);
1385 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1388 // XtSetKeyboardFocus(shellWidget, formWidget);
1389 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1391 XtAppMainLoop(appContext);
1392 if (appData.debugMode) fclose(debugFP); // [DM] debug
1397 TermSizeSigHandler (int sig)
1403 IntSigHandler (int sig)
1409 CmailSigHandler (int sig)
1414 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1416 /* Activate call-back function CmailSigHandlerCallBack() */
1417 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1419 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1423 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1426 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1428 /**** end signal code ****/
1431 #define Abs(n) ((n)<0 ? -(n) : (n))
1435 InsertPxlSize (char *pattern, int targetPxlSize)
1437 char *base_fnt_lst, strInt[12], *p, *q;
1438 int alternatives, i, len, strIntLen;
1441 * Replace the "*" (if present) in the pixel-size slot of each
1442 * alternative with the targetPxlSize.
1446 while ((p = strchr(p, ',')) != NULL) {
1450 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1451 strIntLen = strlen(strInt);
1452 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1456 while (alternatives--) {
1457 char *comma = strchr(p, ',');
1458 for (i=0; i<14; i++) {
1459 char *hyphen = strchr(p, '-');
1461 if (comma && hyphen > comma) break;
1462 len = hyphen + 1 - p;
1463 if (i == 7 && *p == '*' && len == 2) {
1465 memcpy(q, strInt, strIntLen);
1475 len = comma + 1 - p;
1482 return base_fnt_lst;
1486 CreateFontSet (char *base_fnt_lst)
1489 char **missing_list;
1493 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1494 &missing_list, &missing_count, &def_string);
1495 if (appData.debugMode) {
1497 XFontStruct **font_struct_list;
1498 char **font_name_list;
1499 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1501 fprintf(debugFP, " got list %s, locale %s\n",
1502 XBaseFontNameListOfFontSet(fntSet),
1503 XLocaleOfFontSet(fntSet));
1504 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1505 for (i = 0; i < count; i++) {
1506 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1509 for (i = 0; i < missing_count; i++) {
1510 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1513 if (fntSet == NULL) {
1514 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1519 #else // not ENABLE_NLS
1521 * Find a font that matches "pattern" that is as close as
1522 * possible to the targetPxlSize. Prefer fonts that are k
1523 * pixels smaller to fonts that are k pixels larger. The
1524 * pattern must be in the X Consortium standard format,
1525 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1526 * The return value should be freed with XtFree when no
1530 FindFont (char *pattern, int targetPxlSize)
1532 char **fonts, *p, *best, *scalable, *scalableTail;
1533 int i, j, nfonts, minerr, err, pxlSize;
1535 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1537 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1538 programName, pattern);
1545 for (i=0; i<nfonts; i++) {
1548 if (*p != '-') continue;
1550 if (*p == NULLCHAR) break;
1551 if (*p++ == '-') j++;
1553 if (j < 7) continue;
1556 scalable = fonts[i];
1559 err = pxlSize - targetPxlSize;
1560 if (Abs(err) < Abs(minerr) ||
1561 (minerr > 0 && err < 0 && -err == minerr)) {
1567 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1568 /* If the error is too big and there is a scalable font,
1569 use the scalable font. */
1570 int headlen = scalableTail - scalable;
1571 p = (char *) XtMalloc(strlen(scalable) + 10);
1572 while (isdigit(*scalableTail)) scalableTail++;
1573 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1575 p = (char *) XtMalloc(strlen(best) + 2);
1576 safeStrCpy(p, best, strlen(best)+1 );
1578 if (appData.debugMode) {
1579 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1580 pattern, targetPxlSize, p);
1582 XFreeFontNames(fonts);
1588 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1591 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1597 EnableNamedMenuItem (char *menuRef, int state)
1599 MenuItem *item = MenuNameToItem(menuRef);
1601 if(item) XtSetSensitive(item->handle, state);
1605 EnableButtonBar (int state)
1607 XtSetSensitive(optList[W_BUTTON].handle, state);
1612 SetMenuEnables (Enables *enab)
1614 while (enab->name != NULL) {
1615 EnableNamedMenuItem(enab->name, enab->value);
1621 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1622 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1624 if(*nprms == 0) return;
1625 item = MenuNameToItem(prms[0]);
1626 if(item) ((MenuProc *) item->proc) ();
1630 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1632 RecentEngineEvent((int) (intptr_t) addr);
1636 AppendMenuItem (char *msg, int n)
1638 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1650 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1651 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1652 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1653 dmEnables[i].piece);
1654 XtSetSensitive(entry, p != NULL || !appData.testLegality
1655 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1656 && !appData.icsActive));
1658 while (p && *p++ == dmEnables[i].piece) count++;
1659 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1661 XtSetArg(args[j], XtNlabel, label); j++;
1662 XtSetValues(entry, args, j);
1667 do_flash_delay (unsigned long msec)
1673 FlashDelay (int flash_delay)
1675 XSync(xDisplay, False);
1676 if(flash_delay) do_flash_delay(flash_delay);
1680 Fraction (int x, int start, int stop)
1682 double f = ((double) x - start)/(stop - start);
1683 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1687 static WindowPlacement wpNew;
1690 CoDrag (Widget sh, WindowPlacement *wp)
1693 int j=0, touch=0, fudge = 2;
1694 GetActualPlacement(sh, wp);
1695 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1696 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1697 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1698 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1699 if(!touch ) return; // only windows that touch co-move
1700 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1701 int heightInc = wpNew.height - wpMain.height;
1702 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1703 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1704 wp->y += fracTop * heightInc;
1705 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1706 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1707 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1708 int widthInc = wpNew.width - wpMain.width;
1709 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1710 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1711 wp->y += fracLeft * widthInc;
1712 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1713 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1715 wp->x += wpNew.x - wpMain.x;
1716 wp->y += wpNew.y - wpMain.y;
1717 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1718 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1719 XtSetArg(args[j], XtNx, wp->x); j++;
1720 XtSetArg(args[j], XtNy, wp->y); j++;
1721 XtSetValues(sh, args, j);
1725 ReSize (WindowPlacement *wp)
1728 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1729 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1730 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1731 if(sqy < sqx) sqx = sqy;
1732 if(sqx != squareSize) {
1733 squareSize = sqx; // adopt new square size
1734 CreatePNGPieces(); // make newly scaled pieces
1735 InitDrawingSizes(0, 0); // creates grid etc.
1736 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1737 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1738 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1739 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1740 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1743 static XtIntervalId delayedDragID = 0;
1752 GetActualPlacement(shellWidget, &wpNew);
1753 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1754 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1755 busy = 0; return; // false alarm
1758 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1759 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1760 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1761 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1763 DrawPosition(True, NULL);
1764 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1772 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1774 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1778 EventProc (Widget widget, caddr_t unused, XEvent *event)
1780 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1781 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1785 * event handler for redrawing the board
1788 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1790 DrawPosition(True, NULL);
1795 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1796 { // [HGM] pv: walk PV
1797 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1800 static int savedIndex; /* gross that this is global */
1803 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1806 XawTextPosition index, dummy;
1809 XawTextGetSelectionPos(w, &index, &dummy);
1810 XtSetArg(arg, XtNstring, &val);
1811 XtGetValues(w, &arg, 1);
1812 ReplaceComment(savedIndex, val);
1813 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1814 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1818 EditCommentPopUp (int index, char *title, char *text)
1821 if (text == NULL) text = "";
1822 NewCommentPopup(title, text, index);
1826 CommentPopUp (char *title, char *text)
1828 savedIndex = currentMove; // [HGM] vari
1829 NewCommentPopup(title, text, currentMove);
1835 PopDown(CommentDlg);
1839 /* Disable all user input other than deleting the window */
1840 static int frozen = 0;
1846 /* Grab by a widget that doesn't accept input */
1847 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1851 /* Undo a FreezeUI */
1855 if (!frozen) return;
1856 XtRemoveGrab(optList[W_MESSG].handle);
1864 static int oldPausing = FALSE;
1865 static GameMode oldmode = (GameMode) -1;
1868 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1870 if (pausing != oldPausing) {
1871 oldPausing = pausing;
1872 MarkMenuItem("Mode.Pause", pausing);
1874 if (appData.showButtonBar) {
1875 /* Always toggle, don't set. Previous code messes up when
1876 invoked while the button is pressed, as releasing it
1877 toggles the state again. */
1880 XtSetArg(args[0], XtNbackground, &oldbg);
1881 XtSetArg(args[1], XtNforeground, &oldfg);
1882 XtGetValues(optList[W_PAUSE].handle,
1884 XtSetArg(args[0], XtNbackground, oldfg);
1885 XtSetArg(args[1], XtNforeground, oldbg);
1887 XtSetValues(optList[W_PAUSE].handle, args, 2);
1891 wname = ModeToWidgetName(oldmode);
1892 if (wname != NULL) {
1893 MarkMenuItem(wname, False);
1895 wname = ModeToWidgetName(gameMode);
1896 if (wname != NULL) {
1897 MarkMenuItem(wname, True);
1900 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1902 /* Maybe all the enables should be handled here, not just this one */
1903 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1905 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1910 * Button/menu procedures
1913 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1914 char *selected_fen_position=NULL;
1917 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1918 Atom *type_return, XtPointer *value_return,
1919 unsigned long *length_return, int *format_return)
1921 char *selection_tmp;
1923 // if (!selected_fen_position) return False; /* should never happen */
1924 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1925 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1926 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1929 if (f == NULL) return False;
1933 selection_tmp = XtMalloc(len + 1);
1934 count = fread(selection_tmp, 1, len, f);
1937 XtFree(selection_tmp);
1940 selection_tmp[len] = NULLCHAR;
1942 /* note: since no XtSelectionDoneProc was registered, Xt will
1943 * automatically call XtFree on the value returned. So have to
1944 * make a copy of it allocated with XtMalloc */
1945 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1946 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1949 *value_return=selection_tmp;
1950 *length_return=strlen(selection_tmp);
1951 *type_return=*target;
1952 *format_return = 8; /* bits per byte */
1954 } else if (*target == XA_TARGETS(xDisplay)) {
1955 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1956 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1957 targets_tmp[1] = XA_STRING;
1958 *value_return = targets_tmp;
1959 *type_return = XA_ATOM;
1962 // This code leads to a read of value_return out of bounds on 64-bit systems.
1963 // Other code which I have seen always sets *format_return to 32 independent of
1964 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1965 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1966 *format_return = 8 * sizeof(Atom);
1967 if (*format_return > 32) {
1968 *length_return *= *format_return / 32;
1969 *format_return = 32;
1972 *format_return = 32;
1980 /* note: when called from menu all parameters are NULL, so no clue what the
1981 * Widget which was clicked on was, or what the click event was
1984 CopySomething (char *src)
1986 selected_fen_position = src;
1988 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1989 * have a notion of a position that is selected but not copied.
1990 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1992 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1994 SendPositionSelection,
1995 NULL/* lose_ownership_proc */ ,
1996 NULL/* transfer_done_proc */);
1997 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1999 SendPositionSelection,
2000 NULL/* lose_ownership_proc */ ,
2001 NULL/* transfer_done_proc */);
2004 /* function called when the data to Paste is ready */
2006 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2007 Atom *type, XtPointer value, unsigned long *len, int *format)
2010 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2011 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2012 EditPositionPasteFEN(fenstr);
2016 /* called when Paste Position button is pressed,
2017 * all parameters will be NULL */
2019 PastePositionProc ()
2021 XtGetSelectionValue(menuBarWidget,
2022 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2023 /* (XtSelectionCallbackProc) */ PastePositionCB,
2024 NULL, /* client_data passed to PastePositionCB */
2026 /* better to use the time field from the event that triggered the
2027 * call to this function, but that isn't trivial to get
2034 /* note: when called from menu all parameters are NULL, so no clue what the
2035 * Widget which was clicked on was, or what the click event was
2037 /* function called when the data to Paste is ready */
2039 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2040 Atom *type, XtPointer value, unsigned long *len, int *format)
2043 if (value == NULL || *len == 0) {
2044 return; /* nothing had been selected to copy */
2046 f = fopen(gamePasteFilename, "w");
2048 DisplayError(_("Can't open temp file"), errno);
2051 fwrite(value, 1, *len, f);
2054 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2057 /* called when Paste Game button is pressed,
2058 * all parameters will be NULL */
2062 XtGetSelectionValue(menuBarWidget,
2063 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2064 /* (XtSelectionCallbackProc) */ PasteGameCB,
2065 NULL, /* client_data passed to PasteGameCB */
2067 /* better to use the time field from the event that triggered the
2068 * call to this function, but that isn't trivial to get
2077 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2084 { // bassic primitive for determining if modifier keys are pressed
2085 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2088 XQueryKeymap(xDisplay,keys);
2089 for(i=0; i<6; i++) {
2091 j = XKeysymToKeycode(xDisplay, codes[i]);
2092 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2098 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2102 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2103 if ( n == 1 && *buf >= 32 // printable
2104 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2105 ) BoxAutoPopUp (buf);
2109 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2110 { // [HGM] input: let up-arrow recall previous line from history
2115 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2116 { // [HGM] input: let down-arrow recall next line from history
2121 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2127 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2129 if (!TempBackwardActive) {
2130 TempBackwardActive = True;
2136 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2138 /* Check to see if triggered by a key release event for a repeating key.
2139 * If so the next queued event will be a key press of the same key at the same time */
2140 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2142 XPeekEvent(xDisplay, &next);
2143 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2144 next.xkey.keycode == event->xkey.keycode)
2148 TempBackwardActive = False;
2152 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2153 { // called as key binding
2156 if (nprms && *nprms > 0)
2160 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2166 { // called from menu
2167 ManInner(NULL, NULL, NULL, NULL);
2171 SetWindowTitle (char *text, char *title, char *icon)
2175 if (appData.titleInWindow) {
2177 XtSetArg(args[i], XtNlabel, text); i++;
2178 XtSetValues(titleWidget, args, i);
2181 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2182 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2183 XtSetValues(shellWidget, args, i);
2184 XSync(xDisplay, False);
2189 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2195 DisplayIcsInteractionTitle (String message)
2197 if (oldICSInteractionTitle == NULL) {
2198 /* Magic to find the old window title, adapted from vim */
2199 char *wina = getenv("WINDOWID");
2201 Window win = (Window) atoi(wina);
2202 Window root, parent, *children;
2203 unsigned int nchildren;
2204 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2206 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2207 if (!XQueryTree(xDisplay, win, &root, &parent,
2208 &children, &nchildren)) break;
2209 if (children) XFree((void *)children);
2210 if (parent == root || parent == 0) break;
2213 XSetErrorHandler(oldHandler);
2215 if (oldICSInteractionTitle == NULL) {
2216 oldICSInteractionTitle = "xterm";
2219 printf("\033]0;%s\007", message);
2224 XtIntervalId delayedEventTimerXID = 0;
2225 DelayedEventCallback delayedEventCallback = 0;
2230 delayedEventTimerXID = 0;
2231 delayedEventCallback();
2235 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2237 if(delayedEventTimerXID && delayedEventCallback == cb)
2238 // [HGM] alive: replace, rather than add or flush identical event
2239 XtRemoveTimeOut(delayedEventTimerXID);
2240 delayedEventCallback = cb;
2241 delayedEventTimerXID =
2242 XtAppAddTimeOut(appContext, millisec,
2243 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2246 DelayedEventCallback
2249 if (delayedEventTimerXID) {
2250 return delayedEventCallback;
2257 CancelDelayedEvent ()
2259 if (delayedEventTimerXID) {
2260 XtRemoveTimeOut(delayedEventTimerXID);
2261 delayedEventTimerXID = 0;
2265 XtIntervalId loadGameTimerXID = 0;
2268 LoadGameTimerRunning ()
2270 return loadGameTimerXID != 0;
2274 StopLoadGameTimer ()
2276 if (loadGameTimerXID != 0) {
2277 XtRemoveTimeOut(loadGameTimerXID);
2278 loadGameTimerXID = 0;
2286 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2288 loadGameTimerXID = 0;
2293 StartLoadGameTimer (long millisec)
2296 XtAppAddTimeOut(appContext, millisec,
2297 (XtTimerCallbackProc) LoadGameTimerCallback,
2301 XtIntervalId analysisClockXID = 0;
2304 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2306 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2307 || appData.icsEngineAnalyze) { // [DM]
2308 AnalysisPeriodicEvent(0);
2309 StartAnalysisClock();
2314 StartAnalysisClock ()
2317 XtAppAddTimeOut(appContext, 2000,
2318 (XtTimerCallbackProc) AnalysisClockCallback,
2322 XtIntervalId clockTimerXID = 0;
2325 ClockTimerRunning ()
2327 return clockTimerXID != 0;
2333 if (clockTimerXID != 0) {
2334 XtRemoveTimeOut(clockTimerXID);
2343 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2350 StartClockTimer (long millisec)
2353 XtAppAddTimeOut(appContext, millisec,
2354 (XtTimerCallbackProc) ClockTimerCallback,
2359 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2363 Widget w = (Widget) opt->handle;
2365 /* check for low time warning */
2366 Pixel foregroundOrWarningColor = timerForegroundPixel;
2369 appData.lowTimeWarning &&
2370 (timer / 1000) < appData.icsAlarmTime)
2371 foregroundOrWarningColor = lowTimeWarningColor;
2373 if (appData.clockMode) {
2374 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2375 XtSetArg(args[0], XtNlabel, buf);
2377 snprintf(buf, MSG_SIZ, "%s ", color);
2378 XtSetArg(args[0], XtNlabel, buf);
2383 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2384 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2386 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2387 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2390 XtSetValues(w, args, 3);
2393 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2396 SetClockIcon (int color)
2399 Pixmap pm = *clockIcons[color];
2400 if (iconPixmap != pm) {
2402 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2403 XtSetValues(shellWidget, args, 1);
2408 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2410 InputSource *is = (InputSource *) closure;
2415 if (is->lineByLine) {
2416 count = read(is->fd, is->unused,
2417 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2419 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2422 is->unused += count;
2424 while (p < is->unused) {
2425 q = memchr(p, '\n', is->unused - p);
2426 if (q == NULL) break;
2428 (is->func)(is, is->closure, p, q - p, 0);
2432 while (p < is->unused) {
2437 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2442 (is->func)(is, is->closure, is->buf, count, error);
2447 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2450 ChildProc *cp = (ChildProc *) pr;
2452 is = (InputSource *) calloc(1, sizeof(InputSource));
2453 is->lineByLine = lineByLine;
2457 is->fd = fileno(stdin);
2459 is->kind = cp->kind;
2460 is->fd = cp->fdFrom;
2463 is->unused = is->buf;
2466 is->xid = XtAppAddInput(appContext, is->fd,
2467 (XtPointer) (XtInputReadMask),
2468 (XtInputCallbackProc) DoInputCallback,
2470 is->closure = closure;
2471 return (InputSourceRef) is;
2475 RemoveInputSource (InputSourceRef isr)
2477 InputSource *is = (InputSource *) isr;
2479 if (is->xid == 0) return;
2480 XtRemoveInput(is->xid);
2486 static Boolean frameWaiting;
2489 FrameAlarm (int sig)
2491 frameWaiting = False;
2492 /* In case System-V style signals. Needed?? */
2493 signal(SIGALRM, FrameAlarm);
2497 FrameDelay (int time)
2499 struct itimerval delay;
2501 XSync(xDisplay, False);
2504 frameWaiting = True;
2505 signal(SIGALRM, FrameAlarm);
2506 delay.it_interval.tv_sec =
2507 delay.it_value.tv_sec = time / 1000;
2508 delay.it_interval.tv_usec =
2509 delay.it_value.tv_usec = (time % 1000) * 1000;
2510 setitimer(ITIMER_REAL, &delay, NULL);
2511 while (frameWaiting) pause();
2512 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2513 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2514 setitimer(ITIMER_REAL, &delay, NULL);
2521 FrameDelay (int time)
2523 XSync(xDisplay, False);
2525 usleep(time * 1000);
2531 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2533 char buf[MSG_SIZ], *logoName = buf;
2534 if(appData.logo[n][0]) {
2535 logoName = appData.logo[n];
2536 } else if(appData.autoLogo) {
2537 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2538 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2539 } else if(appData.directory[n] && appData.directory[n][0]) {
2540 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2544 { ASSIGN(cps->programLogo, logoName); }
2548 UpdateLogos (int displ)
2550 if(optList[W_WHITE-1].handle == NULL) return;
2551 LoadLogo(&first, 0, 0);
2552 LoadLogo(&second, 1, appData.icsActive);
2553 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);