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"
206 #include "xevalgraph.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;
325 #define INPUT_SOURCE_BUF_SIZE 8192
334 char buf[INPUT_SOURCE_BUF_SIZE];
339 /* This magic number is the number of intermediate frames used
340 in each half of the animation. For short moves it's reduced
341 by 1. The total number of frames will be factor * 2 + 1. */
344 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
351 DropMenuEnables dmEnables[] = {
368 XtResource clientResources[] = {
369 { "flashCount", "flashCount", XtRInt, sizeof(int),
370 XtOffset(AppDataPtr, flashCount), XtRImmediate,
371 (XtPointer) FLASH_COUNT },
374 XrmOptionDescRec shellOptions[] = {
375 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
376 { "-flash", "flashCount", XrmoptionNoArg, "3" },
377 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
380 XtActionsRec boardActions[] = {
381 { "DrawPosition", DrawPositionProc },
382 { "HandlePV", HandlePV },
383 { "SelectPV", SelectPV },
384 { "StopPV", StopPV },
385 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
386 { "QuitProc", QuitWrapper },
387 { "ManProc", ManInner },
388 { "TempBackwardProc", TempBackwardProc },
389 { "TempForwardProc", TempForwardProc },
390 { "CommentClick", (XtActionProc) CommentClick },
391 { "GenericPopDown", (XtActionProc) GenericPopDown },
392 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
393 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
394 { "SelectMove", (XtActionProc) SelectMove },
395 { "LoadSelectedProc", LoadSelectedProc },
396 { "SetFilterProc", SetFilterProc },
397 { "TypeInProc", TypeInProc },
398 { "EnterKeyProc", EnterKeyProc },
399 { "UpKeyProc", UpKeyProc },
400 { "DownKeyProc", DownKeyProc },
401 { "WheelProc", WheelProc },
402 { "TabProc", TabProc },
405 char globalTranslations[] =
406 ":<Key>F9: MenuItem(Actions.Resign) \n \
407 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
408 :Meta<Key>V: MenuItem(File.NewVariant) \n \
409 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
410 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
411 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
412 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
413 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
414 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
415 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
416 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
417 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
418 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
419 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
420 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
421 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
422 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
423 :Ctrl<Key>q: MenuItem(File.Quit) \n \
424 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
425 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
426 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
427 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
428 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
429 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
430 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
431 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
432 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
433 :Meta<Key>G: MenuItem(View.GameList) \n \
434 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
435 :<Key>Pause: MenuItem(Mode.Pause) \n \
436 :<Key>F3: MenuItem(Action.Accept) \n \
437 :<Key>F4: MenuItem(Action.Decline) \n \
438 :<Key>F12: MenuItem(Action.Rematch) \n \
439 :<Key>F5: MenuItem(Action.CallFlag) \n \
440 :<Key>F6: MenuItem(Action.Draw) \n \
441 :<Key>F7: MenuItem(Action.Adjourn) \n \
442 :<Key>F8: MenuItem(Action.Abort) \n \
443 :<Key>F10: MenuItem(Action.StopObserving) \n \
444 :<Key>F11: MenuItem(Action.StopExamining) \n \
445 :Ctrl<Key>d: MenuItem(DebugProc) \n \
446 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
447 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
448 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
449 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
450 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
451 :<Key>Left: MenuItem(Edit.Backward) \n \
452 :<Key>Right: MenuItem(Edit.Forward) \n \
453 :<Key>Home: MenuItem(Edit.Revert) \n \
454 :<Key>End: MenuItem(Edit.TruncateGame) \n \
455 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
456 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
457 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
458 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
459 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
460 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
461 #ifndef OPTIONSDIALOG
463 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
464 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
465 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
466 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
467 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
470 :<Key>F1: MenuItem(Help.ManXBoard) \n \
471 :<Key>F2: MenuItem(View.FlipView) \n \
472 :<KeyDown>Return: TempBackwardProc() \n \
473 :<KeyUp>Return: TempForwardProc() \n";
475 char ICSInputTranslations[] =
476 "<Key>Up: UpKeyProc() \n "
477 "<Key>Down: DownKeyProc() \n "
478 "<Key>Return: EnterKeyProc() \n";
480 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
481 // as the widget is destroyed before the up-click can call extend-end
482 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
484 String xboardResources[] = {
485 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
490 /* Max possible square size */
491 #define MAXSQSIZE 256
493 static int xpm_avail[MAXSQSIZE];
495 #ifdef HAVE_DIR_STRUCT
497 /* Extract piece size from filename */
499 xpm_getsize (char *name, int len, char *ext)
507 if ((p=strchr(name, '.')) == NULL ||
508 StrCaseCmp(p+1, ext) != 0)
514 while (*p && isdigit(*p))
521 /* Setup xpm_avail */
523 xpm_getavail (char *dirname, char *ext)
529 for (i=0; i<MAXSQSIZE; ++i)
532 if (appData.debugMode)
533 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
535 dir = opendir(dirname);
538 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
539 programName, dirname);
543 while ((ent=readdir(dir)) != NULL) {
544 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
545 if (i > 0 && i < MAXSQSIZE)
555 xpm_print_avail (FILE *fp, char *ext)
559 fprintf(fp, _("Available `%s' sizes:\n"), ext);
560 for (i=1; i<MAXSQSIZE; ++i) {
566 /* Return XPM piecesize closest to size */
568 xpm_closest_to (char *dirname, int size, char *ext)
571 int sm_diff = MAXSQSIZE;
575 xpm_getavail(dirname, ext);
577 if (appData.debugMode)
578 xpm_print_avail(stderr, ext);
580 for (i=1; i<MAXSQSIZE; ++i) {
583 diff = (diff<0) ? -diff : diff;
584 if (diff < sm_diff) {
592 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
598 #else /* !HAVE_DIR_STRUCT */
599 /* If we are on a system without a DIR struct, we can't
600 read the directory, so we can't collect a list of
601 filenames, etc., so we can't do any size-fitting. */
603 xpm_closest_to (char *dirname, int size, char *ext)
606 Warning: No DIR structure found on this system --\n\
607 Unable to autosize for XPM/XIM pieces.\n\
608 Please report this error to %s.\n\
609 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
612 #endif /* HAVE_DIR_STRUCT */
615 /* Arrange to catch delete-window events */
616 Atom wm_delete_window;
618 CatchDeleteWindow (Widget w, String procname)
621 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
622 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
623 XtAugmentTranslations(w, XtParseTranslationTable(buf));
630 XtSetArg(args[0], XtNiconic, False);
631 XtSetValues(shellWidget, args, 1);
633 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
636 //---------------------------------------------------------------------------------------------------------
637 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
640 #define CW_USEDEFAULT (1<<31)
641 #define ICS_TEXT_MENU_SIZE 90
642 #define DEBUG_FILE "xboard.debug"
643 #define SetCurrentDirectory chdir
644 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
648 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
651 // front-end part of option handling
653 // [HGM] This platform-dependent table provides the location for storing the color info
654 extern char *crWhite, * crBlack;
658 &appData.whitePieceColor,
659 &appData.blackPieceColor,
660 &appData.lightSquareColor,
661 &appData.darkSquareColor,
662 &appData.highlightSquareColor,
663 &appData.premoveHighlightColor,
664 &appData.lowTimeWarningColor,
675 // [HGM] font: keep a font for each square size, even non-stndard ones
678 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
679 char *fontTable[NUM_FONTS][MAX_SIZE];
682 ParseFont (char *name, int number)
683 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
685 if(sscanf(name, "size%d:", &size)) {
686 // [HGM] font: font is meant for specific boardSize (likely from settings file);
687 // defer processing it until we know if it matches our board size
688 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
689 fontTable[number][size] = strdup(strchr(name, ':')+1);
690 fontValid[number][size] = True;
695 case 0: // CLOCK_FONT
696 appData.clockFont = strdup(name);
698 case 1: // MESSAGE_FONT
699 appData.font = strdup(name);
701 case 2: // COORD_FONT
702 appData.coordFont = strdup(name);
707 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
712 { // only 2 fonts currently
713 appData.clockFont = CLOCK_FONT_NAME;
714 appData.coordFont = COORD_FONT_NAME;
715 appData.font = DEFAULT_FONT_NAME;
720 { // no-op, until we identify the code for this already in XBoard and move it here
724 ParseColor (int n, char *name)
725 { // in XBoard, just copy the color-name string
726 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
730 ParseTextAttribs (ColorClass cc, char *s)
732 (&appData.colorShout)[cc] = strdup(s);
736 ParseBoardSize (void *addr, char *name)
738 appData.boardSize = strdup(name);
743 { // In XBoard the sound-playing program takes care of obtaining the actual sound
747 SetCommPortDefaults ()
748 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
751 // [HGM] args: these three cases taken out to stay in front-end
753 SaveFontArg (FILE *f, ArgDescriptor *ad)
756 int i, n = (int)(intptr_t)ad->argLoc;
758 case 0: // CLOCK_FONT
759 name = appData.clockFont;
761 case 1: // MESSAGE_FONT
764 case 2: // COORD_FONT
765 name = appData.coordFont;
770 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
771 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
772 fontTable[n][squareSize] = strdup(name);
773 fontValid[n][squareSize] = True;
776 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
777 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
782 { // nothing to do, as the sounds are at all times represented by their text-string names already
786 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
787 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
788 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
792 SaveColor (FILE *f, ArgDescriptor *ad)
793 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
794 if(colorVariable[(int)(intptr_t)ad->argLoc])
795 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
799 SaveBoardSize (FILE *f, char *name, void *addr)
800 { // wrapper to shield back-end from BoardSize & sizeInfo
801 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
805 ParseCommPortSettings (char *s)
806 { // no such option in XBoard (yet)
812 GetActualPlacement (Widget wg, WindowPlacement *wp)
814 XWindowAttributes winAt;
821 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
822 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
823 wp->x = rx - winAt.x;
824 wp->y = ry - winAt.y;
825 wp->height = winAt.height;
826 wp->width = winAt.width;
827 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
832 { // wrapper to shield use of window handles from back-end (make addressible by number?)
833 // In XBoard this will have to wait until awareness of window parameters is implemented
834 GetActualPlacement(shellWidget, &wpMain);
835 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
836 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
837 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
838 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
839 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
840 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
844 PrintCommPortSettings (FILE *f, char *name)
845 { // This option does not exist in XBoard
849 EnsureOnScreen (int *x, int *y, int minX, int minY)
856 { // [HGM] args: allows testing if main window is realized from back-end
857 return xBoardWindow != 0;
861 PopUpStartupDialog ()
862 { // start menu not implemented in XBoard
866 ConvertToLine (int argc, char **argv)
868 static char line[128*1024], buf[1024];
872 for(i=1; i<argc; i++)
874 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
875 && argv[i][0] != '{' )
876 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
878 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
879 strncat(line, buf, 128*1024 - strlen(line) - 1 );
882 line[strlen(line)-1] = NULLCHAR;
886 //--------------------------------------------------------------------------------------------
889 ResizeBoardWindow (int w, int h, int inhibit)
891 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
893 shellArgs[0].value = w;
894 shellArgs[1].value = h;
895 shellArgs[4].value = shellArgs[2].value = w;
896 shellArgs[5].value = shellArgs[3].value = h;
897 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
899 XSync(xDisplay, False);
903 MakeOneColor (char *name, Pixel *color)
906 if (!appData.monoMode) {
907 vFrom.addr = (caddr_t) name;
908 vFrom.size = strlen(name);
909 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
910 if (vTo.addr == NULL) {
911 appData.monoMode = True;
914 *color = *(Pixel *) vTo.addr;
922 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
923 int forceMono = False;
925 if (appData.lowTimeWarning)
926 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
927 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
928 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
934 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
935 { // detervtomine what fonts to use, and create them
939 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
940 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
941 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
942 appData.font = fontTable[MESSAGE_FONT][squareSize];
943 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
944 appData.coordFont = fontTable[COORD_FONT][squareSize];
947 appData.font = InsertPxlSize(appData.font, fontPxlSize);
948 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
949 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
950 fontSet = CreateFontSet(appData.font);
951 clockFontSet = CreateFontSet(appData.clockFont);
953 /* For the coordFont, use the 0th font of the fontset. */
954 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
955 XFontStruct **font_struct_list;
956 XFontSetExtents *fontSize;
957 char **font_name_list;
958 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
959 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
960 coordFontStruct = XQueryFont(xDisplay, coordFontID);
961 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
962 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
965 appData.font = FindFont(appData.font, fontPxlSize);
966 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
967 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
968 clockFontID = XLoadFont(xDisplay, appData.clockFont);
969 clockFontStruct = XQueryFont(xDisplay, clockFontID);
970 coordFontID = XLoadFont(xDisplay, appData.coordFont);
971 coordFontStruct = XQueryFont(xDisplay, coordFontID);
972 // textHeight in !NLS mode!
974 countFontID = coordFontID; // [HGM] holdings
975 countFontStruct = coordFontStruct;
977 xdb = XtDatabase(xDisplay);
979 XrmPutLineResource(&xdb, "*international: True");
980 vTo.size = sizeof(XFontSet);
981 vTo.addr = (XtPointer) &fontSet;
982 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
984 XrmPutStringResource(&xdb, "*font", appData.font);
994 case ArgInt: p = " N"; break;
995 case ArgString: p = " STR"; break;
996 case ArgBoolean: p = " TF"; break;
997 case ArgSettingsFilename:
998 case ArgFilename: p = " FILE"; break;
999 case ArgX: p = " Nx"; break;
1000 case ArgY: p = " Ny"; break;
1001 case ArgAttribs: p = " TEXTCOL"; break;
1002 case ArgColor: p = " COL"; break;
1003 case ArgFont: p = " FONT"; break;
1004 case ArgBoardSize: p = " SIZE"; break;
1005 case ArgFloat: p = " FLOAT"; break;
1010 case ArgCommSettings:
1021 ArgDescriptor *q, *p = argDescriptors+5;
1022 printf("\nXBoard accepts the following options:\n"
1023 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1024 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1025 " SIZE = board-size spec(s)\n"
1026 " Within parentheses are short forms, or options to set to true or false.\n"
1027 " Persistent options (saved in the settings file) are marked with *)\n\n");
1029 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1030 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1031 if(p->save) strcat(buf+len, "*");
1032 for(q=p+1; q->argLoc == p->argLoc; q++) {
1033 if(q->argName[0] == '-') continue;
1034 strcat(buf+len, q == p+1 ? " (" : " ");
1035 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1037 if(q != p+1) strcat(buf+len, ")");
1039 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1042 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1046 main (int argc, char **argv)
1048 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1049 XSetWindowAttributes window_attributes;
1051 Dimension boardWidth, boardHeight, w, h;
1053 int forceMono = False;
1055 srandom(time(0)); // [HGM] book: make random truly random
1057 setbuf(stdout, NULL);
1058 setbuf(stderr, NULL);
1061 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1062 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1066 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1071 programName = strrchr(argv[0], '/');
1072 if (programName == NULL)
1073 programName = argv[0];
1078 XtSetLanguageProc(NULL, NULL, NULL);
1079 if (appData.debugMode) {
1080 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1083 bindtextdomain(PACKAGE, LOCALEDIR);
1084 textdomain(PACKAGE);
1087 appData.boardSize = "";
1088 InitAppData(ConvertToLine(argc, argv));
1090 if (p == NULL) p = "/tmp";
1091 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1092 gameCopyFilename = (char*) malloc(i);
1093 gamePasteFilename = (char*) malloc(i);
1094 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1095 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1097 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1098 static char buf[MSG_SIZ];
1099 EscapeExpand(buf, appData.firstInitString);
1100 appData.firstInitString = strdup(buf);
1101 EscapeExpand(buf, appData.secondInitString);
1102 appData.secondInitString = strdup(buf);
1103 EscapeExpand(buf, appData.firstComputerString);
1104 appData.firstComputerString = strdup(buf);
1105 EscapeExpand(buf, appData.secondComputerString);
1106 appData.secondComputerString = strdup(buf);
1109 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1112 if (chdir(chessDir) != 0) {
1113 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1119 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1120 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1121 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1122 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1125 setbuf(debugFP, NULL);
1128 /* [HGM,HR] make sure board size is acceptable */
1129 if(appData.NrFiles > BOARD_FILES ||
1130 appData.NrRanks > BOARD_RANKS )
1131 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1134 /* This feature does not work; animation needs a rewrite */
1135 appData.highlightDragging = FALSE;
1139 gameInfo.variant = StringToVariant(appData.variant);
1140 InitPosition(FALSE);
1143 XtAppInitialize(&appContext, "XBoard", shellOptions,
1144 XtNumber(shellOptions),
1145 &argc, argv, xboardResources, NULL, 0);
1147 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1148 clientResources, XtNumber(clientResources),
1151 xDisplay = XtDisplay(shellWidget);
1152 xScreen = DefaultScreen(xDisplay);
1153 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1156 * determine size, based on supplied or remembered -size, or screen size
1158 if (isdigit(appData.boardSize[0])) {
1159 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1160 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1161 &fontPxlSize, &smallLayout, &tinyLayout);
1163 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1164 programName, appData.boardSize);
1168 /* Find some defaults; use the nearest known size */
1169 SizeDefaults *szd, *nearest;
1170 int distance = 99999;
1171 nearest = szd = sizeDefaults;
1172 while (szd->name != NULL) {
1173 if (abs(szd->squareSize - squareSize) < distance) {
1175 distance = abs(szd->squareSize - squareSize);
1176 if (distance == 0) break;
1180 if (i < 2) lineGap = nearest->lineGap;
1181 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1182 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1183 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1184 if (i < 6) smallLayout = nearest->smallLayout;
1185 if (i < 7) tinyLayout = nearest->tinyLayout;
1188 SizeDefaults *szd = sizeDefaults;
1189 if (*appData.boardSize == NULLCHAR) {
1190 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1191 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1194 if (szd->name == NULL) szd--;
1195 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1197 while (szd->name != NULL &&
1198 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1199 if (szd->name == NULL) {
1200 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1201 programName, appData.boardSize);
1205 squareSize = szd->squareSize;
1206 lineGap = szd->lineGap;
1207 clockFontPxlSize = szd->clockFontPxlSize;
1208 coordFontPxlSize = szd->coordFontPxlSize;
1209 fontPxlSize = szd->fontPxlSize;
1210 smallLayout = szd->smallLayout;
1211 tinyLayout = szd->tinyLayout;
1212 // [HGM] font: use defaults from settings file if available and not overruled
1215 defaultLineGap = lineGap;
1216 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1218 /* [HR] height treated separately (hacked) */
1219 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1220 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1223 * Determine what fonts to use.
1225 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1228 * Detect if there are not enough colors available and adapt.
1230 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1231 appData.monoMode = True;
1234 forceMono = MakeColors();
1237 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1239 appData.monoMode = True;
1242 if (appData.monoMode && appData.debugMode) {
1243 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1244 (unsigned long) XWhitePixel(xDisplay, xScreen),
1245 (unsigned long) XBlackPixel(xDisplay, xScreen));
1248 ParseIcsTextColors();
1250 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1256 layoutName = "tinyLayout";
1257 } else if (smallLayout) {
1258 layoutName = "smallLayout";
1260 layoutName = "normalLayout";
1263 optList = BoardPopUp(squareSize, lineGap, (void*)
1269 InitDrawingHandle(optList + W_BOARD);
1270 currBoard = &optList[W_BOARD];
1271 boardWidget = optList[W_BOARD].handle;
1272 menuBarWidget = optList[W_MENU].handle;
1273 dropMenu = optList[W_DROP].handle;
1274 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1275 formWidget = XtParent(boardWidget);
1276 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1277 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1278 XtGetValues(optList[W_WHITE].handle, args, 2);
1279 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1280 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1281 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1282 XtGetValues(optList[W_PAUSE].handle, args, 2);
1284 AppendEnginesToMenu(appData.recentEngineList);
1286 xBoardWindow = XtWindow(boardWidget);
1288 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1289 // not need to go into InitDrawingSizes().
1292 * Create X checkmark bitmap and initialize option menu checks.
1294 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1295 checkmark_bits, checkmark_width, checkmark_height);
1301 ReadBitmap(&wIconPixmap, "icon_white.bm",
1302 icon_white_bits, icon_white_width, icon_white_height);
1303 ReadBitmap(&bIconPixmap, "icon_black.bm",
1304 icon_black_bits, icon_black_width, icon_black_height);
1305 iconPixmap = wIconPixmap;
1307 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1308 XtSetValues(shellWidget, args, i);
1311 * Create a cursor for the board widget.
1313 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1314 XChangeWindowAttributes(xDisplay, xBoardWindow,
1315 CWCursor, &window_attributes);
1318 * Inhibit shell resizing.
1320 shellArgs[0].value = (XtArgVal) &w;
1321 shellArgs[1].value = (XtArgVal) &h;
1322 XtGetValues(shellWidget, shellArgs, 2);
1323 shellArgs[4].value = shellArgs[2].value = w;
1324 shellArgs[5].value = shellArgs[3].value = h;
1325 // XtSetValues(shellWidget, &shellArgs[2], 4);
1326 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1327 marginH = h - boardHeight;
1329 CatchDeleteWindow(shellWidget, "QuitProc");
1334 if(appData.logoSize)
1335 { // locate and read user logo
1337 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1338 ASSIGN(userLogo, buf);
1341 if (appData.animate || appData.animateDragging)
1344 XtAugmentTranslations(formWidget,
1345 XtParseTranslationTable(globalTranslations));
1347 XtAddEventHandler(formWidget, KeyPressMask, False,
1348 (XtEventHandler) MoveTypeInProc, NULL);
1349 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1350 (XtEventHandler) EventProc, NULL);
1352 /* [AS] Restore layout */
1353 if( wpMoveHistory.visible ) {
1357 if( wpEvalGraph.visible )
1362 if( wpEngineOutput.visible ) {
1363 EngineOutputPopUp();
1368 if (errorExitStatus == -1) {
1369 if (appData.icsActive) {
1370 /* We now wait until we see "login:" from the ICS before
1371 sending the logon script (problems with timestamp otherwise) */
1372 /*ICSInitScript();*/
1373 if (appData.icsInputBox) ICSInputBoxPopUp();
1377 signal(SIGWINCH, TermSizeSigHandler);
1379 signal(SIGINT, IntSigHandler);
1380 signal(SIGTERM, IntSigHandler);
1381 if (*appData.cmailGameName != NULLCHAR) {
1382 signal(SIGUSR1, CmailSigHandler);
1386 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1389 // XtSetKeyboardFocus(shellWidget, formWidget);
1390 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1392 XtAppMainLoop(appContext);
1393 if (appData.debugMode) fclose(debugFP); // [DM] debug
1398 TermSizeSigHandler (int sig)
1404 IntSigHandler (int sig)
1410 CmailSigHandler (int sig)
1415 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1417 /* Activate call-back function CmailSigHandlerCallBack() */
1418 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1420 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1424 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1427 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1429 /**** end signal code ****/
1432 #define Abs(n) ((n)<0 ? -(n) : (n))
1436 InsertPxlSize (char *pattern, int targetPxlSize)
1438 char *base_fnt_lst, strInt[12], *p, *q;
1439 int alternatives, i, len, strIntLen;
1442 * Replace the "*" (if present) in the pixel-size slot of each
1443 * alternative with the targetPxlSize.
1447 while ((p = strchr(p, ',')) != NULL) {
1451 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1452 strIntLen = strlen(strInt);
1453 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1457 while (alternatives--) {
1458 char *comma = strchr(p, ',');
1459 for (i=0; i<14; i++) {
1460 char *hyphen = strchr(p, '-');
1462 if (comma && hyphen > comma) break;
1463 len = hyphen + 1 - p;
1464 if (i == 7 && *p == '*' && len == 2) {
1466 memcpy(q, strInt, strIntLen);
1476 len = comma + 1 - p;
1483 return base_fnt_lst;
1487 CreateFontSet (char *base_fnt_lst)
1490 char **missing_list;
1494 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1495 &missing_list, &missing_count, &def_string);
1496 if (appData.debugMode) {
1498 XFontStruct **font_struct_list;
1499 char **font_name_list;
1500 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1502 fprintf(debugFP, " got list %s, locale %s\n",
1503 XBaseFontNameListOfFontSet(fntSet),
1504 XLocaleOfFontSet(fntSet));
1505 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1506 for (i = 0; i < count; i++) {
1507 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1510 for (i = 0; i < missing_count; i++) {
1511 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1514 if (fntSet == NULL) {
1515 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1520 #else // not ENABLE_NLS
1522 * Find a font that matches "pattern" that is as close as
1523 * possible to the targetPxlSize. Prefer fonts that are k
1524 * pixels smaller to fonts that are k pixels larger. The
1525 * pattern must be in the X Consortium standard format,
1526 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1527 * The return value should be freed with XtFree when no
1531 FindFont (char *pattern, int targetPxlSize)
1533 char **fonts, *p, *best, *scalable, *scalableTail;
1534 int i, j, nfonts, minerr, err, pxlSize;
1536 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1538 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1539 programName, pattern);
1546 for (i=0; i<nfonts; i++) {
1549 if (*p != '-') continue;
1551 if (*p == NULLCHAR) break;
1552 if (*p++ == '-') j++;
1554 if (j < 7) continue;
1557 scalable = fonts[i];
1560 err = pxlSize - targetPxlSize;
1561 if (Abs(err) < Abs(minerr) ||
1562 (minerr > 0 && err < 0 && -err == minerr)) {
1568 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1569 /* If the error is too big and there is a scalable font,
1570 use the scalable font. */
1571 int headlen = scalableTail - scalable;
1572 p = (char *) XtMalloc(strlen(scalable) + 10);
1573 while (isdigit(*scalableTail)) scalableTail++;
1574 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1576 p = (char *) XtMalloc(strlen(best) + 2);
1577 safeStrCpy(p, best, strlen(best)+1 );
1579 if (appData.debugMode) {
1580 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1581 pattern, targetPxlSize, p);
1583 XFreeFontNames(fonts);
1589 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1592 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1598 EnableNamedMenuItem (char *menuRef, int state)
1600 MenuItem *item = MenuNameToItem(menuRef);
1602 if(item) XtSetSensitive(item->handle, state);
1606 EnableButtonBar (int state)
1608 XtSetSensitive(optList[W_BUTTON].handle, state);
1613 SetMenuEnables (Enables *enab)
1615 while (enab->name != NULL) {
1616 EnableNamedMenuItem(enab->name, enab->value);
1622 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1623 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1625 if(*nprms == 0) return;
1626 item = MenuNameToItem(prms[0]);
1627 if(item) ((MenuProc *) item->proc) ();
1631 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1633 RecentEngineEvent((int) (intptr_t) addr);
1637 AppendMenuItem (char *msg, int n)
1639 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1651 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1652 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1653 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1654 dmEnables[i].piece);
1655 XtSetSensitive(entry, p != NULL || !appData.testLegality
1656 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1657 && !appData.icsActive));
1659 while (p && *p++ == dmEnables[i].piece) count++;
1660 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1662 XtSetArg(args[j], XtNlabel, label); j++;
1663 XtSetValues(entry, args, j);
1668 do_flash_delay (unsigned long msec)
1674 FlashDelay (int flash_delay)
1676 XSync(xDisplay, False);
1677 if(flash_delay) do_flash_delay(flash_delay);
1681 Fraction (int x, int start, int stop)
1683 double f = ((double) x - start)/(stop - start);
1684 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1688 static WindowPlacement wpNew;
1691 CoDrag (Widget sh, WindowPlacement *wp)
1694 int j=0, touch=0, fudge = 2;
1695 GetActualPlacement(sh, wp);
1696 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1697 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1698 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1699 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1700 if(!touch ) return; // only windows that touch co-move
1701 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1702 int heightInc = wpNew.height - wpMain.height;
1703 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1704 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1705 wp->y += fracTop * heightInc;
1706 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1707 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1708 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1709 int widthInc = wpNew.width - wpMain.width;
1710 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1711 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1712 wp->y += fracLeft * widthInc;
1713 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1714 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1716 wp->x += wpNew.x - wpMain.x;
1717 wp->y += wpNew.y - wpMain.y;
1718 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1719 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1720 XtSetArg(args[j], XtNx, wp->x); j++;
1721 XtSetArg(args[j], XtNy, wp->y); j++;
1722 XtSetValues(sh, args, j);
1726 ReSize (WindowPlacement *wp)
1729 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1730 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1731 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1732 if(sqy < sqx) sqx = sqy;
1733 if(sqx != squareSize) {
1734 squareSize = sqx; // adopt new square size
1735 CreatePNGPieces(); // make newly scaled pieces
1736 InitDrawingSizes(0, 0); // creates grid etc.
1737 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1738 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1739 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1740 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1741 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1744 static XtIntervalId delayedDragID = 0;
1753 GetActualPlacement(shellWidget, &wpNew);
1754 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1755 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1756 busy = 0; return; // false alarm
1759 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1760 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1761 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1762 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1764 DrawPosition(True, NULL);
1765 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1773 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1775 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1779 EventProc (Widget widget, caddr_t unused, XEvent *event)
1781 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1782 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1786 * event handler for redrawing the board
1789 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1791 DrawPosition(True, NULL);
1796 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1797 { // [HGM] pv: walk PV
1798 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1801 static int savedIndex; /* gross that this is global */
1804 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1807 XawTextPosition index, dummy;
1810 XawTextGetSelectionPos(w, &index, &dummy);
1811 XtSetArg(arg, XtNstring, &val);
1812 XtGetValues(w, &arg, 1);
1813 ReplaceComment(savedIndex, val);
1814 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1815 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1819 EditCommentPopUp (int index, char *title, char *text)
1822 if (text == NULL) text = "";
1823 NewCommentPopup(title, text, index);
1827 CommentPopUp (char *title, char *text)
1829 savedIndex = currentMove; // [HGM] vari
1830 NewCommentPopup(title, text, currentMove);
1836 PopDown(CommentDlg);
1840 /* Disable all user input other than deleting the window */
1841 static int frozen = 0;
1847 /* Grab by a widget that doesn't accept input */
1848 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1852 /* Undo a FreezeUI */
1856 if (!frozen) return;
1857 XtRemoveGrab(optList[W_MESSG].handle);
1865 static int oldPausing = FALSE;
1866 static GameMode oldmode = (GameMode) -1;
1869 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1871 if (pausing != oldPausing) {
1872 oldPausing = pausing;
1873 MarkMenuItem("Mode.Pause", pausing);
1875 if (appData.showButtonBar) {
1876 /* Always toggle, don't set. Previous code messes up when
1877 invoked while the button is pressed, as releasing it
1878 toggles the state again. */
1881 XtSetArg(args[0], XtNbackground, &oldbg);
1882 XtSetArg(args[1], XtNforeground, &oldfg);
1883 XtGetValues(optList[W_PAUSE].handle,
1885 XtSetArg(args[0], XtNbackground, oldfg);
1886 XtSetArg(args[1], XtNforeground, oldbg);
1888 XtSetValues(optList[W_PAUSE].handle, args, 2);
1892 wname = ModeToWidgetName(oldmode);
1893 if (wname != NULL) {
1894 MarkMenuItem(wname, False);
1896 wname = ModeToWidgetName(gameMode);
1897 if (wname != NULL) {
1898 MarkMenuItem(wname, True);
1901 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1903 /* Maybe all the enables should be handled here, not just this one */
1904 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1906 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1911 * Button/menu procedures
1914 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1915 char *selected_fen_position=NULL;
1918 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1919 Atom *type_return, XtPointer *value_return,
1920 unsigned long *length_return, int *format_return)
1922 char *selection_tmp;
1924 // if (!selected_fen_position) return False; /* should never happen */
1925 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1926 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1927 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1930 if (f == NULL) return False;
1934 selection_tmp = XtMalloc(len + 1);
1935 count = fread(selection_tmp, 1, len, f);
1938 XtFree(selection_tmp);
1941 selection_tmp[len] = NULLCHAR;
1943 /* note: since no XtSelectionDoneProc was registered, Xt will
1944 * automatically call XtFree on the value returned. So have to
1945 * make a copy of it allocated with XtMalloc */
1946 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1947 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1950 *value_return=selection_tmp;
1951 *length_return=strlen(selection_tmp);
1952 *type_return=*target;
1953 *format_return = 8; /* bits per byte */
1955 } else if (*target == XA_TARGETS(xDisplay)) {
1956 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1957 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1958 targets_tmp[1] = XA_STRING;
1959 *value_return = targets_tmp;
1960 *type_return = XA_ATOM;
1963 // This code leads to a read of value_return out of bounds on 64-bit systems.
1964 // Other code which I have seen always sets *format_return to 32 independent of
1965 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1966 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1967 *format_return = 8 * sizeof(Atom);
1968 if (*format_return > 32) {
1969 *length_return *= *format_return / 32;
1970 *format_return = 32;
1973 *format_return = 32;
1981 /* note: when called from menu all parameters are NULL, so no clue what the
1982 * Widget which was clicked on was, or what the click event was
1985 CopySomething (char *src)
1987 selected_fen_position = src;
1989 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1990 * have a notion of a position that is selected but not copied.
1991 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1993 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1995 SendPositionSelection,
1996 NULL/* lose_ownership_proc */ ,
1997 NULL/* transfer_done_proc */);
1998 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2000 SendPositionSelection,
2001 NULL/* lose_ownership_proc */ ,
2002 NULL/* transfer_done_proc */);
2005 /* function called when the data to Paste is ready */
2007 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2008 Atom *type, XtPointer value, unsigned long *len, int *format)
2011 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2012 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2013 EditPositionPasteFEN(fenstr);
2017 /* called when Paste Position button is pressed,
2018 * all parameters will be NULL */
2020 PastePositionProc ()
2022 XtGetSelectionValue(menuBarWidget,
2023 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2024 /* (XtSelectionCallbackProc) */ PastePositionCB,
2025 NULL, /* client_data passed to PastePositionCB */
2027 /* better to use the time field from the event that triggered the
2028 * call to this function, but that isn't trivial to get
2035 /* note: when called from menu all parameters are NULL, so no clue what the
2036 * Widget which was clicked on was, or what the click event was
2038 /* function called when the data to Paste is ready */
2040 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2041 Atom *type, XtPointer value, unsigned long *len, int *format)
2044 if (value == NULL || *len == 0) {
2045 return; /* nothing had been selected to copy */
2047 f = fopen(gamePasteFilename, "w");
2049 DisplayError(_("Can't open temp file"), errno);
2052 fwrite(value, 1, *len, f);
2055 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2058 /* called when Paste Game button is pressed,
2059 * all parameters will be NULL */
2063 XtGetSelectionValue(menuBarWidget,
2064 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2065 /* (XtSelectionCallbackProc) */ PasteGameCB,
2066 NULL, /* client_data passed to PasteGameCB */
2068 /* better to use the time field from the event that triggered the
2069 * call to this function, but that isn't trivial to get
2078 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2085 { // bassic primitive for determining if modifier keys are pressed
2086 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2089 XQueryKeymap(xDisplay,keys);
2090 for(i=0; i<6; i++) {
2092 j = XKeysymToKeycode(xDisplay, codes[i]);
2093 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2099 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2103 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2104 if ( n == 1 && *buf >= 32 // printable
2105 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2106 ) BoxAutoPopUp (buf);
2110 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2111 { // [HGM] input: let up-arrow recall previous line from history
2116 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2117 { // [HGM] input: let down-arrow recall next line from history
2122 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2128 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2130 if (!TempBackwardActive) {
2131 TempBackwardActive = True;
2137 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2139 /* Check to see if triggered by a key release event for a repeating key.
2140 * If so the next queued event will be a key press of the same key at the same time */
2141 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2143 XPeekEvent(xDisplay, &next);
2144 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2145 next.xkey.keycode == event->xkey.keycode)
2149 TempBackwardActive = False;
2153 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2154 { // called as key binding
2157 if (nprms && *nprms > 0)
2161 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2167 { // called from menu
2168 ManInner(NULL, NULL, NULL, NULL);
2172 SetWindowTitle (char *text, char *title, char *icon)
2176 if (appData.titleInWindow) {
2178 XtSetArg(args[i], XtNlabel, text); i++;
2179 XtSetValues(titleWidget, args, i);
2182 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2183 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2184 XtSetValues(shellWidget, args, i);
2185 XSync(xDisplay, False);
2190 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2196 DisplayIcsInteractionTitle (String message)
2198 if (oldICSInteractionTitle == NULL) {
2199 /* Magic to find the old window title, adapted from vim */
2200 char *wina = getenv("WINDOWID");
2202 Window win = (Window) atoi(wina);
2203 Window root, parent, *children;
2204 unsigned int nchildren;
2205 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2207 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2208 if (!XQueryTree(xDisplay, win, &root, &parent,
2209 &children, &nchildren)) break;
2210 if (children) XFree((void *)children);
2211 if (parent == root || parent == 0) break;
2214 XSetErrorHandler(oldHandler);
2216 if (oldICSInteractionTitle == NULL) {
2217 oldICSInteractionTitle = "xterm";
2220 printf("\033]0;%s\007", message);
2225 XtIntervalId delayedEventTimerXID = 0;
2226 DelayedEventCallback delayedEventCallback = 0;
2231 delayedEventTimerXID = 0;
2232 delayedEventCallback();
2236 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2238 if(delayedEventTimerXID && delayedEventCallback == cb)
2239 // [HGM] alive: replace, rather than add or flush identical event
2240 XtRemoveTimeOut(delayedEventTimerXID);
2241 delayedEventCallback = cb;
2242 delayedEventTimerXID =
2243 XtAppAddTimeOut(appContext, millisec,
2244 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2247 DelayedEventCallback
2250 if (delayedEventTimerXID) {
2251 return delayedEventCallback;
2258 CancelDelayedEvent ()
2260 if (delayedEventTimerXID) {
2261 XtRemoveTimeOut(delayedEventTimerXID);
2262 delayedEventTimerXID = 0;
2266 XtIntervalId loadGameTimerXID = 0;
2269 LoadGameTimerRunning ()
2271 return loadGameTimerXID != 0;
2275 StopLoadGameTimer ()
2277 if (loadGameTimerXID != 0) {
2278 XtRemoveTimeOut(loadGameTimerXID);
2279 loadGameTimerXID = 0;
2287 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2289 loadGameTimerXID = 0;
2294 StartLoadGameTimer (long millisec)
2297 XtAppAddTimeOut(appContext, millisec,
2298 (XtTimerCallbackProc) LoadGameTimerCallback,
2302 XtIntervalId analysisClockXID = 0;
2305 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2307 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2308 || appData.icsEngineAnalyze) { // [DM]
2309 AnalysisPeriodicEvent(0);
2310 StartAnalysisClock();
2315 StartAnalysisClock ()
2318 XtAppAddTimeOut(appContext, 2000,
2319 (XtTimerCallbackProc) AnalysisClockCallback,
2323 XtIntervalId clockTimerXID = 0;
2326 ClockTimerRunning ()
2328 return clockTimerXID != 0;
2334 if (clockTimerXID != 0) {
2335 XtRemoveTimeOut(clockTimerXID);
2344 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2351 StartClockTimer (long millisec)
2354 XtAppAddTimeOut(appContext, millisec,
2355 (XtTimerCallbackProc) ClockTimerCallback,
2360 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2364 Widget w = (Widget) opt->handle;
2366 /* check for low time warning */
2367 Pixel foregroundOrWarningColor = timerForegroundPixel;
2370 appData.lowTimeWarning &&
2371 (timer / 1000) < appData.icsAlarmTime)
2372 foregroundOrWarningColor = lowTimeWarningColor;
2374 if (appData.clockMode) {
2375 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2376 XtSetArg(args[0], XtNlabel, buf);
2378 snprintf(buf, MSG_SIZ, "%s ", color);
2379 XtSetArg(args[0], XtNlabel, buf);
2384 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2385 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2387 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2388 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2391 XtSetValues(w, args, 3);
2394 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2397 SetClockIcon (int color)
2400 Pixmap pm = *clockIcons[color];
2401 if (iconPixmap != pm) {
2403 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2404 XtSetValues(shellWidget, args, 1);
2409 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2411 InputSource *is = (InputSource *) closure;
2416 if (is->lineByLine) {
2417 count = read(is->fd, is->unused,
2418 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2420 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2423 is->unused += count;
2425 while (p < is->unused) {
2426 q = memchr(p, '\n', is->unused - p);
2427 if (q == NULL) break;
2429 (is->func)(is, is->closure, p, q - p, 0);
2433 while (p < is->unused) {
2438 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2443 (is->func)(is, is->closure, is->buf, count, error);
2448 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2451 ChildProc *cp = (ChildProc *) pr;
2453 is = (InputSource *) calloc(1, sizeof(InputSource));
2454 is->lineByLine = lineByLine;
2458 is->fd = fileno(stdin);
2460 is->kind = cp->kind;
2461 is->fd = cp->fdFrom;
2464 is->unused = is->buf;
2467 is->xid = XtAppAddInput(appContext, is->fd,
2468 (XtPointer) (XtInputReadMask),
2469 (XtInputCallbackProc) DoInputCallback,
2471 is->closure = closure;
2472 return (InputSourceRef) is;
2476 RemoveInputSource (InputSourceRef isr)
2478 InputSource *is = (InputSource *) isr;
2480 if (is->xid == 0) return;
2481 XtRemoveInput(is->xid);
2487 static Boolean frameWaiting;
2490 FrameAlarm (int sig)
2492 frameWaiting = False;
2493 /* In case System-V style signals. Needed?? */
2494 signal(SIGALRM, FrameAlarm);
2498 FrameDelay (int time)
2500 struct itimerval delay;
2502 XSync(xDisplay, False);
2505 frameWaiting = True;
2506 signal(SIGALRM, FrameAlarm);
2507 delay.it_interval.tv_sec =
2508 delay.it_value.tv_sec = time / 1000;
2509 delay.it_interval.tv_usec =
2510 delay.it_value.tv_usec = (time % 1000) * 1000;
2511 setitimer(ITIMER_REAL, &delay, NULL);
2512 while (frameWaiting) pause();
2513 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2514 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2515 setitimer(ITIMER_REAL, &delay, NULL);
2522 FrameDelay (int time)
2524 XSync(xDisplay, False);
2526 usleep(time * 1000);
2532 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2534 char buf[MSG_SIZ], *logoName = buf;
2535 if(appData.logo[n][0]) {
2536 logoName = appData.logo[n];
2537 } else if(appData.autoLogo) {
2538 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2539 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2540 } else if(appData.directory[n] && appData.directory[n][0]) {
2541 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2545 { ASSIGN(cps->programLogo, logoName); }
2549 UpdateLogos (int displ)
2551 if(optList[W_WHITE-1].handle == NULL) return;
2552 LoadLogo(&first, 0, 0);
2553 LoadLogo(&second, 1, appData.icsActive);
2554 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);