2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
64 #include <cairo/cairo.h>
65 #include <cairo/cairo-xlib.h>
68 # if HAVE_SYS_SOCKET_H
69 # include <sys/socket.h>
70 # include <netinet/in.h>
72 # else /* not HAVE_SYS_SOCKET_H */
73 # if HAVE_LAN_SOCKET_H
74 # include <lan/socket.h>
76 # include <lan/netdb.h>
77 # else /* not HAVE_LAN_SOCKET_H */
78 # define OMIT_SOCKETS 1
79 # endif /* not HAVE_LAN_SOCKET_H */
80 # endif /* not HAVE_SYS_SOCKET_H */
81 #endif /* !OMIT_SOCKETS */
86 #else /* not STDC_HEADERS */
87 extern char *getenv();
90 # else /* not HAVE_STRING_H */
92 # endif /* not HAVE_STRING_H */
93 #endif /* not STDC_HEADERS */
96 # include <sys/fcntl.h>
97 #else /* not HAVE_SYS_FCNTL_H */
100 # endif /* HAVE_FCNTL_H */
101 #endif /* not HAVE_SYS_FCNTL_H */
103 #if HAVE_SYS_SYSTEMINFO_H
104 # include <sys/systeminfo.h>
105 #endif /* HAVE_SYS_SYSTEMINFO_H */
107 #if TIME_WITH_SYS_TIME
108 # include <sys/time.h>
112 # include <sys/time.h>
123 # include <sys/wait.h>
128 # define NAMLEN(dirent) strlen((dirent)->d_name)
129 # define HAVE_DIR_STRUCT
131 # define dirent direct
132 # define NAMLEN(dirent) (dirent)->d_namlen
134 # include <sys/ndir.h>
135 # define HAVE_DIR_STRUCT
138 # include <sys/dir.h>
139 # define HAVE_DIR_STRUCT
143 # define HAVE_DIR_STRUCT
151 #include <X11/Intrinsic.h>
152 #include <X11/StringDefs.h>
153 #include <X11/Shell.h>
154 #include <X11/cursorfont.h>
155 #include <X11/Xatom.h>
156 #include <X11/Xmu/Atoms.h>
158 #include <X11/Xaw3d/Dialog.h>
159 #include <X11/Xaw3d/Form.h>
160 #include <X11/Xaw3d/List.h>
161 #include <X11/Xaw3d/Label.h>
162 #include <X11/Xaw3d/SimpleMenu.h>
163 #include <X11/Xaw3d/SmeBSB.h>
164 #include <X11/Xaw3d/SmeLine.h>
165 #include <X11/Xaw3d/Box.h>
166 #include <X11/Xaw3d/MenuButton.h>
167 #include <X11/Xaw3d/Text.h>
168 #include <X11/Xaw3d/AsciiText.h>
170 #include <X11/Xaw/Dialog.h>
171 #include <X11/Xaw/Form.h>
172 #include <X11/Xaw/List.h>
173 #include <X11/Xaw/Label.h>
174 #include <X11/Xaw/SimpleMenu.h>
175 #include <X11/Xaw/SmeBSB.h>
176 #include <X11/Xaw/SmeLine.h>
177 #include <X11/Xaw/Box.h>
178 #include <X11/Xaw/MenuButton.h>
179 #include <X11/Xaw/Text.h>
180 #include <X11/Xaw/AsciiText.h>
183 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
188 #define IMAGE_EXT "xpm"
190 #define IMAGE_EXT "xim"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xevalgraph.h"
206 #include "xedittags.h"
210 #include "engineoutput.h"
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
231 int main P((int argc, char **argv));
232 RETSIGTYPE CmailSigHandler P((int sig));
233 RETSIGTYPE IntSigHandler P((int sig));
234 RETSIGTYPE TermSizeSigHandler P((int sig));
235 Widget CreateMenuBar P((Menu *mb, int boardWidth));
237 char *InsertPxlSize P((char *pattern, int targetPxlSize));
238 XFontSet CreateFontSet P((char *base_fnt_lst));
240 char *FindFont P((char *pattern, int targetPxlSize));
242 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
243 u_int wreq, u_int hreq));
244 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
245 void DelayedDrag P((void));
246 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
247 void HandlePV P((Widget w, XEvent * event,
248 String * params, Cardinal * nParams));
249 void DrawPositionProc P((Widget w, XEvent *event,
250 String *prms, Cardinal *nprms));
251 void CommentClick P((Widget w, XEvent * event,
252 String * params, Cardinal * nParams));
253 void ICSInputBoxPopUp P((void));
254 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
255 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
257 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
258 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
259 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
260 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
261 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
262 Boolean TempBackwardActive = False;
263 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
264 void DisplayMove P((int moveNumber));
265 void ICSInitScript P((void));
266 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
267 void update_ics_width P(());
268 int CopyMemoProc P(());
271 * XBoard depends on Xt R4 or higher
273 int xtVersion = XtSpecificationRelease;
278 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
279 highlightSquareColor, premoveHighlightColor; // used in graphics
280 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
281 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
282 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
283 Option *optList; // contains all widgets of main window
285 XFontSet fontSet, clockFontSet;
288 XFontStruct *clockFontStruct;
290 Font coordFontID, countFontID;
291 XFontStruct *coordFontStruct, *countFontStruct;
292 XtAppContext appContext;
295 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
297 Position commentX = -1, commentY = -1;
298 Dimension commentW, commentH;
299 typedef unsigned int BoardSize;
301 Boolean chessProgram;
303 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
304 int smallLayout = 0, tinyLayout = 0,
305 marginW, marginH, // [HGM] for run-time resizing
306 fromX = -1, fromY = -1, toX, toY, commentUp = False,
307 errorExitStatus = -1, defaultLineGap;
308 Dimension textHeight;
309 Pixel timerForegroundPixel, timerBackgroundPixel;
310 Pixel buttonForegroundPixel, buttonBackgroundPixel;
311 char *chessDir, *programName, *programVersion;
312 Boolean alwaysOnTop = False;
313 char *icsTextMenuString;
315 char *firstChessProgramNames;
316 char *secondChessProgramNames;
318 WindowPlacement wpMain;
319 WindowPlacement wpConsole;
320 WindowPlacement wpComment;
321 WindowPlacement wpMoveHistory;
322 WindowPlacement wpEvalGraph;
323 WindowPlacement wpEngineOutput;
324 WindowPlacement wpGameList;
325 WindowPlacement wpTags;
328 /* This magic number is the number of intermediate frames used
329 in each half of the animation. For short moves it's reduced
330 by 1. The total number of frames will be factor * 2 + 1. */
333 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
340 DropMenuEnables dmEnables[] = {
357 XtResource clientResources[] = {
358 { "flashCount", "flashCount", XtRInt, sizeof(int),
359 XtOffset(AppDataPtr, flashCount), XtRImmediate,
360 (XtPointer) FLASH_COUNT },
363 XrmOptionDescRec shellOptions[] = {
364 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
365 { "-flash", "flashCount", XrmoptionNoArg, "3" },
366 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
369 XtActionsRec boardActions[] = {
370 { "DrawPosition", DrawPositionProc },
371 { "HandlePV", HandlePV },
372 { "SelectPV", SelectPV },
373 { "StopPV", StopPV },
374 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
375 { "QuitProc", QuitWrapper },
376 { "ManProc", ManInner },
377 { "TempBackwardProc", TempBackwardProc },
378 { "TempForwardProc", TempForwardProc },
379 { "CommentClick", (XtActionProc) CommentClick },
380 { "GenericPopDown", (XtActionProc) GenericPopDown },
381 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
382 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
383 { "SelectMove", (XtActionProc) SelectMove },
384 { "LoadSelectedProc", LoadSelectedProc },
385 { "SetFilterProc", SetFilterProc },
386 { "TypeInProc", TypeInProc },
387 { "EnterKeyProc", EnterKeyProc },
388 { "UpKeyProc", UpKeyProc },
389 { "DownKeyProc", DownKeyProc },
390 { "WheelProc", WheelProc },
391 { "TabProc", TabProc },
394 char globalTranslations[] =
395 ":<Key>F9: MenuItem(Actions.Resign) \n \
396 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
397 :Meta<Key>V: MenuItem(File.NewVariant) \n \
398 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
399 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
400 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
401 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
402 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
403 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
404 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
405 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
406 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
407 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
408 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
409 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
410 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
411 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
412 :Ctrl<Key>q: MenuItem(File.Quit) \n \
413 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
414 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
415 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
416 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
417 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
418 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
419 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
420 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
421 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
422 :Meta<Key>G: MenuItem(View.GameList) \n \
423 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
424 :<Key>Pause: MenuItem(Mode.Pause) \n \
425 :<Key>F3: MenuItem(Action.Accept) \n \
426 :<Key>F4: MenuItem(Action.Decline) \n \
427 :<Key>F12: MenuItem(Action.Rematch) \n \
428 :<Key>F5: MenuItem(Action.CallFlag) \n \
429 :<Key>F6: MenuItem(Action.Draw) \n \
430 :<Key>F7: MenuItem(Action.Adjourn) \n \
431 :<Key>F8: MenuItem(Action.Abort) \n \
432 :<Key>F10: MenuItem(Action.StopObserving) \n \
433 :<Key>F11: MenuItem(Action.StopExamining) \n \
434 :Ctrl<Key>d: MenuItem(DebugProc) \n \
435 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
436 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
437 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
438 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
439 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
440 :<Key>Left: MenuItem(Edit.Backward) \n \
441 :<Key>Right: MenuItem(Edit.Forward) \n \
442 :<Key>Home: MenuItem(Edit.Revert) \n \
443 :<Key>End: MenuItem(Edit.TruncateGame) \n \
444 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
445 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
446 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
447 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
448 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
449 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
450 #ifndef OPTIONSDIALOG
452 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
453 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
454 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
455 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
456 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
459 :<Key>F1: MenuItem(Help.ManXBoard) \n \
460 :<Key>F2: MenuItem(View.FlipView) \n \
461 :<KeyDown>Return: TempBackwardProc() \n \
462 :<KeyUp>Return: TempForwardProc() \n";
464 char ICSInputTranslations[] =
465 "<Key>Up: UpKeyProc() \n "
466 "<Key>Down: DownKeyProc() \n "
467 "<Key>Return: EnterKeyProc() \n";
469 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
470 // as the widget is destroyed before the up-click can call extend-end
471 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
473 String xboardResources[] = {
474 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
479 /* Max possible square size */
480 #define MAXSQSIZE 256
482 static int xpm_avail[MAXSQSIZE];
484 #ifdef HAVE_DIR_STRUCT
486 /* Extract piece size from filename */
488 xpm_getsize (char *name, int len, char *ext)
496 if ((p=strchr(name, '.')) == NULL ||
497 StrCaseCmp(p+1, ext) != 0)
503 while (*p && isdigit(*p))
510 /* Setup xpm_avail */
512 xpm_getavail (char *dirname, char *ext)
518 for (i=0; i<MAXSQSIZE; ++i)
521 if (appData.debugMode)
522 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
524 dir = opendir(dirname);
527 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
528 programName, dirname);
532 while ((ent=readdir(dir)) != NULL) {
533 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
534 if (i > 0 && i < MAXSQSIZE)
544 xpm_print_avail (FILE *fp, char *ext)
548 fprintf(fp, _("Available `%s' sizes:\n"), ext);
549 for (i=1; i<MAXSQSIZE; ++i) {
555 /* Return XPM piecesize closest to size */
557 xpm_closest_to (char *dirname, int size, char *ext)
560 int sm_diff = MAXSQSIZE;
564 xpm_getavail(dirname, ext);
566 if (appData.debugMode)
567 xpm_print_avail(stderr, ext);
569 for (i=1; i<MAXSQSIZE; ++i) {
572 diff = (diff<0) ? -diff : diff;
573 if (diff < sm_diff) {
581 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
587 #else /* !HAVE_DIR_STRUCT */
588 /* If we are on a system without a DIR struct, we can't
589 read the directory, so we can't collect a list of
590 filenames, etc., so we can't do any size-fitting. */
592 xpm_closest_to (char *dirname, int size, char *ext)
595 Warning: No DIR structure found on this system --\n\
596 Unable to autosize for XPM/XIM pieces.\n\
597 Please report this error to %s.\n\
598 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
601 #endif /* HAVE_DIR_STRUCT */
604 /* Arrange to catch delete-window events */
605 Atom wm_delete_window;
607 CatchDeleteWindow (Widget w, String procname)
610 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
611 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
612 XtAugmentTranslations(w, XtParseTranslationTable(buf));
619 XtSetArg(args[0], XtNiconic, False);
620 XtSetValues(shellWidget, args, 1);
622 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
625 //---------------------------------------------------------------------------------------------------------
626 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
629 #define CW_USEDEFAULT (1<<31)
630 #define ICS_TEXT_MENU_SIZE 90
631 #define DEBUG_FILE "xboard.debug"
632 #define SetCurrentDirectory chdir
633 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
637 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
640 // front-end part of option handling
642 // [HGM] This platform-dependent table provides the location for storing the color info
643 extern char *crWhite, * crBlack;
647 &appData.whitePieceColor,
648 &appData.blackPieceColor,
649 &appData.lightSquareColor,
650 &appData.darkSquareColor,
651 &appData.highlightSquareColor,
652 &appData.premoveHighlightColor,
653 &appData.lowTimeWarningColor,
664 // [HGM] font: keep a font for each square size, even non-stndard ones
667 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
668 char *fontTable[NUM_FONTS][MAX_SIZE];
671 ParseFont (char *name, int number)
672 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
674 if(sscanf(name, "size%d:", &size)) {
675 // [HGM] font: font is meant for specific boardSize (likely from settings file);
676 // defer processing it until we know if it matches our board size
677 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
678 fontTable[number][size] = strdup(strchr(name, ':')+1);
679 fontValid[number][size] = True;
684 case 0: // CLOCK_FONT
685 appData.clockFont = strdup(name);
687 case 1: // MESSAGE_FONT
688 appData.font = strdup(name);
690 case 2: // COORD_FONT
691 appData.coordFont = strdup(name);
696 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
701 { // only 2 fonts currently
702 appData.clockFont = CLOCK_FONT_NAME;
703 appData.coordFont = COORD_FONT_NAME;
704 appData.font = DEFAULT_FONT_NAME;
709 { // no-op, until we identify the code for this already in XBoard and move it here
713 ParseColor (int n, char *name)
714 { // in XBoard, just copy the color-name string
715 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
719 ParseTextAttribs (ColorClass cc, char *s)
721 (&appData.colorShout)[cc] = strdup(s);
725 ParseBoardSize (void *addr, char *name)
727 appData.boardSize = strdup(name);
732 { // In XBoard the sound-playing program takes care of obtaining the actual sound
736 SetCommPortDefaults ()
737 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
740 // [HGM] args: these three cases taken out to stay in front-end
742 SaveFontArg (FILE *f, ArgDescriptor *ad)
745 int i, n = (int)(intptr_t)ad->argLoc;
747 case 0: // CLOCK_FONT
748 name = appData.clockFont;
750 case 1: // MESSAGE_FONT
753 case 2: // COORD_FONT
754 name = appData.coordFont;
759 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
760 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
761 fontTable[n][squareSize] = strdup(name);
762 fontValid[n][squareSize] = True;
765 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
766 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
771 { // nothing to do, as the sounds are at all times represented by their text-string names already
775 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
776 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
777 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
781 SaveColor (FILE *f, ArgDescriptor *ad)
782 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
783 if(colorVariable[(int)(intptr_t)ad->argLoc])
784 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
788 SaveBoardSize (FILE *f, char *name, void *addr)
789 { // wrapper to shield back-end from BoardSize & sizeInfo
790 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
794 ParseCommPortSettings (char *s)
795 { // no such option in XBoard (yet)
801 GetActualPlacement (Widget wg, WindowPlacement *wp)
803 XWindowAttributes winAt;
810 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
811 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
812 wp->x = rx - winAt.x;
813 wp->y = ry - winAt.y;
814 wp->height = winAt.height;
815 wp->width = winAt.width;
816 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
821 { // wrapper to shield use of window handles from back-end (make addressible by number?)
822 // In XBoard this will have to wait until awareness of window parameters is implemented
823 GetActualPlacement(shellWidget, &wpMain);
824 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
825 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
826 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
827 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
828 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
829 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
833 PrintCommPortSettings (FILE *f, char *name)
834 { // This option does not exist in XBoard
838 EnsureOnScreen (int *x, int *y, int minX, int minY)
845 { // [HGM] args: allows testing if main window is realized from back-end
846 return xBoardWindow != 0;
850 PopUpStartupDialog ()
851 { // start menu not implemented in XBoard
855 ConvertToLine (int argc, char **argv)
857 static char line[128*1024], buf[1024];
861 for(i=1; i<argc; i++)
863 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
864 && argv[i][0] != '{' )
865 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
867 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
868 strncat(line, buf, 128*1024 - strlen(line) - 1 );
871 line[strlen(line)-1] = NULLCHAR;
875 //--------------------------------------------------------------------------------------------
878 ResizeBoardWindow (int w, int h, int inhibit)
880 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
882 shellArgs[0].value = w;
883 shellArgs[1].value = h;
884 shellArgs[4].value = shellArgs[2].value = w;
885 shellArgs[5].value = shellArgs[3].value = h;
886 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
888 XSync(xDisplay, False);
892 MakeOneColor (char *name, Pixel *color)
895 if (!appData.monoMode) {
896 vFrom.addr = (caddr_t) name;
897 vFrom.size = strlen(name);
898 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
899 if (vTo.addr == NULL) {
900 appData.monoMode = True;
903 *color = *(Pixel *) vTo.addr;
911 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
912 int forceMono = False;
914 forceMono |= MakeOneColor(appData.lightSquareColor, &lightSquareColor);
915 forceMono |= MakeOneColor(appData.darkSquareColor, &darkSquareColor);
916 forceMono |= MakeOneColor(appData.whitePieceColor, &whitePieceColor);
917 forceMono |= MakeOneColor(appData.blackPieceColor, &blackPieceColor);
918 forceMono |= MakeOneColor(appData.highlightSquareColor, &highlightSquareColor);
919 forceMono |= MakeOneColor(appData.premoveHighlightColor, &premoveHighlightColor);
920 if (appData.lowTimeWarning)
921 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
922 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
923 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
929 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
930 { // detervtomine what fonts to use, and create them
934 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
935 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
936 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
937 appData.font = fontTable[MESSAGE_FONT][squareSize];
938 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
939 appData.coordFont = fontTable[COORD_FONT][squareSize];
942 appData.font = InsertPxlSize(appData.font, fontPxlSize);
943 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
944 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
945 fontSet = CreateFontSet(appData.font);
946 clockFontSet = CreateFontSet(appData.clockFont);
948 /* For the coordFont, use the 0th font of the fontset. */
949 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
950 XFontStruct **font_struct_list;
951 XFontSetExtents *fontSize;
952 char **font_name_list;
953 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
954 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
955 coordFontStruct = XQueryFont(xDisplay, coordFontID);
956 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
957 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
960 appData.font = FindFont(appData.font, fontPxlSize);
961 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
962 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
963 clockFontID = XLoadFont(xDisplay, appData.clockFont);
964 clockFontStruct = XQueryFont(xDisplay, clockFontID);
965 coordFontID = XLoadFont(xDisplay, appData.coordFont);
966 coordFontStruct = XQueryFont(xDisplay, coordFontID);
967 // textHeight in !NLS mode!
969 countFontID = coordFontID; // [HGM] holdings
970 countFontStruct = coordFontStruct;
972 xdb = XtDatabase(xDisplay);
974 XrmPutLineResource(&xdb, "*international: True");
975 vTo.size = sizeof(XFontSet);
976 vTo.addr = (XtPointer) &fontSet;
977 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
979 XrmPutStringResource(&xdb, "*font", appData.font);
989 case ArgInt: p = " N"; break;
990 case ArgString: p = " STR"; break;
991 case ArgBoolean: p = " TF"; break;
992 case ArgSettingsFilename:
993 case ArgFilename: p = " FILE"; break;
994 case ArgX: p = " Nx"; break;
995 case ArgY: p = " Ny"; break;
996 case ArgAttribs: p = " TEXTCOL"; break;
997 case ArgColor: p = " COL"; break;
998 case ArgFont: p = " FONT"; break;
999 case ArgBoardSize: p = " SIZE"; break;
1000 case ArgFloat: p = " FLOAT"; break;
1005 case ArgCommSettings:
1016 ArgDescriptor *q, *p = argDescriptors+5;
1017 printf("\nXBoard accepts the following options:\n"
1018 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1019 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1020 " SIZE = board-size spec(s)\n"
1021 " Within parentheses are short forms, or options to set to true or false.\n"
1022 " Persistent options (saved in the settings file) are marked with *)\n\n");
1024 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1025 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1026 if(p->save) strcat(buf+len, "*");
1027 for(q=p+1; q->argLoc == p->argLoc; q++) {
1028 if(q->argName[0] == '-') continue;
1029 strcat(buf+len, q == p+1 ? " (" : " ");
1030 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1032 if(q != p+1) strcat(buf+len, ")");
1034 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1037 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1041 main (int argc, char **argv)
1043 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1044 XSetWindowAttributes window_attributes;
1046 Dimension boardWidth, boardHeight, w, h;
1048 int forceMono = False;
1050 srandom(time(0)); // [HGM] book: make random truly random
1052 setbuf(stdout, NULL);
1053 setbuf(stderr, NULL);
1056 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1057 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1061 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1066 programName = strrchr(argv[0], '/');
1067 if (programName == NULL)
1068 programName = argv[0];
1073 XtSetLanguageProc(NULL, NULL, NULL);
1074 if (appData.debugMode) {
1075 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1078 bindtextdomain(PACKAGE, LOCALEDIR);
1079 textdomain(PACKAGE);
1082 appData.boardSize = "";
1083 InitAppData(ConvertToLine(argc, argv));
1085 if (p == NULL) p = "/tmp";
1086 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1087 gameCopyFilename = (char*) malloc(i);
1088 gamePasteFilename = (char*) malloc(i);
1089 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1090 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1092 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1093 static char buf[MSG_SIZ];
1094 EscapeExpand(buf, appData.firstInitString);
1095 appData.firstInitString = strdup(buf);
1096 EscapeExpand(buf, appData.secondInitString);
1097 appData.secondInitString = strdup(buf);
1098 EscapeExpand(buf, appData.firstComputerString);
1099 appData.firstComputerString = strdup(buf);
1100 EscapeExpand(buf, appData.secondComputerString);
1101 appData.secondComputerString = strdup(buf);
1104 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1107 if (chdir(chessDir) != 0) {
1108 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1114 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1115 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1116 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1117 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1120 setbuf(debugFP, NULL);
1123 /* [HGM,HR] make sure board size is acceptable */
1124 if(appData.NrFiles > BOARD_FILES ||
1125 appData.NrRanks > BOARD_RANKS )
1126 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1129 /* This feature does not work; animation needs a rewrite */
1130 appData.highlightDragging = FALSE;
1134 gameInfo.variant = StringToVariant(appData.variant);
1135 InitPosition(FALSE);
1138 XtAppInitialize(&appContext, "XBoard", shellOptions,
1139 XtNumber(shellOptions),
1140 &argc, argv, xboardResources, NULL, 0);
1142 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1143 clientResources, XtNumber(clientResources),
1146 xDisplay = XtDisplay(shellWidget);
1147 xScreen = DefaultScreen(xDisplay);
1148 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1151 * determine size, based on supplied or remembered -size, or screen size
1153 if (isdigit(appData.boardSize[0])) {
1154 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1155 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1156 &fontPxlSize, &smallLayout, &tinyLayout);
1158 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1159 programName, appData.boardSize);
1163 /* Find some defaults; use the nearest known size */
1164 SizeDefaults *szd, *nearest;
1165 int distance = 99999;
1166 nearest = szd = sizeDefaults;
1167 while (szd->name != NULL) {
1168 if (abs(szd->squareSize - squareSize) < distance) {
1170 distance = abs(szd->squareSize - squareSize);
1171 if (distance == 0) break;
1175 if (i < 2) lineGap = nearest->lineGap;
1176 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1177 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1178 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1179 if (i < 6) smallLayout = nearest->smallLayout;
1180 if (i < 7) tinyLayout = nearest->tinyLayout;
1183 SizeDefaults *szd = sizeDefaults;
1184 if (*appData.boardSize == NULLCHAR) {
1185 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1186 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1189 if (szd->name == NULL) szd--;
1190 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1192 while (szd->name != NULL &&
1193 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1194 if (szd->name == NULL) {
1195 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1196 programName, appData.boardSize);
1200 squareSize = szd->squareSize;
1201 lineGap = szd->lineGap;
1202 clockFontPxlSize = szd->clockFontPxlSize;
1203 coordFontPxlSize = szd->coordFontPxlSize;
1204 fontPxlSize = szd->fontPxlSize;
1205 smallLayout = szd->smallLayout;
1206 tinyLayout = szd->tinyLayout;
1207 // [HGM] font: use defaults from settings file if available and not overruled
1210 defaultLineGap = lineGap;
1211 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1213 /* [HR] height treated separately (hacked) */
1214 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1215 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1218 * Determine what fonts to use.
1220 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1223 * Detect if there are not enough colors available and adapt.
1225 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1226 appData.monoMode = True;
1229 forceMono = MakeColors();
1232 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1234 appData.monoMode = True;
1237 if (appData.monoMode && appData.debugMode) {
1238 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1239 (unsigned long) XWhitePixel(xDisplay, xScreen),
1240 (unsigned long) XBlackPixel(xDisplay, xScreen));
1243 ParseIcsTextColors();
1245 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1251 layoutName = "tinyLayout";
1252 } else if (smallLayout) {
1253 layoutName = "smallLayout";
1255 layoutName = "normalLayout";
1258 optList = BoardPopUp(squareSize, lineGap, (void*)
1264 InitDrawingHandle(optList + W_BOARD);
1265 currBoard = &optList[W_BOARD];
1266 boardWidget = optList[W_BOARD].handle;
1267 menuBarWidget = optList[W_MENU].handle;
1268 dropMenu = optList[W_DROP].handle;
1269 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1270 formWidget = XtParent(boardWidget);
1271 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1272 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1273 XtGetValues(optList[W_WHITE].handle, args, 2);
1274 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1275 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1276 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1277 XtGetValues(optList[W_PAUSE].handle, args, 2);
1279 AppendEnginesToMenu(appData.recentEngineList);
1281 xBoardWindow = XtWindow(boardWidget);
1283 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1284 // not need to go into InitDrawingSizes().
1287 * Create X checkmark bitmap and initialize option menu checks.
1289 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1290 checkmark_bits, checkmark_width, checkmark_height);
1296 ReadBitmap(&wIconPixmap, "icon_white.bm",
1297 icon_white_bits, icon_white_width, icon_white_height);
1298 ReadBitmap(&bIconPixmap, "icon_black.bm",
1299 icon_black_bits, icon_black_width, icon_black_height);
1300 iconPixmap = wIconPixmap;
1302 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1303 XtSetValues(shellWidget, args, i);
1306 * Create a cursor for the board widget.
1308 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1309 XChangeWindowAttributes(xDisplay, xBoardWindow,
1310 CWCursor, &window_attributes);
1313 * Inhibit shell resizing.
1315 shellArgs[0].value = (XtArgVal) &w;
1316 shellArgs[1].value = (XtArgVal) &h;
1317 XtGetValues(shellWidget, shellArgs, 2);
1318 shellArgs[4].value = shellArgs[2].value = w;
1319 shellArgs[5].value = shellArgs[3].value = h;
1320 // XtSetValues(shellWidget, &shellArgs[2], 4);
1321 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1322 marginH = h - boardHeight;
1324 CatchDeleteWindow(shellWidget, "QuitProc");
1329 if(appData.logoSize)
1330 { // locate and read user logo
1332 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1333 ASSIGN(userLogo, buf);
1336 if (appData.animate || appData.animateDragging)
1339 XtAugmentTranslations(formWidget,
1340 XtParseTranslationTable(globalTranslations));
1342 XtAddEventHandler(formWidget, KeyPressMask, False,
1343 (XtEventHandler) MoveTypeInProc, NULL);
1344 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1345 (XtEventHandler) EventProc, NULL);
1347 /* [AS] Restore layout */
1348 if( wpMoveHistory.visible ) {
1352 if( wpEvalGraph.visible )
1357 if( wpEngineOutput.visible ) {
1358 EngineOutputPopUp();
1363 if (errorExitStatus == -1) {
1364 if (appData.icsActive) {
1365 /* We now wait until we see "login:" from the ICS before
1366 sending the logon script (problems with timestamp otherwise) */
1367 /*ICSInitScript();*/
1368 if (appData.icsInputBox) ICSInputBoxPopUp();
1372 signal(SIGWINCH, TermSizeSigHandler);
1374 signal(SIGINT, IntSigHandler);
1375 signal(SIGTERM, IntSigHandler);
1376 if (*appData.cmailGameName != NULLCHAR) {
1377 signal(SIGUSR1, CmailSigHandler);
1381 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1384 // XtSetKeyboardFocus(shellWidget, formWidget);
1385 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1387 XtAppMainLoop(appContext);
1388 if (appData.debugMode) fclose(debugFP); // [DM] debug
1393 TermSizeSigHandler (int sig)
1399 IntSigHandler (int sig)
1405 CmailSigHandler (int sig)
1410 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1412 /* Activate call-back function CmailSigHandlerCallBack() */
1413 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1415 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1419 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1422 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1424 /**** end signal code ****/
1427 #define Abs(n) ((n)<0 ? -(n) : (n))
1431 InsertPxlSize (char *pattern, int targetPxlSize)
1433 char *base_fnt_lst, strInt[12], *p, *q;
1434 int alternatives, i, len, strIntLen;
1437 * Replace the "*" (if present) in the pixel-size slot of each
1438 * alternative with the targetPxlSize.
1442 while ((p = strchr(p, ',')) != NULL) {
1446 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1447 strIntLen = strlen(strInt);
1448 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1452 while (alternatives--) {
1453 char *comma = strchr(p, ',');
1454 for (i=0; i<14; i++) {
1455 char *hyphen = strchr(p, '-');
1457 if (comma && hyphen > comma) break;
1458 len = hyphen + 1 - p;
1459 if (i == 7 && *p == '*' && len == 2) {
1461 memcpy(q, strInt, strIntLen);
1471 len = comma + 1 - p;
1478 return base_fnt_lst;
1482 CreateFontSet (char *base_fnt_lst)
1485 char **missing_list;
1489 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1490 &missing_list, &missing_count, &def_string);
1491 if (appData.debugMode) {
1493 XFontStruct **font_struct_list;
1494 char **font_name_list;
1495 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1497 fprintf(debugFP, " got list %s, locale %s\n",
1498 XBaseFontNameListOfFontSet(fntSet),
1499 XLocaleOfFontSet(fntSet));
1500 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1501 for (i = 0; i < count; i++) {
1502 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1505 for (i = 0; i < missing_count; i++) {
1506 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1509 if (fntSet == NULL) {
1510 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1515 #else // not ENABLE_NLS
1517 * Find a font that matches "pattern" that is as close as
1518 * possible to the targetPxlSize. Prefer fonts that are k
1519 * pixels smaller to fonts that are k pixels larger. The
1520 * pattern must be in the X Consortium standard format,
1521 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1522 * The return value should be freed with XtFree when no
1526 FindFont (char *pattern, int targetPxlSize)
1528 char **fonts, *p, *best, *scalable, *scalableTail;
1529 int i, j, nfonts, minerr, err, pxlSize;
1531 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1533 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1534 programName, pattern);
1541 for (i=0; i<nfonts; i++) {
1544 if (*p != '-') continue;
1546 if (*p == NULLCHAR) break;
1547 if (*p++ == '-') j++;
1549 if (j < 7) continue;
1552 scalable = fonts[i];
1555 err = pxlSize - targetPxlSize;
1556 if (Abs(err) < Abs(minerr) ||
1557 (minerr > 0 && err < 0 && -err == minerr)) {
1563 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1564 /* If the error is too big and there is a scalable font,
1565 use the scalable font. */
1566 int headlen = scalableTail - scalable;
1567 p = (char *) XtMalloc(strlen(scalable) + 10);
1568 while (isdigit(*scalableTail)) scalableTail++;
1569 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1571 p = (char *) XtMalloc(strlen(best) + 2);
1572 safeStrCpy(p, best, strlen(best)+1 );
1574 if (appData.debugMode) {
1575 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1576 pattern, targetPxlSize, p);
1578 XFreeFontNames(fonts);
1584 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1587 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1593 MarkMenuItem (char *menuRef, int state)
1595 MenuItem *item = MenuNameToItem(menuRef);
1599 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1600 XtSetValues(item->handle, args, 1);
1605 EnableNamedMenuItem (char *menuRef, int state)
1607 MenuItem *item = MenuNameToItem(menuRef);
1609 if(item) XtSetSensitive(item->handle, state);
1613 EnableButtonBar (int state)
1615 XtSetSensitive(optList[W_BUTTON].handle, state);
1620 SetMenuEnables (Enables *enab)
1622 while (enab->name != NULL) {
1623 EnableNamedMenuItem(enab->name, enab->value);
1629 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1630 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1632 if(*nprms == 0) return;
1633 item = MenuNameToItem(prms[0]);
1634 if(item) ((MenuProc *) item->proc) ();
1638 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1640 RecentEngineEvent((int) (intptr_t) addr);
1644 AppendMenuItem (char *msg, int n)
1646 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1658 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1659 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1660 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1661 dmEnables[i].piece);
1662 XtSetSensitive(entry, p != NULL || !appData.testLegality
1663 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1664 && !appData.icsActive));
1666 while (p && *p++ == dmEnables[i].piece) count++;
1667 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1669 XtSetArg(args[j], XtNlabel, label); j++;
1670 XtSetValues(entry, args, j);
1675 do_flash_delay (unsigned long msec)
1681 FlashDelay (int flash_delay)
1683 XSync(xDisplay, False);
1684 if(flash_delay) do_flash_delay(flash_delay);
1688 Fraction (int x, int start, int stop)
1690 double f = ((double) x - start)/(stop - start);
1691 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1695 static WindowPlacement wpNew;
1698 CoDrag (Widget sh, WindowPlacement *wp)
1701 int j=0, touch=0, fudge = 2;
1702 GetActualPlacement(sh, wp);
1703 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1704 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1705 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1706 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1707 if(!touch ) return; // only windows that touch co-move
1708 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1709 int heightInc = wpNew.height - wpMain.height;
1710 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1711 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1712 wp->y += fracTop * heightInc;
1713 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1714 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1715 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1716 int widthInc = wpNew.width - wpMain.width;
1717 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1718 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1719 wp->y += fracLeft * widthInc;
1720 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1721 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1723 wp->x += wpNew.x - wpMain.x;
1724 wp->y += wpNew.y - wpMain.y;
1725 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1726 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1727 XtSetArg(args[j], XtNx, wp->x); j++;
1728 XtSetArg(args[j], XtNy, wp->y); j++;
1729 XtSetValues(sh, args, j);
1733 ReSize (WindowPlacement *wp)
1736 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1737 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1738 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1739 if(sqy < sqx) sqx = sqy;
1740 if(sqx != squareSize) {
1741 squareSize = sqx; // adopt new square size
1742 CreatePNGPieces(); // make newly scaled pieces
1743 InitDrawingSizes(0, 0); // creates grid etc.
1744 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1747 static XtIntervalId delayedDragID = 0;
1756 GetActualPlacement(shellWidget, &wpNew);
1757 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1758 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1759 busy = 0; return; // false alarm
1762 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1763 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1764 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1765 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1767 DrawPosition(True, NULL);
1768 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1776 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1778 XtAppAddTimeOut(appContext, 100, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1782 EventProc (Widget widget, caddr_t unused, XEvent *event)
1784 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1785 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1789 * event handler for redrawing the board
1792 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1794 DrawPosition(True, NULL);
1799 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1800 { // [HGM] pv: walk PV
1801 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1804 static int savedIndex; /* gross that this is global */
1807 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1810 XawTextPosition index, dummy;
1813 XawTextGetSelectionPos(w, &index, &dummy);
1814 XtSetArg(arg, XtNstring, &val);
1815 XtGetValues(w, &arg, 1);
1816 ReplaceComment(savedIndex, val);
1817 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1818 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1822 EditCommentPopUp (int index, char *title, char *text)
1825 if (text == NULL) text = "";
1826 NewCommentPopup(title, text, index);
1830 CommentPopUp (char *title, char *text)
1832 savedIndex = currentMove; // [HGM] vari
1833 NewCommentPopup(title, text, currentMove);
1839 PopDown(CommentDlg);
1843 /* Disable all user input other than deleting the window */
1844 static int frozen = 0;
1850 /* Grab by a widget that doesn't accept input */
1851 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1855 /* Undo a FreezeUI */
1859 if (!frozen) return;
1860 XtRemoveGrab(optList[W_MESSG].handle);
1868 static int oldPausing = FALSE;
1869 static GameMode oldmode = (GameMode) -1;
1872 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1874 if (pausing != oldPausing) {
1875 oldPausing = pausing;
1876 MarkMenuItem("Mode.Pause", pausing);
1878 if (appData.showButtonBar) {
1879 /* Always toggle, don't set. Previous code messes up when
1880 invoked while the button is pressed, as releasing it
1881 toggles the state again. */
1884 XtSetArg(args[0], XtNbackground, &oldbg);
1885 XtSetArg(args[1], XtNforeground, &oldfg);
1886 XtGetValues(optList[W_PAUSE].handle,
1888 XtSetArg(args[0], XtNbackground, oldfg);
1889 XtSetArg(args[1], XtNforeground, oldbg);
1891 XtSetValues(optList[W_PAUSE].handle, args, 2);
1895 wname = ModeToWidgetName(oldmode);
1896 if (wname != NULL) {
1897 MarkMenuItem(wname, False);
1899 wname = ModeToWidgetName(gameMode);
1900 if (wname != NULL) {
1901 MarkMenuItem(wname, True);
1904 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1906 /* Maybe all the enables should be handled here, not just this one */
1907 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1909 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1914 * Button/menu procedures
1917 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1918 char *selected_fen_position=NULL;
1921 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1922 Atom *type_return, XtPointer *value_return,
1923 unsigned long *length_return, int *format_return)
1925 char *selection_tmp;
1927 // if (!selected_fen_position) return False; /* should never happen */
1928 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1929 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1930 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1933 if (f == NULL) return False;
1937 selection_tmp = XtMalloc(len + 1);
1938 count = fread(selection_tmp, 1, len, f);
1941 XtFree(selection_tmp);
1944 selection_tmp[len] = NULLCHAR;
1946 /* note: since no XtSelectionDoneProc was registered, Xt will
1947 * automatically call XtFree on the value returned. So have to
1948 * make a copy of it allocated with XtMalloc */
1949 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1950 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1953 *value_return=selection_tmp;
1954 *length_return=strlen(selection_tmp);
1955 *type_return=*target;
1956 *format_return = 8; /* bits per byte */
1958 } else if (*target == XA_TARGETS(xDisplay)) {
1959 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1960 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1961 targets_tmp[1] = XA_STRING;
1962 *value_return = targets_tmp;
1963 *type_return = XA_ATOM;
1966 // This code leads to a read of value_return out of bounds on 64-bit systems.
1967 // Other code which I have seen always sets *format_return to 32 independent of
1968 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1969 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1970 *format_return = 8 * sizeof(Atom);
1971 if (*format_return > 32) {
1972 *length_return *= *format_return / 32;
1973 *format_return = 32;
1976 *format_return = 32;
1984 /* note: when called from menu all parameters are NULL, so no clue what the
1985 * Widget which was clicked on was, or what the click event was
1988 CopySomething (char *src)
1990 selected_fen_position = src;
1992 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1993 * have a notion of a position that is selected but not copied.
1994 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1996 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1998 SendPositionSelection,
1999 NULL/* lose_ownership_proc */ ,
2000 NULL/* transfer_done_proc */);
2001 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2003 SendPositionSelection,
2004 NULL/* lose_ownership_proc */ ,
2005 NULL/* transfer_done_proc */);
2008 /* function called when the data to Paste is ready */
2010 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2011 Atom *type, XtPointer value, unsigned long *len, int *format)
2014 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2015 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2016 EditPositionPasteFEN(fenstr);
2020 /* called when Paste Position button is pressed,
2021 * all parameters will be NULL */
2023 PastePositionProc ()
2025 XtGetSelectionValue(menuBarWidget,
2026 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2027 /* (XtSelectionCallbackProc) */ PastePositionCB,
2028 NULL, /* client_data passed to PastePositionCB */
2030 /* better to use the time field from the event that triggered the
2031 * call to this function, but that isn't trivial to get
2038 /* note: when called from menu all parameters are NULL, so no clue what the
2039 * Widget which was clicked on was, or what the click event was
2041 /* function called when the data to Paste is ready */
2043 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2044 Atom *type, XtPointer value, unsigned long *len, int *format)
2047 if (value == NULL || *len == 0) {
2048 return; /* nothing had been selected to copy */
2050 f = fopen(gamePasteFilename, "w");
2052 DisplayError(_("Can't open temp file"), errno);
2055 fwrite(value, 1, *len, f);
2058 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2061 /* called when Paste Game button is pressed,
2062 * all parameters will be NULL */
2066 XtGetSelectionValue(menuBarWidget,
2067 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2068 /* (XtSelectionCallbackProc) */ PasteGameCB,
2069 NULL, /* client_data passed to PasteGameCB */
2071 /* better to use the time field from the event that triggered the
2072 * call to this function, but that isn't trivial to get
2081 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2088 { // bassic primitive for determining if modifier keys are pressed
2089 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2092 XQueryKeymap(xDisplay,keys);
2093 for(i=0; i<6; i++) {
2095 j = XKeysymToKeycode(xDisplay, codes[i]);
2096 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2102 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2106 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2107 if ( n == 1 && *buf >= 32 // printable
2108 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2109 ) BoxAutoPopUp (buf);
2113 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2114 { // [HGM] input: let up-arrow recall previous line from history
2119 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2120 { // [HGM] input: let down-arrow recall next line from history
2125 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2131 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2133 if (!TempBackwardActive) {
2134 TempBackwardActive = True;
2140 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2142 /* Check to see if triggered by a key release event for a repeating key.
2143 * If so the next queued event will be a key press of the same key at the same time */
2144 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2146 XPeekEvent(xDisplay, &next);
2147 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2148 next.xkey.keycode == event->xkey.keycode)
2152 TempBackwardActive = False;
2156 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2157 { // called as key binding
2160 if (nprms && *nprms > 0)
2164 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2170 { // called from menu
2171 ManInner(NULL, NULL, NULL, NULL);
2175 SetWindowTitle (char *text, char *title, char *icon)
2179 if (appData.titleInWindow) {
2181 XtSetArg(args[i], XtNlabel, text); i++;
2182 XtSetValues(titleWidget, args, i);
2185 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2186 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2187 XtSetValues(shellWidget, args, i);
2188 XSync(xDisplay, False);
2193 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2199 DisplayIcsInteractionTitle (String message)
2201 if (oldICSInteractionTitle == NULL) {
2202 /* Magic to find the old window title, adapted from vim */
2203 char *wina = getenv("WINDOWID");
2205 Window win = (Window) atoi(wina);
2206 Window root, parent, *children;
2207 unsigned int nchildren;
2208 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2210 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2211 if (!XQueryTree(xDisplay, win, &root, &parent,
2212 &children, &nchildren)) break;
2213 if (children) XFree((void *)children);
2214 if (parent == root || parent == 0) break;
2217 XSetErrorHandler(oldHandler);
2219 if (oldICSInteractionTitle == NULL) {
2220 oldICSInteractionTitle = "xterm";
2223 printf("\033]0;%s\007", message);
2228 XtIntervalId delayedEventTimerXID = 0;
2229 DelayedEventCallback delayedEventCallback = 0;
2234 delayedEventTimerXID = 0;
2235 delayedEventCallback();
2239 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2241 if(delayedEventTimerXID && delayedEventCallback == cb)
2242 // [HGM] alive: replace, rather than add or flush identical event
2243 XtRemoveTimeOut(delayedEventTimerXID);
2244 delayedEventCallback = cb;
2245 delayedEventTimerXID =
2246 XtAppAddTimeOut(appContext, millisec,
2247 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2250 DelayedEventCallback
2253 if (delayedEventTimerXID) {
2254 return delayedEventCallback;
2261 CancelDelayedEvent ()
2263 if (delayedEventTimerXID) {
2264 XtRemoveTimeOut(delayedEventTimerXID);
2265 delayedEventTimerXID = 0;
2269 XtIntervalId loadGameTimerXID = 0;
2272 LoadGameTimerRunning ()
2274 return loadGameTimerXID != 0;
2278 StopLoadGameTimer ()
2280 if (loadGameTimerXID != 0) {
2281 XtRemoveTimeOut(loadGameTimerXID);
2282 loadGameTimerXID = 0;
2290 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2292 loadGameTimerXID = 0;
2297 StartLoadGameTimer (long millisec)
2300 XtAppAddTimeOut(appContext, millisec,
2301 (XtTimerCallbackProc) LoadGameTimerCallback,
2305 XtIntervalId analysisClockXID = 0;
2308 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2310 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2311 || appData.icsEngineAnalyze) { // [DM]
2312 AnalysisPeriodicEvent(0);
2313 StartAnalysisClock();
2318 StartAnalysisClock ()
2321 XtAppAddTimeOut(appContext, 2000,
2322 (XtTimerCallbackProc) AnalysisClockCallback,
2326 XtIntervalId clockTimerXID = 0;
2329 ClockTimerRunning ()
2331 return clockTimerXID != 0;
2337 if (clockTimerXID != 0) {
2338 XtRemoveTimeOut(clockTimerXID);
2347 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2354 StartClockTimer (long millisec)
2357 XtAppAddTimeOut(appContext, millisec,
2358 (XtTimerCallbackProc) ClockTimerCallback,
2363 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2367 Widget w = (Widget) opt->handle;
2369 /* check for low time warning */
2370 Pixel foregroundOrWarningColor = timerForegroundPixel;
2373 appData.lowTimeWarning &&
2374 (timer / 1000) < appData.icsAlarmTime)
2375 foregroundOrWarningColor = lowTimeWarningColor;
2377 if (appData.clockMode) {
2378 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2379 XtSetArg(args[0], XtNlabel, buf);
2381 snprintf(buf, MSG_SIZ, "%s ", color);
2382 XtSetArg(args[0], XtNlabel, buf);
2387 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2388 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2390 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2391 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2394 XtSetValues(w, args, 3);
2397 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2400 SetClockIcon (int color)
2403 Pixmap pm = *clockIcons[color];
2404 if (iconPixmap != pm) {
2406 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2407 XtSetValues(shellWidget, args, 1);
2412 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2414 InputSource *is = (InputSource *) closure;
2419 if (is->lineByLine) {
2420 count = read(is->fd, is->unused,
2421 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2423 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2426 is->unused += count;
2428 while (p < is->unused) {
2429 q = memchr(p, '\n', is->unused - p);
2430 if (q == NULL) break;
2432 (is->func)(is, is->closure, p, q - p, 0);
2436 while (p < is->unused) {
2441 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2446 (is->func)(is, is->closure, is->buf, count, error);
2451 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2454 ChildProc *cp = (ChildProc *) pr;
2456 is = (InputSource *) calloc(1, sizeof(InputSource));
2457 is->lineByLine = lineByLine;
2461 is->fd = fileno(stdin);
2463 is->kind = cp->kind;
2464 is->fd = cp->fdFrom;
2467 is->unused = is->buf;
2470 is->xid = XtAppAddInput(appContext, is->fd,
2471 (XtPointer) (XtInputReadMask),
2472 (XtInputCallbackProc) DoInputCallback,
2474 is->closure = closure;
2475 return (InputSourceRef) is;
2479 RemoveInputSource (InputSourceRef isr)
2481 InputSource *is = (InputSource *) isr;
2483 if (is->xid == 0) return;
2484 XtRemoveInput(is->xid);
2490 static Boolean frameWaiting;
2493 FrameAlarm (int sig)
2495 frameWaiting = False;
2496 /* In case System-V style signals. Needed?? */
2497 signal(SIGALRM, FrameAlarm);
2501 FrameDelay (int time)
2503 struct itimerval delay;
2505 XSync(xDisplay, False);
2508 frameWaiting = True;
2509 signal(SIGALRM, FrameAlarm);
2510 delay.it_interval.tv_sec =
2511 delay.it_value.tv_sec = time / 1000;
2512 delay.it_interval.tv_usec =
2513 delay.it_value.tv_usec = (time % 1000) * 1000;
2514 setitimer(ITIMER_REAL, &delay, NULL);
2515 while (frameWaiting) pause();
2516 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2517 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2518 setitimer(ITIMER_REAL, &delay, NULL);
2525 FrameDelay (int time)
2527 XSync(xDisplay, False);
2529 usleep(time * 1000);
2535 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2537 char buf[MSG_SIZ], *logoName = buf;
2538 if(appData.logo[n][0]) {
2539 logoName = appData.logo[n];
2540 } else if(appData.autoLogo) {
2541 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2542 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2543 } else if(appData.directory[n] && appData.directory[n][0]) {
2544 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2548 { ASSIGN(cps->programLogo, logoName); }
2552 UpdateLogos (int displ)
2554 if(optList[W_WHITE-1].handle == NULL) return;
2555 LoadLogo(&first, 0, 0);
2556 LoadLogo(&second, 1, appData.icsActive);
2557 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);