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"
209 #include "engineoutput.h"
219 #define usleep(t) _sleep2(((t)+500)/1000)
223 # define _(s) gettext (s)
224 # define N_(s) gettext_noop (s)
230 int main P((int argc, char **argv));
231 RETSIGTYPE CmailSigHandler P((int sig));
232 RETSIGTYPE IntSigHandler P((int sig));
233 RETSIGTYPE TermSizeSigHandler P((int sig));
234 Widget CreateMenuBar P((Menu *mb, int boardWidth));
236 char *InsertPxlSize P((char *pattern, int targetPxlSize));
237 XFontSet CreateFontSet P((char *base_fnt_lst));
239 char *FindFont P((char *pattern, int targetPxlSize));
241 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
242 u_int wreq, u_int hreq));
243 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
244 void DelayedDrag P((void));
245 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
246 void HandlePV P((Widget w, XEvent * event,
247 String * params, Cardinal * nParams));
248 void DrawPositionProc P((Widget w, XEvent *event,
249 String *prms, Cardinal *nprms));
250 void CommentClick P((Widget w, XEvent * event,
251 String * params, Cardinal * nParams));
252 void ICSInputBoxPopUp P((void));
253 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
254 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
255 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
256 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
257 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
258 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
259 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
260 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
261 Boolean TempBackwardActive = False;
262 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
263 void DisplayMove P((int moveNumber));
264 void ICSInitScript P((void));
265 void update_ics_width P(());
266 int CopyMemoProc P(());
269 * XBoard depends on Xt R4 or higher
271 int xtVersion = XtSpecificationRelease;
276 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
277 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
278 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
279 Option *optList; // contains all widgets of main window
281 XFontSet fontSet, clockFontSet;
284 XFontStruct *clockFontStruct;
286 Font coordFontID, countFontID;
287 XFontStruct *coordFontStruct, *countFontStruct;
288 XtAppContext appContext;
291 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
293 Position commentX = -1, commentY = -1;
294 Dimension commentW, commentH;
295 typedef unsigned int BoardSize;
297 Boolean chessProgram;
299 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
300 int smallLayout = 0, tinyLayout = 0,
301 marginW, marginH, // [HGM] for run-time resizing
302 fromX = -1, fromY = -1, toX, toY, commentUp = False,
303 errorExitStatus = -1, defaultLineGap;
304 Dimension textHeight;
305 Pixel timerForegroundPixel, timerBackgroundPixel;
306 Pixel buttonForegroundPixel, buttonBackgroundPixel;
307 char *chessDir, *programName, *programVersion;
308 Boolean alwaysOnTop = False;
309 char *icsTextMenuString;
311 char *firstChessProgramNames;
312 char *secondChessProgramNames;
314 WindowPlacement wpMain;
315 WindowPlacement wpConsole;
316 WindowPlacement wpComment;
317 WindowPlacement wpMoveHistory;
318 WindowPlacement wpEvalGraph;
319 WindowPlacement wpEngineOutput;
320 WindowPlacement wpGameList;
321 WindowPlacement wpTags;
324 /* This magic number is the number of intermediate frames used
325 in each half of the animation. For short moves it's reduced
326 by 1. The total number of frames will be factor * 2 + 1. */
329 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
336 DropMenuEnables dmEnables[] = {
353 XtResource clientResources[] = {
354 { "flashCount", "flashCount", XtRInt, sizeof(int),
355 XtOffset(AppDataPtr, flashCount), XtRImmediate,
356 (XtPointer) FLASH_COUNT },
359 XrmOptionDescRec shellOptions[] = {
360 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
361 { "-flash", "flashCount", XrmoptionNoArg, "3" },
362 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
365 XtActionsRec boardActions[] = {
366 { "DrawPosition", DrawPositionProc },
367 { "HandlePV", HandlePV },
368 { "SelectPV", SelectPV },
369 { "StopPV", StopPV },
370 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
371 { "QuitProc", QuitWrapper },
372 { "ManProc", ManInner },
373 { "TempBackwardProc", TempBackwardProc },
374 { "TempForwardProc", TempForwardProc },
375 { "CommentClick", (XtActionProc) CommentClick },
376 { "GenericPopDown", (XtActionProc) GenericPopDown },
377 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
378 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
379 { "SelectMove", (XtActionProc) SelectMoveX },
380 { "LoadSelectedProc", LoadSelectedProc },
381 { "SetFilterProc", SetFilterProc },
382 { "TypeInProc", TypeInProc },
383 { "EnterKeyProc", EnterKeyProc },
384 { "UpKeyProc", UpKeyProc },
385 { "DownKeyProc", DownKeyProc },
386 { "WheelProc", WheelProc },
387 { "TabProc", TabProc },
390 char globalTranslations[] =
391 ":<Key>F9: MenuItem(Actions.Resign) \n \
392 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
393 :Meta<Key>V: MenuItem(File.NewVariant) \n \
394 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
395 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
396 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
397 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
398 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
399 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
400 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
401 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
402 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
403 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
404 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
405 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
406 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
407 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
408 :Ctrl<Key>q: MenuItem(File.Quit) \n \
409 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
410 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
411 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
412 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
413 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
414 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
415 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
416 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
417 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
418 :Meta<Key>G: MenuItem(View.GameList) \n \
419 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
420 :<Key>Pause: MenuItem(Mode.Pause) \n \
421 :<Key>F3: MenuItem(Action.Accept) \n \
422 :<Key>F4: MenuItem(Action.Decline) \n \
423 :<Key>F12: MenuItem(Action.Rematch) \n \
424 :<Key>F5: MenuItem(Action.CallFlag) \n \
425 :<Key>F6: MenuItem(Action.Draw) \n \
426 :<Key>F7: MenuItem(Action.Adjourn) \n \
427 :<Key>F8: MenuItem(Action.Abort) \n \
428 :<Key>F10: MenuItem(Action.StopObserving) \n \
429 :<Key>F11: MenuItem(Action.StopExamining) \n \
430 :Ctrl<Key>d: MenuItem(DebugProc) \n \
431 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
432 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
433 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
434 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
435 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
436 :<Key>Left: MenuItem(Edit.Backward) \n \
437 :<Key>Right: MenuItem(Edit.Forward) \n \
438 :<Key>Home: MenuItem(Edit.Revert) \n \
439 :<Key>End: MenuItem(Edit.TruncateGame) \n \
440 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
441 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
442 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
443 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
444 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
445 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
446 #ifndef OPTIONSDIALOG
448 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
449 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
450 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
451 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
452 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
455 :<Key>F1: MenuItem(Help.ManXBoard) \n \
456 :<Key>F2: MenuItem(View.FlipView) \n \
457 :<KeyDown>Return: TempBackwardProc() \n \
458 :<KeyUp>Return: TempForwardProc() \n";
460 char ICSInputTranslations[] =
461 "<Key>Up: UpKeyProc() \n "
462 "<Key>Down: DownKeyProc() \n "
463 "<Key>Return: EnterKeyProc() \n";
465 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
466 // as the widget is destroyed before the up-click can call extend-end
467 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
469 String xboardResources[] = {
470 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
475 /* Max possible square size */
476 #define MAXSQSIZE 256
478 static int xpm_avail[MAXSQSIZE];
480 #ifdef HAVE_DIR_STRUCT
482 /* Extract piece size from filename */
484 xpm_getsize (char *name, int len, char *ext)
492 if ((p=strchr(name, '.')) == NULL ||
493 StrCaseCmp(p+1, ext) != 0)
499 while (*p && isdigit(*p))
506 /* Setup xpm_avail */
508 xpm_getavail (char *dirname, char *ext)
514 for (i=0; i<MAXSQSIZE; ++i)
517 if (appData.debugMode)
518 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
520 dir = opendir(dirname);
523 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
524 programName, dirname);
528 while ((ent=readdir(dir)) != NULL) {
529 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
530 if (i > 0 && i < MAXSQSIZE)
540 xpm_print_avail (FILE *fp, char *ext)
544 fprintf(fp, _("Available `%s' sizes:\n"), ext);
545 for (i=1; i<MAXSQSIZE; ++i) {
551 /* Return XPM piecesize closest to size */
553 xpm_closest_to (char *dirname, int size, char *ext)
556 int sm_diff = MAXSQSIZE;
560 xpm_getavail(dirname, ext);
562 if (appData.debugMode)
563 xpm_print_avail(stderr, ext);
565 for (i=1; i<MAXSQSIZE; ++i) {
568 diff = (diff<0) ? -diff : diff;
569 if (diff < sm_diff) {
577 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
583 #else /* !HAVE_DIR_STRUCT */
584 /* If we are on a system without a DIR struct, we can't
585 read the directory, so we can't collect a list of
586 filenames, etc., so we can't do any size-fitting. */
588 xpm_closest_to (char *dirname, int size, char *ext)
591 Warning: No DIR structure found on this system --\n\
592 Unable to autosize for XPM/XIM pieces.\n\
593 Please report this error to %s.\n\
594 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
597 #endif /* HAVE_DIR_STRUCT */
600 /* Arrange to catch delete-window events */
601 Atom wm_delete_window;
603 CatchDeleteWindow (Widget w, String procname)
606 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
607 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
608 XtAugmentTranslations(w, XtParseTranslationTable(buf));
615 XtSetArg(args[0], XtNiconic, False);
616 XtSetValues(shellWidget, args, 1);
618 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
621 //---------------------------------------------------------------------------------------------------------
622 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
625 #define CW_USEDEFAULT (1<<31)
626 #define ICS_TEXT_MENU_SIZE 90
627 #define DEBUG_FILE "xboard.debug"
628 #define SetCurrentDirectory chdir
629 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
633 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
636 // front-end part of option handling
638 // [HGM] This platform-dependent table provides the location for storing the color info
639 extern char *crWhite, * crBlack;
643 &appData.whitePieceColor,
644 &appData.blackPieceColor,
645 &appData.lightSquareColor,
646 &appData.darkSquareColor,
647 &appData.highlightSquareColor,
648 &appData.premoveHighlightColor,
649 &appData.lowTimeWarningColor,
660 // [HGM] font: keep a font for each square size, even non-stndard ones
663 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
664 char *fontTable[NUM_FONTS][MAX_SIZE];
667 ParseFont (char *name, int number)
668 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
670 if(sscanf(name, "size%d:", &size)) {
671 // [HGM] font: font is meant for specific boardSize (likely from settings file);
672 // defer processing it until we know if it matches our board size
673 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
674 fontTable[number][size] = strdup(strchr(name, ':')+1);
675 fontValid[number][size] = True;
680 case 0: // CLOCK_FONT
681 appData.clockFont = strdup(name);
683 case 1: // MESSAGE_FONT
684 appData.font = strdup(name);
686 case 2: // COORD_FONT
687 appData.coordFont = strdup(name);
692 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
697 { // only 2 fonts currently
698 appData.clockFont = CLOCK_FONT_NAME;
699 appData.coordFont = COORD_FONT_NAME;
700 appData.font = DEFAULT_FONT_NAME;
705 { // no-op, until we identify the code for this already in XBoard and move it here
709 ParseColor (int n, char *name)
710 { // in XBoard, just copy the color-name string
711 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
715 ParseTextAttribs (ColorClass cc, char *s)
717 (&appData.colorShout)[cc] = strdup(s);
721 ParseBoardSize (void *addr, char *name)
723 appData.boardSize = strdup(name);
728 { // In XBoard the sound-playing program takes care of obtaining the actual sound
732 SetCommPortDefaults ()
733 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
736 // [HGM] args: these three cases taken out to stay in front-end
738 SaveFontArg (FILE *f, ArgDescriptor *ad)
741 int i, n = (int)(intptr_t)ad->argLoc;
743 case 0: // CLOCK_FONT
744 name = appData.clockFont;
746 case 1: // MESSAGE_FONT
749 case 2: // COORD_FONT
750 name = appData.coordFont;
755 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
756 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
757 fontTable[n][squareSize] = strdup(name);
758 fontValid[n][squareSize] = True;
761 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
762 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
767 { // nothing to do, as the sounds are at all times represented by their text-string names already
771 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
772 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
773 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
777 SaveColor (FILE *f, ArgDescriptor *ad)
778 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
779 if(colorVariable[(int)(intptr_t)ad->argLoc])
780 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
784 SaveBoardSize (FILE *f, char *name, void *addr)
785 { // wrapper to shield back-end from BoardSize & sizeInfo
786 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
790 ParseCommPortSettings (char *s)
791 { // no such option in XBoard (yet)
797 GetActualPlacement (Widget wg, WindowPlacement *wp)
799 XWindowAttributes winAt;
806 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
807 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
808 wp->x = rx - winAt.x;
809 wp->y = ry - winAt.y;
810 wp->height = winAt.height;
811 wp->width = winAt.width;
812 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
817 { // wrapper to shield use of window handles from back-end (make addressible by number?)
818 // In XBoard this will have to wait until awareness of window parameters is implemented
819 GetActualPlacement(shellWidget, &wpMain);
820 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
821 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
822 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
823 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
824 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
825 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
829 PrintCommPortSettings (FILE *f, char *name)
830 { // This option does not exist in XBoard
834 EnsureOnScreen (int *x, int *y, int minX, int minY)
841 { // [HGM] args: allows testing if main window is realized from back-end
842 return xBoardWindow != 0;
846 PopUpStartupDialog ()
847 { // start menu not implemented in XBoard
851 ConvertToLine (int argc, char **argv)
853 static char line[128*1024], buf[1024];
857 for(i=1; i<argc; i++)
859 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
860 && argv[i][0] != '{' )
861 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
863 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
864 strncat(line, buf, 128*1024 - strlen(line) - 1 );
867 line[strlen(line)-1] = NULLCHAR;
871 //--------------------------------------------------------------------------------------------
874 ResizeBoardWindow (int w, int h, int inhibit)
876 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
878 shellArgs[0].value = w;
879 shellArgs[1].value = h;
880 shellArgs[4].value = shellArgs[2].value = w;
881 shellArgs[5].value = shellArgs[3].value = h;
882 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
884 XSync(xDisplay, False);
888 MakeOneColor (char *name, Pixel *color)
891 if (!appData.monoMode) {
892 vFrom.addr = (caddr_t) name;
893 vFrom.size = strlen(name);
894 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
895 if (vTo.addr == NULL) {
896 appData.monoMode = True;
899 *color = *(Pixel *) vTo.addr;
907 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
908 int forceMono = False;
910 if (appData.lowTimeWarning)
911 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
912 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
913 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
919 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
920 { // detervtomine what fonts to use, and create them
924 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
925 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
926 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
927 appData.font = fontTable[MESSAGE_FONT][squareSize];
928 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
929 appData.coordFont = fontTable[COORD_FONT][squareSize];
932 appData.font = InsertPxlSize(appData.font, fontPxlSize);
933 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
934 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
935 fontSet = CreateFontSet(appData.font);
936 clockFontSet = CreateFontSet(appData.clockFont);
938 /* For the coordFont, use the 0th font of the fontset. */
939 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
940 XFontStruct **font_struct_list;
941 XFontSetExtents *fontSize;
942 char **font_name_list;
943 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
944 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
945 coordFontStruct = XQueryFont(xDisplay, coordFontID);
946 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
947 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
950 appData.font = FindFont(appData.font, fontPxlSize);
951 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
952 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
953 clockFontID = XLoadFont(xDisplay, appData.clockFont);
954 clockFontStruct = XQueryFont(xDisplay, clockFontID);
955 coordFontID = XLoadFont(xDisplay, appData.coordFont);
956 coordFontStruct = XQueryFont(xDisplay, coordFontID);
957 // textHeight in !NLS mode!
959 countFontID = coordFontID; // [HGM] holdings
960 countFontStruct = coordFontStruct;
962 xdb = XtDatabase(xDisplay);
964 XrmPutLineResource(&xdb, "*international: True");
965 vTo.size = sizeof(XFontSet);
966 vTo.addr = (XtPointer) &fontSet;
967 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
969 XrmPutStringResource(&xdb, "*font", appData.font);
979 case ArgInt: p = " N"; break;
980 case ArgString: p = " STR"; break;
981 case ArgBoolean: p = " TF"; break;
982 case ArgSettingsFilename:
983 case ArgFilename: p = " FILE"; break;
984 case ArgX: p = " Nx"; break;
985 case ArgY: p = " Ny"; break;
986 case ArgAttribs: p = " TEXTCOL"; break;
987 case ArgColor: p = " COL"; break;
988 case ArgFont: p = " FONT"; break;
989 case ArgBoardSize: p = " SIZE"; break;
990 case ArgFloat: p = " FLOAT"; break;
995 case ArgCommSettings:
1006 ArgDescriptor *q, *p = argDescriptors+5;
1007 printf("\nXBoard accepts the following options:\n"
1008 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1009 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1010 " SIZE = board-size spec(s)\n"
1011 " Within parentheses are short forms, or options to set to true or false.\n"
1012 " Persistent options (saved in the settings file) are marked with *)\n\n");
1014 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1015 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1016 if(p->save) strcat(buf+len, "*");
1017 for(q=p+1; q->argLoc == p->argLoc; q++) {
1018 if(q->argName[0] == '-') continue;
1019 strcat(buf+len, q == p+1 ? " (" : " ");
1020 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1022 if(q != p+1) strcat(buf+len, ")");
1024 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1027 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1031 main (int argc, char **argv)
1033 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1034 XSetWindowAttributes window_attributes;
1036 Dimension boardWidth, boardHeight, w, h;
1038 int forceMono = False;
1040 srandom(time(0)); // [HGM] book: make random truly random
1042 setbuf(stdout, NULL);
1043 setbuf(stderr, NULL);
1046 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1047 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1051 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1056 programName = strrchr(argv[0], '/');
1057 if (programName == NULL)
1058 programName = argv[0];
1063 XtSetLanguageProc(NULL, NULL, NULL);
1064 if (appData.debugMode) {
1065 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1068 bindtextdomain(PACKAGE, LOCALEDIR);
1069 textdomain(PACKAGE);
1072 appData.boardSize = "";
1073 InitAppData(ConvertToLine(argc, argv));
1075 if (p == NULL) p = "/tmp";
1076 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1077 gameCopyFilename = (char*) malloc(i);
1078 gamePasteFilename = (char*) malloc(i);
1079 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1080 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1082 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1083 static char buf[MSG_SIZ];
1084 EscapeExpand(buf, appData.firstInitString);
1085 appData.firstInitString = strdup(buf);
1086 EscapeExpand(buf, appData.secondInitString);
1087 appData.secondInitString = strdup(buf);
1088 EscapeExpand(buf, appData.firstComputerString);
1089 appData.firstComputerString = strdup(buf);
1090 EscapeExpand(buf, appData.secondComputerString);
1091 appData.secondComputerString = strdup(buf);
1094 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1097 if (chdir(chessDir) != 0) {
1098 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1104 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1105 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1106 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1107 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1110 setbuf(debugFP, NULL);
1113 /* [HGM,HR] make sure board size is acceptable */
1114 if(appData.NrFiles > BOARD_FILES ||
1115 appData.NrRanks > BOARD_RANKS )
1116 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1119 /* This feature does not work; animation needs a rewrite */
1120 appData.highlightDragging = FALSE;
1124 gameInfo.variant = StringToVariant(appData.variant);
1125 InitPosition(FALSE);
1128 XtAppInitialize(&appContext, "XBoard", shellOptions,
1129 XtNumber(shellOptions),
1130 &argc, argv, xboardResources, NULL, 0);
1132 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1133 clientResources, XtNumber(clientResources),
1136 xDisplay = XtDisplay(shellWidget);
1137 xScreen = DefaultScreen(xDisplay);
1138 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1141 * determine size, based on supplied or remembered -size, or screen size
1143 if (isdigit(appData.boardSize[0])) {
1144 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1145 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1146 &fontPxlSize, &smallLayout, &tinyLayout);
1148 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1149 programName, appData.boardSize);
1153 /* Find some defaults; use the nearest known size */
1154 SizeDefaults *szd, *nearest;
1155 int distance = 99999;
1156 nearest = szd = sizeDefaults;
1157 while (szd->name != NULL) {
1158 if (abs(szd->squareSize - squareSize) < distance) {
1160 distance = abs(szd->squareSize - squareSize);
1161 if (distance == 0) break;
1165 if (i < 2) lineGap = nearest->lineGap;
1166 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1167 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1168 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1169 if (i < 6) smallLayout = nearest->smallLayout;
1170 if (i < 7) tinyLayout = nearest->tinyLayout;
1173 SizeDefaults *szd = sizeDefaults;
1174 if (*appData.boardSize == NULLCHAR) {
1175 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1176 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1179 if (szd->name == NULL) szd--;
1180 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1182 while (szd->name != NULL &&
1183 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1184 if (szd->name == NULL) {
1185 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1186 programName, appData.boardSize);
1190 squareSize = szd->squareSize;
1191 lineGap = szd->lineGap;
1192 clockFontPxlSize = szd->clockFontPxlSize;
1193 coordFontPxlSize = szd->coordFontPxlSize;
1194 fontPxlSize = szd->fontPxlSize;
1195 smallLayout = szd->smallLayout;
1196 tinyLayout = szd->tinyLayout;
1197 // [HGM] font: use defaults from settings file if available and not overruled
1200 defaultLineGap = lineGap;
1201 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1203 /* [HR] height treated separately (hacked) */
1204 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1205 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1208 * Determine what fonts to use.
1210 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1213 * Detect if there are not enough colors available and adapt.
1215 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1216 appData.monoMode = True;
1219 forceMono = MakeColors();
1222 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1224 appData.monoMode = True;
1227 if (appData.monoMode && appData.debugMode) {
1228 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1229 (unsigned long) XWhitePixel(xDisplay, xScreen),
1230 (unsigned long) XBlackPixel(xDisplay, xScreen));
1233 ParseIcsTextColors();
1235 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1241 layoutName = "tinyLayout";
1242 } else if (smallLayout) {
1243 layoutName = "smallLayout";
1245 layoutName = "normalLayout";
1248 optList = BoardPopUp(squareSize, lineGap, (void*)
1254 InitDrawingHandle(optList + W_BOARD);
1255 currBoard = &optList[W_BOARD];
1256 boardWidget = optList[W_BOARD].handle;
1257 menuBarWidget = optList[W_MENU].handle;
1258 dropMenu = optList[W_DROP].handle;
1259 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1260 formWidget = XtParent(boardWidget);
1261 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1262 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1263 XtGetValues(optList[W_WHITE].handle, args, 2);
1264 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1265 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1266 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1267 XtGetValues(optList[W_PAUSE].handle, args, 2);
1269 AppendEnginesToMenu(appData.recentEngineList);
1271 xBoardWindow = XtWindow(boardWidget);
1273 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1274 // not need to go into InitDrawingSizes().
1277 * Create X checkmark bitmap and initialize option menu checks.
1279 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1280 checkmark_bits, checkmark_width, checkmark_height);
1286 ReadBitmap(&wIconPixmap, "icon_white.bm",
1287 icon_white_bits, icon_white_width, icon_white_height);
1288 ReadBitmap(&bIconPixmap, "icon_black.bm",
1289 icon_black_bits, icon_black_width, icon_black_height);
1290 iconPixmap = wIconPixmap;
1292 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1293 XtSetValues(shellWidget, args, i);
1296 * Create a cursor for the board widget.
1298 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1299 XChangeWindowAttributes(xDisplay, xBoardWindow,
1300 CWCursor, &window_attributes);
1303 * Inhibit shell resizing.
1305 shellArgs[0].value = (XtArgVal) &w;
1306 shellArgs[1].value = (XtArgVal) &h;
1307 XtGetValues(shellWidget, shellArgs, 2);
1308 shellArgs[4].value = shellArgs[2].value = w;
1309 shellArgs[5].value = shellArgs[3].value = h;
1310 // XtSetValues(shellWidget, &shellArgs[2], 4);
1311 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1312 marginH = h - boardHeight;
1314 CatchDeleteWindow(shellWidget, "QuitProc");
1319 if(appData.logoSize)
1320 { // locate and read user logo
1322 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1323 ASSIGN(userLogo, buf);
1326 if (appData.animate || appData.animateDragging)
1329 XtAugmentTranslations(formWidget,
1330 XtParseTranslationTable(globalTranslations));
1332 XtAddEventHandler(formWidget, KeyPressMask, False,
1333 (XtEventHandler) MoveTypeInProc, NULL);
1334 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1335 (XtEventHandler) EventProc, NULL);
1337 /* [AS] Restore layout */
1338 if( wpMoveHistory.visible ) {
1342 if( wpEvalGraph.visible )
1347 if( wpEngineOutput.visible ) {
1348 EngineOutputPopUp();
1353 if (errorExitStatus == -1) {
1354 if (appData.icsActive) {
1355 /* We now wait until we see "login:" from the ICS before
1356 sending the logon script (problems with timestamp otherwise) */
1357 /*ICSInitScript();*/
1358 if (appData.icsInputBox) ICSInputBoxPopUp();
1362 signal(SIGWINCH, TermSizeSigHandler);
1364 signal(SIGINT, IntSigHandler);
1365 signal(SIGTERM, IntSigHandler);
1366 if (*appData.cmailGameName != NULLCHAR) {
1367 signal(SIGUSR1, CmailSigHandler);
1371 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1374 // XtSetKeyboardFocus(shellWidget, formWidget);
1375 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1377 XtAppMainLoop(appContext);
1378 if (appData.debugMode) fclose(debugFP); // [DM] debug
1383 TermSizeSigHandler (int sig)
1389 IntSigHandler (int sig)
1395 CmailSigHandler (int sig)
1400 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1402 /* Activate call-back function CmailSigHandlerCallBack() */
1403 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1405 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1409 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1412 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1414 /**** end signal code ****/
1417 #define Abs(n) ((n)<0 ? -(n) : (n))
1421 InsertPxlSize (char *pattern, int targetPxlSize)
1423 char *base_fnt_lst, strInt[12], *p, *q;
1424 int alternatives, i, len, strIntLen;
1427 * Replace the "*" (if present) in the pixel-size slot of each
1428 * alternative with the targetPxlSize.
1432 while ((p = strchr(p, ',')) != NULL) {
1436 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1437 strIntLen = strlen(strInt);
1438 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1442 while (alternatives--) {
1443 char *comma = strchr(p, ',');
1444 for (i=0; i<14; i++) {
1445 char *hyphen = strchr(p, '-');
1447 if (comma && hyphen > comma) break;
1448 len = hyphen + 1 - p;
1449 if (i == 7 && *p == '*' && len == 2) {
1451 memcpy(q, strInt, strIntLen);
1461 len = comma + 1 - p;
1468 return base_fnt_lst;
1472 CreateFontSet (char *base_fnt_lst)
1475 char **missing_list;
1479 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1480 &missing_list, &missing_count, &def_string);
1481 if (appData.debugMode) {
1483 XFontStruct **font_struct_list;
1484 char **font_name_list;
1485 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1487 fprintf(debugFP, " got list %s, locale %s\n",
1488 XBaseFontNameListOfFontSet(fntSet),
1489 XLocaleOfFontSet(fntSet));
1490 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1491 for (i = 0; i < count; i++) {
1492 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1495 for (i = 0; i < missing_count; i++) {
1496 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1499 if (fntSet == NULL) {
1500 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1505 #else // not ENABLE_NLS
1507 * Find a font that matches "pattern" that is as close as
1508 * possible to the targetPxlSize. Prefer fonts that are k
1509 * pixels smaller to fonts that are k pixels larger. The
1510 * pattern must be in the X Consortium standard format,
1511 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1512 * The return value should be freed with XtFree when no
1516 FindFont (char *pattern, int targetPxlSize)
1518 char **fonts, *p, *best, *scalable, *scalableTail;
1519 int i, j, nfonts, minerr, err, pxlSize;
1521 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1523 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1524 programName, pattern);
1531 for (i=0; i<nfonts; i++) {
1534 if (*p != '-') continue;
1536 if (*p == NULLCHAR) break;
1537 if (*p++ == '-') j++;
1539 if (j < 7) continue;
1542 scalable = fonts[i];
1545 err = pxlSize - targetPxlSize;
1546 if (Abs(err) < Abs(minerr) ||
1547 (minerr > 0 && err < 0 && -err == minerr)) {
1553 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1554 /* If the error is too big and there is a scalable font,
1555 use the scalable font. */
1556 int headlen = scalableTail - scalable;
1557 p = (char *) XtMalloc(strlen(scalable) + 10);
1558 while (isdigit(*scalableTail)) scalableTail++;
1559 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1561 p = (char *) XtMalloc(strlen(best) + 2);
1562 safeStrCpy(p, best, strlen(best)+1 );
1564 if (appData.debugMode) {
1565 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1566 pattern, targetPxlSize, p);
1568 XFreeFontNames(fonts);
1574 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1577 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1583 MarkMenuItem (char *menuRef, int state)
1585 MenuItem *item = MenuNameToItem(menuRef);
1589 XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
1590 XtSetValues(item->handle, args, 1);
1595 EnableNamedMenuItem (char *menuRef, int state)
1597 MenuItem *item = MenuNameToItem(menuRef);
1599 if(item) XtSetSensitive(item->handle, state);
1603 EnableButtonBar (int state)
1605 XtSetSensitive(optList[W_BUTTON].handle, state);
1610 SetMenuEnables (Enables *enab)
1612 while (enab->name != NULL) {
1613 EnableNamedMenuItem(enab->name, enab->value);
1619 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1620 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1622 if(*nprms == 0) return;
1623 item = MenuNameToItem(prms[0]);
1624 if(item) ((MenuProc *) item->proc) ();
1628 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1630 RecentEngineEvent((int) (intptr_t) addr);
1634 AppendMenuItem (char *msg, int n)
1636 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1648 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1649 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1650 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1651 dmEnables[i].piece);
1652 XtSetSensitive(entry, p != NULL || !appData.testLegality
1653 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1654 && !appData.icsActive));
1656 while (p && *p++ == dmEnables[i].piece) count++;
1657 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1659 XtSetArg(args[j], XtNlabel, label); j++;
1660 XtSetValues(entry, args, j);
1665 do_flash_delay (unsigned long msec)
1671 FlashDelay (int flash_delay)
1673 XSync(xDisplay, False);
1674 if(flash_delay) do_flash_delay(flash_delay);
1678 Fraction (int x, int start, int stop)
1680 double f = ((double) x - start)/(stop - start);
1681 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1685 static WindowPlacement wpNew;
1688 CoDrag (Widget sh, WindowPlacement *wp)
1691 int j=0, touch=0, fudge = 2;
1692 GetActualPlacement(sh, wp);
1693 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1694 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1695 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1696 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1697 if(!touch ) return; // only windows that touch co-move
1698 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1699 int heightInc = wpNew.height - wpMain.height;
1700 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1701 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1702 wp->y += fracTop * heightInc;
1703 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1704 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1705 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1706 int widthInc = wpNew.width - wpMain.width;
1707 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1708 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1709 wp->y += fracLeft * widthInc;
1710 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1711 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1713 wp->x += wpNew.x - wpMain.x;
1714 wp->y += wpNew.y - wpMain.y;
1715 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1716 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1717 XtSetArg(args[j], XtNx, wp->x); j++;
1718 XtSetArg(args[j], XtNy, wp->y); j++;
1719 XtSetValues(sh, args, j);
1723 ReSize (WindowPlacement *wp)
1726 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1727 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1728 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1729 if(sqy < sqx) sqx = sqy;
1730 if(sqx != squareSize) {
1731 squareSize = sqx; // adopt new square size
1732 CreatePNGPieces(); // make newly scaled pieces
1733 InitDrawingSizes(0, 0); // creates grid etc.
1734 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1735 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1736 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1737 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1738 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1741 static XtIntervalId delayedDragID = 0;
1750 GetActualPlacement(shellWidget, &wpNew);
1751 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1752 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1753 busy = 0; return; // false alarm
1756 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1757 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1758 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1759 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1761 DrawPosition(True, NULL);
1762 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1770 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1772 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1776 EventProc (Widget widget, caddr_t unused, XEvent *event)
1778 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1779 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1783 * event handler for redrawing the board
1786 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1788 DrawPosition(True, NULL);
1793 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1794 { // [HGM] pv: walk PV
1795 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1798 static int savedIndex; /* gross that this is global */
1801 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1804 XawTextPosition index, dummy;
1807 XawTextGetSelectionPos(w, &index, &dummy);
1808 XtSetArg(arg, XtNstring, &val);
1809 XtGetValues(w, &arg, 1);
1810 ReplaceComment(savedIndex, val);
1811 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1812 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1816 EditCommentPopUp (int index, char *title, char *text)
1819 if (text == NULL) text = "";
1820 NewCommentPopup(title, text, index);
1824 CommentPopUp (char *title, char *text)
1826 savedIndex = currentMove; // [HGM] vari
1827 NewCommentPopup(title, text, currentMove);
1833 PopDown(CommentDlg);
1837 /* Disable all user input other than deleting the window */
1838 static int frozen = 0;
1844 /* Grab by a widget that doesn't accept input */
1845 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1849 /* Undo a FreezeUI */
1853 if (!frozen) return;
1854 XtRemoveGrab(optList[W_MESSG].handle);
1862 static int oldPausing = FALSE;
1863 static GameMode oldmode = (GameMode) -1;
1866 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1868 if (pausing != oldPausing) {
1869 oldPausing = pausing;
1870 MarkMenuItem("Mode.Pause", pausing);
1872 if (appData.showButtonBar) {
1873 /* Always toggle, don't set. Previous code messes up when
1874 invoked while the button is pressed, as releasing it
1875 toggles the state again. */
1878 XtSetArg(args[0], XtNbackground, &oldbg);
1879 XtSetArg(args[1], XtNforeground, &oldfg);
1880 XtGetValues(optList[W_PAUSE].handle,
1882 XtSetArg(args[0], XtNbackground, oldfg);
1883 XtSetArg(args[1], XtNforeground, oldbg);
1885 XtSetValues(optList[W_PAUSE].handle, args, 2);
1889 wname = ModeToWidgetName(oldmode);
1890 if (wname != NULL) {
1891 MarkMenuItem(wname, False);
1893 wname = ModeToWidgetName(gameMode);
1894 if (wname != NULL) {
1895 MarkMenuItem(wname, True);
1898 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1900 /* Maybe all the enables should be handled here, not just this one */
1901 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1903 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1908 * Button/menu procedures
1911 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1912 char *selected_fen_position=NULL;
1915 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1916 Atom *type_return, XtPointer *value_return,
1917 unsigned long *length_return, int *format_return)
1919 char *selection_tmp;
1921 // if (!selected_fen_position) return False; /* should never happen */
1922 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1923 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1924 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1927 if (f == NULL) return False;
1931 selection_tmp = XtMalloc(len + 1);
1932 count = fread(selection_tmp, 1, len, f);
1935 XtFree(selection_tmp);
1938 selection_tmp[len] = NULLCHAR;
1940 /* note: since no XtSelectionDoneProc was registered, Xt will
1941 * automatically call XtFree on the value returned. So have to
1942 * make a copy of it allocated with XtMalloc */
1943 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
1944 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
1947 *value_return=selection_tmp;
1948 *length_return=strlen(selection_tmp);
1949 *type_return=*target;
1950 *format_return = 8; /* bits per byte */
1952 } else if (*target == XA_TARGETS(xDisplay)) {
1953 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
1954 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
1955 targets_tmp[1] = XA_STRING;
1956 *value_return = targets_tmp;
1957 *type_return = XA_ATOM;
1960 // This code leads to a read of value_return out of bounds on 64-bit systems.
1961 // Other code which I have seen always sets *format_return to 32 independent of
1962 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
1963 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
1964 *format_return = 8 * sizeof(Atom);
1965 if (*format_return > 32) {
1966 *length_return *= *format_return / 32;
1967 *format_return = 32;
1970 *format_return = 32;
1978 /* note: when called from menu all parameters are NULL, so no clue what the
1979 * Widget which was clicked on was, or what the click event was
1982 CopySomething (char *src)
1984 selected_fen_position = src;
1986 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
1987 * have a notion of a position that is selected but not copied.
1988 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
1990 XtOwnSelection(menuBarWidget, XA_PRIMARY,
1992 SendPositionSelection,
1993 NULL/* lose_ownership_proc */ ,
1994 NULL/* transfer_done_proc */);
1995 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
1997 SendPositionSelection,
1998 NULL/* lose_ownership_proc */ ,
1999 NULL/* transfer_done_proc */);
2002 /* function called when the data to Paste is ready */
2004 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2005 Atom *type, XtPointer value, unsigned long *len, int *format)
2008 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2009 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2010 EditPositionPasteFEN(fenstr);
2014 /* called when Paste Position button is pressed,
2015 * all parameters will be NULL */
2017 PastePositionProc ()
2019 XtGetSelectionValue(menuBarWidget,
2020 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2021 /* (XtSelectionCallbackProc) */ PastePositionCB,
2022 NULL, /* client_data passed to PastePositionCB */
2024 /* better to use the time field from the event that triggered the
2025 * call to this function, but that isn't trivial to get
2032 /* note: when called from menu all parameters are NULL, so no clue what the
2033 * Widget which was clicked on was, or what the click event was
2035 /* function called when the data to Paste is ready */
2037 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2038 Atom *type, XtPointer value, unsigned long *len, int *format)
2041 if (value == NULL || *len == 0) {
2042 return; /* nothing had been selected to copy */
2044 f = fopen(gamePasteFilename, "w");
2046 DisplayError(_("Can't open temp file"), errno);
2049 fwrite(value, 1, *len, f);
2052 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2055 /* called when Paste Game button is pressed,
2056 * all parameters will be NULL */
2060 XtGetSelectionValue(menuBarWidget,
2061 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2062 /* (XtSelectionCallbackProc) */ PasteGameCB,
2063 NULL, /* client_data passed to PasteGameCB */
2065 /* better to use the time field from the event that triggered the
2066 * call to this function, but that isn't trivial to get
2075 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2082 { // bassic primitive for determining if modifier keys are pressed
2083 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2086 XQueryKeymap(xDisplay,keys);
2087 for(i=0; i<6; i++) {
2089 j = XKeysymToKeycode(xDisplay, codes[i]);
2090 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2096 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2100 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2101 if ( n == 1 && *buf >= 32 // printable
2102 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2103 ) BoxAutoPopUp (buf);
2107 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2108 { // [HGM] input: let up-arrow recall previous line from history
2113 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2114 { // [HGM] input: let down-arrow recall next line from history
2119 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2125 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2127 if (!TempBackwardActive) {
2128 TempBackwardActive = True;
2134 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2136 /* Check to see if triggered by a key release event for a repeating key.
2137 * If so the next queued event will be a key press of the same key at the same time */
2138 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2140 XPeekEvent(xDisplay, &next);
2141 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2142 next.xkey.keycode == event->xkey.keycode)
2146 TempBackwardActive = False;
2150 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2151 { // called as key binding
2154 if (nprms && *nprms > 0)
2158 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2164 { // called from menu
2165 ManInner(NULL, NULL, NULL, NULL);
2169 SetWindowTitle (char *text, char *title, char *icon)
2173 if (appData.titleInWindow) {
2175 XtSetArg(args[i], XtNlabel, text); i++;
2176 XtSetValues(titleWidget, args, i);
2179 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2180 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2181 XtSetValues(shellWidget, args, i);
2182 XSync(xDisplay, False);
2187 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2193 DisplayIcsInteractionTitle (String message)
2195 if (oldICSInteractionTitle == NULL) {
2196 /* Magic to find the old window title, adapted from vim */
2197 char *wina = getenv("WINDOWID");
2199 Window win = (Window) atoi(wina);
2200 Window root, parent, *children;
2201 unsigned int nchildren;
2202 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2204 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2205 if (!XQueryTree(xDisplay, win, &root, &parent,
2206 &children, &nchildren)) break;
2207 if (children) XFree((void *)children);
2208 if (parent == root || parent == 0) break;
2211 XSetErrorHandler(oldHandler);
2213 if (oldICSInteractionTitle == NULL) {
2214 oldICSInteractionTitle = "xterm";
2217 printf("\033]0;%s\007", message);
2222 XtIntervalId delayedEventTimerXID = 0;
2223 DelayedEventCallback delayedEventCallback = 0;
2228 delayedEventTimerXID = 0;
2229 delayedEventCallback();
2233 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
2235 if(delayedEventTimerXID && delayedEventCallback == cb)
2236 // [HGM] alive: replace, rather than add or flush identical event
2237 XtRemoveTimeOut(delayedEventTimerXID);
2238 delayedEventCallback = cb;
2239 delayedEventTimerXID =
2240 XtAppAddTimeOut(appContext, millisec,
2241 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
2244 DelayedEventCallback
2247 if (delayedEventTimerXID) {
2248 return delayedEventCallback;
2255 CancelDelayedEvent ()
2257 if (delayedEventTimerXID) {
2258 XtRemoveTimeOut(delayedEventTimerXID);
2259 delayedEventTimerXID = 0;
2263 XtIntervalId loadGameTimerXID = 0;
2266 LoadGameTimerRunning ()
2268 return loadGameTimerXID != 0;
2272 StopLoadGameTimer ()
2274 if (loadGameTimerXID != 0) {
2275 XtRemoveTimeOut(loadGameTimerXID);
2276 loadGameTimerXID = 0;
2284 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
2286 loadGameTimerXID = 0;
2291 StartLoadGameTimer (long millisec)
2294 XtAppAddTimeOut(appContext, millisec,
2295 (XtTimerCallbackProc) LoadGameTimerCallback,
2299 XtIntervalId analysisClockXID = 0;
2302 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
2304 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
2305 || appData.icsEngineAnalyze) { // [DM]
2306 AnalysisPeriodicEvent(0);
2307 StartAnalysisClock();
2312 StartAnalysisClock ()
2315 XtAppAddTimeOut(appContext, 2000,
2316 (XtTimerCallbackProc) AnalysisClockCallback,
2320 XtIntervalId clockTimerXID = 0;
2323 ClockTimerRunning ()
2325 return clockTimerXID != 0;
2331 if (clockTimerXID != 0) {
2332 XtRemoveTimeOut(clockTimerXID);
2341 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
2348 StartClockTimer (long millisec)
2351 XtAppAddTimeOut(appContext, millisec,
2352 (XtTimerCallbackProc) ClockTimerCallback,
2357 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2361 Widget w = (Widget) opt->handle;
2363 /* check for low time warning */
2364 Pixel foregroundOrWarningColor = timerForegroundPixel;
2367 appData.lowTimeWarning &&
2368 (timer / 1000) < appData.icsAlarmTime)
2369 foregroundOrWarningColor = lowTimeWarningColor;
2371 if (appData.clockMode) {
2372 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2373 XtSetArg(args[0], XtNlabel, buf);
2375 snprintf(buf, MSG_SIZ, "%s ", color);
2376 XtSetArg(args[0], XtNlabel, buf);
2381 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2382 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2384 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2385 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2388 XtSetValues(w, args, 3);
2391 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2394 SetClockIcon (int color)
2397 Pixmap pm = *clockIcons[color];
2398 if (iconPixmap != pm) {
2400 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2401 XtSetValues(shellWidget, args, 1);
2405 #define INPUT_SOURCE_BUF_SIZE 8192
2414 char buf[INPUT_SOURCE_BUF_SIZE];
2419 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2421 InputSource *is = (InputSource *) closure;
2426 if (is->lineByLine) {
2427 count = read(is->fd, is->unused,
2428 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2430 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2433 is->unused += count;
2435 while (p < is->unused) {
2436 q = memchr(p, '\n', is->unused - p);
2437 if (q == NULL) break;
2439 (is->func)(is, is->closure, p, q - p, 0);
2443 while (p < is->unused) {
2448 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2453 (is->func)(is, is->closure, is->buf, count, error);
2458 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2461 ChildProc *cp = (ChildProc *) pr;
2463 is = (InputSource *) calloc(1, sizeof(InputSource));
2464 is->lineByLine = lineByLine;
2468 is->fd = fileno(stdin);
2470 is->kind = cp->kind;
2471 is->fd = cp->fdFrom;
2474 is->unused = is->buf;
2477 is->xid = XtAppAddInput(appContext, is->fd,
2478 (XtPointer) (XtInputReadMask),
2479 (XtInputCallbackProc) DoInputCallback,
2481 is->closure = closure;
2482 return (InputSourceRef) is;
2486 RemoveInputSource (InputSourceRef isr)
2488 InputSource *is = (InputSource *) isr;
2490 if (is->xid == 0) return;
2491 XtRemoveInput(is->xid);
2497 static Boolean frameWaiting;
2500 FrameAlarm (int sig)
2502 frameWaiting = False;
2503 /* In case System-V style signals. Needed?? */
2504 signal(SIGALRM, FrameAlarm);
2508 FrameDelay (int time)
2510 struct itimerval delay;
2512 XSync(xDisplay, False);
2515 frameWaiting = True;
2516 signal(SIGALRM, FrameAlarm);
2517 delay.it_interval.tv_sec =
2518 delay.it_value.tv_sec = time / 1000;
2519 delay.it_interval.tv_usec =
2520 delay.it_value.tv_usec = (time % 1000) * 1000;
2521 setitimer(ITIMER_REAL, &delay, NULL);
2522 while (frameWaiting) pause();
2523 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2524 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2525 setitimer(ITIMER_REAL, &delay, NULL);
2532 FrameDelay (int time)
2534 XSync(xDisplay, False);
2536 usleep(time * 1000);
2542 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2544 char buf[MSG_SIZ], *logoName = buf;
2545 if(appData.logo[n][0]) {
2546 logoName = appData.logo[n];
2547 } else if(appData.autoLogo) {
2548 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2549 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2550 } else if(appData.directory[n] && appData.directory[n][0]) {
2551 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2555 { ASSIGN(cps->programLogo, logoName); }
2559 UpdateLogos (int displ)
2561 if(optList[W_WHITE-1].handle == NULL) return;
2562 LoadLogo(&first, 0, 0);
2563 LoadLogo(&second, 1, appData.icsActive);
2564 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);