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>
69 # if HAVE_SYS_SOCKET_H
70 # include <sys/socket.h>
71 # include <netinet/in.h>
73 # else /* not HAVE_SYS_SOCKET_H */
74 # if HAVE_LAN_SOCKET_H
75 # include <lan/socket.h>
77 # include <lan/netdb.h>
78 # else /* not HAVE_LAN_SOCKET_H */
79 # define OMIT_SOCKETS 1
80 # endif /* not HAVE_LAN_SOCKET_H */
81 # endif /* not HAVE_SYS_SOCKET_H */
82 #endif /* !OMIT_SOCKETS */
87 #else /* not STDC_HEADERS */
88 extern char *getenv();
91 # else /* not HAVE_STRING_H */
93 # endif /* not HAVE_STRING_H */
94 #endif /* not STDC_HEADERS */
97 # include <sys/fcntl.h>
98 #else /* not HAVE_SYS_FCNTL_H */
101 # endif /* HAVE_FCNTL_H */
102 #endif /* not HAVE_SYS_FCNTL_H */
104 #if HAVE_SYS_SYSTEMINFO_H
105 # include <sys/systeminfo.h>
106 #endif /* HAVE_SYS_SYSTEMINFO_H */
108 #if TIME_WITH_SYS_TIME
109 # include <sys/time.h>
113 # include <sys/time.h>
124 # include <sys/wait.h>
129 # define NAMLEN(dirent) strlen((dirent)->d_name)
130 # define HAVE_DIR_STRUCT
132 # define dirent direct
133 # define NAMLEN(dirent) (dirent)->d_namlen
135 # include <sys/ndir.h>
136 # define HAVE_DIR_STRUCT
139 # include <sys/dir.h>
140 # define HAVE_DIR_STRUCT
144 # define HAVE_DIR_STRUCT
152 #include <X11/Intrinsic.h>
153 #include <X11/StringDefs.h>
154 #include <X11/Shell.h>
155 #include <X11/cursorfont.h>
156 #include <X11/Xatom.h>
157 #include <X11/Xmu/Atoms.h>
159 #include <X11/Xaw3d/Dialog.h>
160 #include <X11/Xaw3d/Form.h>
161 #include <X11/Xaw3d/List.h>
162 #include <X11/Xaw3d/Label.h>
163 #include <X11/Xaw3d/SimpleMenu.h>
164 #include <X11/Xaw3d/SmeBSB.h>
165 #include <X11/Xaw3d/SmeLine.h>
166 #include <X11/Xaw3d/Box.h>
167 #include <X11/Xaw3d/MenuButton.h>
168 #include <X11/Xaw3d/Text.h>
169 #include <X11/Xaw3d/AsciiText.h>
171 #include <X11/Xaw/Dialog.h>
172 #include <X11/Xaw/Form.h>
173 #include <X11/Xaw/List.h>
174 #include <X11/Xaw/Label.h>
175 #include <X11/Xaw/SimpleMenu.h>
176 #include <X11/Xaw/SmeBSB.h>
177 #include <X11/Xaw/SmeLine.h>
178 #include <X11/Xaw/Box.h>
179 #include <X11/Xaw/MenuButton.h>
180 #include <X11/Xaw/Text.h>
181 #include <X11/Xaw/AsciiText.h>
184 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
189 #define IMAGE_EXT "xpm"
191 #define IMAGE_EXT "xim"
194 #include "bitmaps/icon_white.bm"
195 #include "bitmaps/icon_black.bm"
196 #include "bitmaps/checkmark.bm"
198 #include "frontend.h"
200 #include "backendz.h"
205 #include "xgamelist.h"
206 #include "xhistory.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;
279 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
280 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
281 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
283 XFontSet fontSet, clockFontSet;
286 XFontStruct *clockFontStruct;
288 Font coordFontID, countFontID;
289 XFontStruct *coordFontStruct, *countFontStruct;
290 XtAppContext appContext;
292 void *shellWidget, *formWidget, *boardWidget, *titleWidget, *dropMenu, *menuBarWidget;
294 GtkWidget *mainwindow;
296 Option *optList; // contains all widgets of main window
299 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
301 Position commentX = -1, commentY = -1;
302 Dimension commentW, commentH;
303 typedef unsigned int BoardSize;
305 Boolean chessProgram;
307 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
308 int smallLayout = 0, tinyLayout = 0,
309 marginW, marginH, // [HGM] for run-time resizing
310 fromX = -1, fromY = -1, toX, toY, commentUp = False,
311 errorExitStatus = -1, defaultLineGap;
312 Dimension textHeight;
313 Pixel timerForegroundPixel, timerBackgroundPixel;
314 Pixel buttonForegroundPixel, buttonBackgroundPixel;
315 char *chessDir, *programName, *programVersion;
316 Boolean alwaysOnTop = False;
317 char *icsTextMenuString;
319 char *firstChessProgramNames;
320 char *secondChessProgramNames;
322 WindowPlacement wpMain;
323 WindowPlacement wpConsole;
324 WindowPlacement wpComment;
325 WindowPlacement wpMoveHistory;
326 WindowPlacement wpEvalGraph;
327 WindowPlacement wpEngineOutput;
328 WindowPlacement wpGameList;
329 WindowPlacement wpTags;
331 #define INPUT_SOURCE_BUF_SIZE 8192
340 char buf[INPUT_SOURCE_BUF_SIZE];
345 /* This magic number is the number of intermediate frames used
346 in each half of the animation. For short moves it's reduced
347 by 1. The total number of frames will be factor * 2 + 1. */
350 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
357 DropMenuEnables dmEnables[] = {
375 XtResource clientResources[] = {
376 { "flashCount", "flashCount", XtRInt, sizeof(int),
377 XtOffset(AppDataPtr, flashCount), XtRImmediate,
378 (XtPointer) FLASH_COUNT },
381 XrmOptionDescRec shellOptions[] = {
382 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
383 { "-flash", "flashCount", XrmoptionNoArg, "3" },
384 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
387 XtActionsRec boardActions[] = {
388 { "DrawPosition", DrawPositionProc },
389 { "HandlePV", HandlePV },
390 { "SelectPV", SelectPV },
391 { "StopPV", StopPV },
392 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
393 { "QuitProc", QuitWrapper },
394 { "ManProc", ManInner },
395 { "TempBackwardProc", TempBackwardProc },
396 { "TempForwardProc", TempForwardProc },
397 { "CommentClick", (XtActionProc) CommentClick },
398 { "GenericPopDown", (XtActionProc) GenericPopDown },
399 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
400 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
401 { "SelectMove", (XtActionProc) SelectMove },
402 { "LoadSelectedProc", LoadSelectedProc },
403 { "SetFilterProc", SetFilterProc },
404 { "TypeInProc", TypeInProc },
405 { "EnterKeyProc", EnterKeyProc },
406 { "UpKeyProc", UpKeyProc },
407 { "DownKeyProc", DownKeyProc },
408 { "WheelProc", WheelProc },
409 { "TabProc", TabProc },
413 char globalTranslations[] =
414 ":<Key>F9: MenuItem(Actions.Resign) \n \
415 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
416 :Meta<Key>V: MenuItem(File.NewVariant) \n \
417 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
418 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
419 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
420 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
421 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
422 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
423 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
424 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
425 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
426 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
427 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
428 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
429 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
430 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
431 :Ctrl<Key>q: MenuItem(File.Quit) \n \
432 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
433 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
434 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
435 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
436 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
437 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
438 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
439 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
440 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
441 :Meta<Key>G: MenuItem(View.GameList) \n \
442 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
443 :<Key>Pause: MenuItem(Mode.Pause) \n \
444 :<Key>F3: MenuItem(Action.Accept) \n \
445 :<Key>F4: MenuItem(Action.Decline) \n \
446 :<Key>F12: MenuItem(Action.Rematch) \n \
447 :<Key>F5: MenuItem(Action.CallFlag) \n \
448 :<Key>F6: MenuItem(Action.Draw) \n \
449 :<Key>F7: MenuItem(Action.Adjourn) \n \
450 :<Key>F8: MenuItem(Action.Abort) \n \
451 :<Key>F10: MenuItem(Action.StopObserving) \n \
452 :<Key>F11: MenuItem(Action.StopExamining) \n \
453 :Ctrl<Key>d: MenuItem(DebugProc) \n \
454 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
455 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
456 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
457 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
458 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
459 :<Key>Left: MenuItem(Edit.Backward) \n \
460 :<Key>Right: MenuItem(Edit.Forward) \n \
461 :<Key>Home: MenuItem(Edit.Revert) \n \
462 :<Key>End: MenuItem(Edit.TruncateGame) \n \
463 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
464 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
465 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
466 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
467 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
468 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
469 #ifndef OPTIONSDIALOG
471 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
472 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
473 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
474 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
475 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
478 :<Key>F1: MenuItem(Help.ManXBoard) \n \
479 :<Key>F2: MenuItem(View.FlipView) \n \
480 :<KeyDown>Return: TempBackwardProc() \n \
481 :<KeyUp>Return: TempForwardProc() \n";
483 char ICSInputTranslations[] =
484 "<Key>Up: UpKeyProc() \n "
485 "<Key>Down: DownKeyProc() \n "
486 "<Key>Return: EnterKeyProc() \n";
488 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
489 // as the widget is destroyed before the up-click can call extend-end
490 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
493 String xboardResources[] = {
494 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
499 /* Max possible square size */
500 #define MAXSQSIZE 256
502 static int xpm_avail[MAXSQSIZE];
504 #ifdef HAVE_DIR_STRUCT
506 /* Extract piece size from filename */
508 xpm_getsize (char *name, int len, char *ext)
516 if ((p=strchr(name, '.')) == NULL ||
517 StrCaseCmp(p+1, ext) != 0)
523 while (*p && isdigit(*p))
530 /* Setup xpm_avail */
532 xpm_getavail (char *dirname, char *ext)
538 for (i=0; i<MAXSQSIZE; ++i)
541 if (appData.debugMode)
542 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
544 dir = opendir(dirname);
547 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
548 programName, dirname);
552 while ((ent=readdir(dir)) != NULL) {
553 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
554 if (i > 0 && i < MAXSQSIZE)
564 xpm_print_avail (FILE *fp, char *ext)
568 fprintf(fp, _("Available `%s' sizes:\n"), ext);
569 for (i=1; i<MAXSQSIZE; ++i) {
575 /* Return XPM piecesize closest to size */
577 xpm_closest_to (char *dirname, int size, char *ext)
580 int sm_diff = MAXSQSIZE;
584 xpm_getavail(dirname, ext);
586 if (appData.debugMode)
587 xpm_print_avail(stderr, ext);
589 for (i=1; i<MAXSQSIZE; ++i) {
592 diff = (diff<0) ? -diff : diff;
593 if (diff < sm_diff) {
601 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
607 #else /* !HAVE_DIR_STRUCT */
608 /* If we are on a system without a DIR struct, we can't
609 read the directory, so we can't collect a list of
610 filenames, etc., so we can't do any size-fitting. */
612 xpm_closest_to (char *dirname, int size, char *ext)
615 Warning: No DIR structure found on this system --\n\
616 Unable to autosize for XPM/XIM pieces.\n\
617 Please report this error to %s.\n\
618 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
621 #endif /* HAVE_DIR_STRUCT */
625 /* Arrange to catch delete-window events */
626 Atom wm_delete_window;
628 CatchDeleteWindow (Widget w, String procname)
631 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
632 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
633 XtAugmentTranslations(w, XtParseTranslationTable(buf));
640 gtk_window_present(GTK_WINDOW(mainwindow));
643 //---------------------------------------------------------------------------------------------------------
644 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
647 #define CW_USEDEFAULT (1<<31)
648 #define ICS_TEXT_MENU_SIZE 90
649 #define DEBUG_FILE "xboard.debug"
650 #define SetCurrentDirectory chdir
651 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
655 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
658 // front-end part of option handling
660 // [HGM] This platform-dependent table provides the location for storing the color info
661 extern char *crWhite, * crBlack;
665 &appData.whitePieceColor,
666 &appData.blackPieceColor,
667 &appData.lightSquareColor,
668 &appData.darkSquareColor,
669 &appData.highlightSquareColor,
670 &appData.premoveHighlightColor,
671 &appData.lowTimeWarningColor,
682 // [HGM] font: keep a font for each square size, even non-stndard ones
685 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
686 char *fontTable[NUM_FONTS][MAX_SIZE];
689 ParseFont (char *name, int number)
690 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
692 if(sscanf(name, "size%d:", &size)) {
693 // [HGM] font: font is meant for specific boardSize (likely from settings file);
694 // defer processing it until we know if it matches our board size
695 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
696 fontTable[number][size] = strdup(strchr(name, ':')+1);
697 fontValid[number][size] = True;
702 case 0: // CLOCK_FONT
703 appData.clockFont = strdup(name);
705 case 1: // MESSAGE_FONT
706 appData.font = strdup(name);
708 case 2: // COORD_FONT
709 appData.coordFont = strdup(name);
714 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
719 { // only 2 fonts currently
720 appData.clockFont = CLOCK_FONT_NAME;
721 appData.coordFont = COORD_FONT_NAME;
722 appData.font = DEFAULT_FONT_NAME;
727 { // no-op, until we identify the code for this already in XBoard and move it here
731 ParseColor (int n, char *name)
732 { // in XBoard, just copy the color-name string
733 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
737 ParseTextAttribs (ColorClass cc, char *s)
739 (&appData.colorShout)[cc] = strdup(s);
743 ParseBoardSize (void *addr, char *name)
745 appData.boardSize = strdup(name);
750 { // In XBoard the sound-playing program takes care of obtaining the actual sound
754 SetCommPortDefaults ()
755 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
758 // [HGM] args: these three cases taken out to stay in front-end
760 SaveFontArg (FILE *f, ArgDescriptor *ad)
763 int i, n = (int)(intptr_t)ad->argLoc;
765 case 0: // CLOCK_FONT
766 name = appData.clockFont;
768 case 1: // MESSAGE_FONT
771 case 2: // COORD_FONT
772 name = appData.coordFont;
777 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
778 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
779 fontTable[n][squareSize] = strdup(name);
780 fontValid[n][squareSize] = True;
783 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
784 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
789 { // nothing to do, as the sounds are at all times represented by their text-string names already
793 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
794 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
795 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
799 SaveColor (FILE *f, ArgDescriptor *ad)
800 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
801 if(colorVariable[(int)(intptr_t)ad->argLoc])
802 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
806 SaveBoardSize (FILE *f, char *name, void *addr)
807 { // wrapper to shield back-end from BoardSize & sizeInfo
808 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
812 ParseCommPortSettings (char *s)
813 { // no such option in XBoard (yet)
820 GetActualPlacement (Widget wg, WindowPlacement *wp)
822 XWindowAttributes winAt;
829 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
830 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
831 wp->x = rx - winAt.x;
832 wp->y = ry - winAt.y;
833 wp->height = winAt.height;
834 wp->width = winAt.width;
835 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
841 { // wrapper to shield use of window handles from back-end (make addressible by number?)
842 // In XBoard this will have to wait until awareness of window parameters is implemented
844 GetActualPlacement(shellWidget, &wpMain);
845 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
846 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
847 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
848 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
849 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
850 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
855 PrintCommPortSettings (FILE *f, char *name)
856 { // This option does not exist in XBoard
860 EnsureOnScreen (int *x, int *y, int minX, int minY)
867 { // [HGM] args: allows testing if main window is realized from back-end
869 return xBoardWindow != 0;
876 PopUpStartupDialog ()
877 { // start menu not implemented in XBoard
881 ConvertToLine (int argc, char **argv)
883 static char line[128*1024], buf[1024];
887 for(i=1; i<argc; i++)
889 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
890 && argv[i][0] != '{' )
891 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
893 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
894 strncat(line, buf, 128*1024 - strlen(line) - 1 );
897 line[strlen(line)-1] = NULLCHAR;
901 //--------------------------------------------------------------------------------------------
904 ResizeBoardWindow (int w, int h, int inhibit)
907 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
909 shellArgs[0].value = w;
910 shellArgs[1].value = h;
911 shellArgs[4].value = shellArgs[2].value = w;
912 shellArgs[5].value = shellArgs[3].value = h;
913 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
915 XSync(xDisplay, False);
921 MakeOneColor (char *name, Pixel *color)
924 if (!appData.monoMode) {
925 vFrom.addr = (caddr_t) name;
926 vFrom.size = strlen(name);
927 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
928 if (vTo.addr == NULL) {
929 appData.monoMode = True;
932 *color = *(Pixel *) vTo.addr;
941 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
942 int forceMono = False;
945 if (appData.lowTimeWarning)
946 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
947 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
948 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
955 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
956 { // detervtomine what fonts to use, and create them
961 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
962 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
963 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
964 appData.font = fontTable[MESSAGE_FONT][squareSize];
965 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
966 appData.coordFont = fontTable[COORD_FONT][squareSize];
969 appData.font = InsertPxlSize(appData.font, fontPxlSize);
970 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
971 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
972 fontSet = CreateFontSet(appData.font);
973 clockFontSet = CreateFontSet(appData.clockFont);
975 /* For the coordFont, use the 0th font of the fontset. */
976 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
977 XFontStruct **font_struct_list;
978 XFontSetExtents *fontSize;
979 char **font_name_list;
980 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
981 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
982 coordFontStruct = XQueryFont(xDisplay, coordFontID);
983 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
984 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
987 appData.font = FindFont(appData.font, fontPxlSize);
988 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
989 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
990 clockFontID = XLoadFont(xDisplay, appData.clockFont);
991 clockFontStruct = XQueryFont(xDisplay, clockFontID);
992 coordFontID = XLoadFont(xDisplay, appData.coordFont);
993 coordFontStruct = XQueryFont(xDisplay, coordFontID);
994 // textHeight in !NLS mode!
996 countFontID = coordFontID; // [HGM] holdings
997 countFontStruct = coordFontStruct;
999 xdb = XtDatabase(xDisplay);
1001 XrmPutLineResource(&xdb, "*international: True");
1002 vTo.size = sizeof(XFontSet);
1003 vTo.addr = (XtPointer) &fontSet;
1004 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
1006 XrmPutStringResource(&xdb, "*font", appData.font);
1012 PrintArg (ArgType t)
1017 case ArgInt: p = " N"; break;
1018 case ArgString: p = " STR"; break;
1019 case ArgBoolean: p = " TF"; break;
1020 case ArgSettingsFilename:
1021 case ArgFilename: p = " FILE"; break;
1022 case ArgX: p = " Nx"; break;
1023 case ArgY: p = " Ny"; break;
1024 case ArgAttribs: p = " TEXTCOL"; break;
1025 case ArgColor: p = " COL"; break;
1026 case ArgFont: p = " FONT"; break;
1027 case ArgBoardSize: p = " SIZE"; break;
1028 case ArgFloat: p = " FLOAT"; break;
1033 case ArgCommSettings:
1044 ArgDescriptor *q, *p = argDescriptors+5;
1045 printf("\nXBoard accepts the following options:\n"
1046 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1047 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1048 " SIZE = board-size spec(s)\n"
1049 " Within parentheses are short forms, or options to set to true or false.\n"
1050 " Persistent options (saved in the settings file) are marked with *)\n\n");
1052 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1053 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1054 if(p->save) strcat(buf+len, "*");
1055 for(q=p+1; q->argLoc == p->argLoc; q++) {
1056 if(q->argName[0] == '-') continue;
1057 strcat(buf+len, q == p+1 ? " (" : " ");
1058 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1060 if(q != p+1) strcat(buf+len, ")");
1062 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1065 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1069 main (int argc, char **argv)
1071 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1073 XSetWindowAttributes window_attributes;
1077 Dimension boardWidth, boardHeight, w, h;
1079 int forceMono = False;
1080 GError *gtkerror=NULL;
1082 srandom(time(0)); // [HGM] book: make random truly random
1084 setbuf(stdout, NULL);
1085 setbuf(stderr, NULL);
1088 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1089 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1093 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1099 gtk_init (&argc, &argv);
1101 programName = strrchr(argv[0], '/');
1102 if (programName == NULL)
1103 programName = argv[0];
1108 // if (appData.debugMode) {
1109 // fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1112 bindtextdomain(PACKAGE, LOCALEDIR);
1113 textdomain(PACKAGE);
1116 appData.boardSize = "";
1117 InitAppData(ConvertToLine(argc, argv));
1119 if (p == NULL) p = "/tmp";
1120 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1121 gameCopyFilename = (char*) malloc(i);
1122 gamePasteFilename = (char*) malloc(i);
1123 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1124 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1126 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1127 static char buf[MSG_SIZ];
1128 EscapeExpand(buf, appData.firstInitString);
1129 appData.firstInitString = strdup(buf);
1130 EscapeExpand(buf, appData.secondInitString);
1131 appData.secondInitString = strdup(buf);
1132 EscapeExpand(buf, appData.firstComputerString);
1133 appData.firstComputerString = strdup(buf);
1134 EscapeExpand(buf, appData.secondComputerString);
1135 appData.secondComputerString = strdup(buf);
1138 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1141 if (chdir(chessDir) != 0) {
1142 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1148 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1149 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1150 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1151 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1154 setbuf(debugFP, NULL);
1158 if (appData.debugMode) {
1159 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1163 /* [HGM,HR] make sure board size is acceptable */
1164 if(appData.NrFiles > BOARD_FILES ||
1165 appData.NrRanks > BOARD_RANKS )
1166 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1169 /* This feature does not work; animation needs a rewrite */
1170 appData.highlightDragging = FALSE;
1174 gameInfo.variant = StringToVariant(appData.variant);
1175 InitPosition(FALSE);
1179 builder = gtk_builder_new();
1180 filename = get_glade_filename ("mainboard.glade");
1181 if(! gtk_builder_add_from_file (builder, filename, >kerror) )
1184 printf ("Error: %d %s\n",gtkerror->code,gtkerror->message);
1186 mainwindow = GTK_WIDGET(gtk_builder_get_object (builder, "mainwindow"));
1189 XtAppInitialize(&appContext, "XBoard", shellOptions,
1190 XtNumber(shellOptions),
1191 &argc, argv, xboardResources, NULL, 0);
1193 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1194 clientResources, XtNumber(clientResources),
1197 xDisplay = XtDisplay(shellWidget);
1198 xScreen = DefaultScreen(xDisplay);
1199 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1203 * determine size, based on supplied or remembered -size, or screen size
1205 if (isdigit(appData.boardSize[0])) {
1206 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1207 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1208 &fontPxlSize, &smallLayout, &tinyLayout);
1210 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1211 programName, appData.boardSize);
1215 /* Find some defaults; use the nearest known size */
1216 SizeDefaults *szd, *nearest;
1217 int distance = 99999;
1218 nearest = szd = sizeDefaults;
1219 while (szd->name != NULL) {
1220 if (abs(szd->squareSize - squareSize) < distance) {
1222 distance = abs(szd->squareSize - squareSize);
1223 if (distance == 0) break;
1227 if (i < 2) lineGap = nearest->lineGap;
1228 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1229 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1230 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1231 if (i < 6) smallLayout = nearest->smallLayout;
1232 if (i < 7) tinyLayout = nearest->tinyLayout;
1235 SizeDefaults *szd = sizeDefaults;
1236 if (*appData.boardSize == NULLCHAR) {
1238 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1239 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1243 GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(mainwindow));
1244 guint screenwidth = gdk_screen_get_width(screen);
1245 guint screenheight = gdk_screen_get_height(screen);
1246 while (screenwidth < szd->minScreenSize ||
1247 screenheight < szd->minScreenSize) {
1251 if (szd->name == NULL) szd--;
1252 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1254 while (szd->name != NULL &&
1255 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1256 if (szd->name == NULL) {
1257 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1258 programName, appData.boardSize);
1262 squareSize = szd->squareSize;
1263 lineGap = szd->lineGap;
1264 clockFontPxlSize = szd->clockFontPxlSize;
1265 coordFontPxlSize = szd->coordFontPxlSize;
1266 fontPxlSize = szd->fontPxlSize;
1267 smallLayout = szd->smallLayout;
1268 tinyLayout = szd->tinyLayout;
1269 // [HGM] font: use defaults from settings file if available and not overruled
1272 defaultLineGap = lineGap;
1273 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1275 /* [HR] height treated separately (hacked) */
1276 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1277 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1280 * Determine what fonts to use.
1283 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1287 * Detect if there are not enough colors available and adapt.
1290 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1291 appData.monoMode = True;
1295 forceMono = MakeColors();
1298 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1300 appData.monoMode = True;
1303 if (appData.monoMode && appData.debugMode) {
1305 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1306 (unsigned long) XWhitePixel(xDisplay, xScreen),
1307 (unsigned long) XBlackPixel(xDisplay, xScreen));
1311 ParseIcsTextColors();
1314 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1321 layoutName = "tinyLayout";
1322 } else if (smallLayout) {
1323 layoutName = "smallLayout";
1325 layoutName = "normalLayout";
1328 optList = BoardPopUp(squareSize, lineGap, (void*)
1338 InitDrawingHandle(optList + W_BOARD);
1339 currBoard = &optList[W_BOARD];
1340 boardWidget = optList[W_BOARD].handle;
1341 menuBarWidget = optList[W_MENU].handle;
1342 dropMenu = optList[W_DROP].handle;
1343 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1344 formWidget = XtParent(boardWidget);
1346 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1347 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1348 XtGetValues(optList[W_WHITE].handle, args, 2);
1349 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1350 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1351 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1352 XtGetValues(optList[W_PAUSE].handle, args, 2);
1355 AppendEnginesToMenu(appData.recentEngineList);
1358 xBoardWindow = XtWindow(boardWidget);
1361 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1362 // not need to go into InitDrawingSizes().
1365 * Create X checkmark bitmap and initialize option menu checks.
1368 ReadBitmap(&xMarkPixmap, "checkmark.bm",
1369 checkmark_bits, checkmark_width, checkmark_height);
1377 ReadBitmap(&wIconPixmap, "icon_white.bm",
1378 icon_white_bits, icon_white_width, icon_white_height);
1379 ReadBitmap(&bIconPixmap, "icon_black.bm",
1380 icon_black_bits, icon_black_width, icon_black_height);
1381 iconPixmap = wIconPixmap;
1383 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1384 XtSetValues(shellWidget, args, i);
1388 * Create a cursor for the board widget.
1391 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1392 XChangeWindowAttributes(xDisplay, xBoardWindow,
1393 CWCursor, &window_attributes);
1397 * Inhibit shell resizing.
1400 shellArgs[0].value = (XtArgVal) &w;
1401 shellArgs[1].value = (XtArgVal) &h;
1402 XtGetValues(shellWidget, shellArgs, 2);
1403 shellArgs[4].value = shellArgs[2].value = w;
1404 shellArgs[5].value = shellArgs[3].value = h;
1405 // XtSetValues(shellWidget, &shellArgs[2], 4);
1407 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1408 marginH = h - boardHeight;
1411 CatchDeleteWindow(shellWidget, "QuitProc");
1417 if(appData.logoSize)
1418 { // locate and read user logo
1420 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1421 ASSIGN(userLogo, buf);
1424 if (appData.animate || appData.animateDragging)
1428 XtAugmentTranslations(formWidget,
1429 XtParseTranslationTable(globalTranslations));
1431 XtAddEventHandler(formWidget, KeyPressMask, False,
1432 (XtEventHandler) MoveTypeInProc, NULL);
1433 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1434 (XtEventHandler) EventProc, NULL);
1437 /* [AS] Restore layout */
1438 if( wpMoveHistory.visible ) {
1442 if( wpEvalGraph.visible )
1447 if( wpEngineOutput.visible ) {
1448 EngineOutputPopUp();
1453 if (errorExitStatus == -1) {
1454 if (appData.icsActive) {
1455 /* We now wait until we see "login:" from the ICS before
1456 sending the logon script (problems with timestamp otherwise) */
1457 /*ICSInitScript();*/
1458 if (appData.icsInputBox) ICSInputBoxPopUp();
1462 signal(SIGWINCH, TermSizeSigHandler);
1464 signal(SIGINT, IntSigHandler);
1465 signal(SIGTERM, IntSigHandler);
1466 if (*appData.cmailGameName != NULLCHAR) {
1467 signal(SIGUSR1, CmailSigHandler);
1471 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1474 // XtSetKeyboardFocus(shellWidget, formWidget);
1476 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1479 /* check for GTK events and process them */
1482 if (appData.debugMode) fclose(debugFP); // [DM] debug
1487 TermSizeSigHandler (int sig)
1493 IntSigHandler (int sig)
1499 CmailSigHandler (int sig)
1504 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1506 /* Activate call-back function CmailSigHandlerCallBack() */
1507 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1509 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1513 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1516 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1518 /**** end signal code ****/
1521 #define Abs(n) ((n)<0 ? -(n) : (n))
1525 InsertPxlSize (char *pattern, int targetPxlSize)
1527 char *base_fnt_lst, strInt[12], *p, *q;
1528 int alternatives, i, len, strIntLen;
1531 * Replace the "*" (if present) in the pixel-size slot of each
1532 * alternative with the targetPxlSize.
1536 while ((p = strchr(p, ',')) != NULL) {
1540 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1541 strIntLen = strlen(strInt);
1542 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1546 while (alternatives--) {
1547 char *comma = strchr(p, ',');
1548 for (i=0; i<14; i++) {
1549 char *hyphen = strchr(p, '-');
1551 if (comma && hyphen > comma) break;
1552 len = hyphen + 1 - p;
1553 if (i == 7 && *p == '*' && len == 2) {
1555 memcpy(q, strInt, strIntLen);
1565 len = comma + 1 - p;
1572 return base_fnt_lst;
1577 CreateFontSet (char *base_fnt_lst)
1580 char **missing_list;
1584 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1585 &missing_list, &missing_count, &def_string);
1586 if (appData.debugMode) {
1588 XFontStruct **font_struct_list;
1589 char **font_name_list;
1590 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1592 fprintf(debugFP, " got list %s, locale %s\n",
1593 XBaseFontNameListOfFontSet(fntSet),
1594 XLocaleOfFontSet(fntSet));
1595 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1596 for (i = 0; i < count; i++) {
1597 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1600 for (i = 0; i < missing_count; i++) {
1601 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1604 if (fntSet == NULL) {
1605 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1611 #else // not ENABLE_NLS
1613 * Find a font that matches "pattern" that is as close as
1614 * possible to the targetPxlSize. Prefer fonts that are k
1615 * pixels smaller to fonts that are k pixels larger. The
1616 * pattern must be in the X Consortium standard format,
1617 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1618 * The return value should be freed with XtFree when no
1622 FindFont (char *pattern, int targetPxlSize)
1624 char **fonts, *p, *best, *scalable, *scalableTail;
1625 int i, j, nfonts, minerr, err, pxlSize;
1628 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1630 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1631 programName, pattern);
1638 for (i=0; i<nfonts; i++) {
1641 if (*p != '-') continue;
1643 if (*p == NULLCHAR) break;
1644 if (*p++ == '-') j++;
1646 if (j < 7) continue;
1649 scalable = fonts[i];
1652 err = pxlSize - targetPxlSize;
1653 if (Abs(err) < Abs(minerr) ||
1654 (minerr > 0 && err < 0 && -err == minerr)) {
1660 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1661 /* If the error is too big and there is a scalable font,
1662 use the scalable font. */
1663 int headlen = scalableTail - scalable;
1664 p = (char *) XtMalloc(strlen(scalable) + 10);
1665 while (isdigit(*scalableTail)) scalableTail++;
1666 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1668 p = (char *) XtMalloc(strlen(best) + 2);
1669 safeStrCpy(p, best, strlen(best)+1 );
1671 if (appData.debugMode) {
1672 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1673 pattern, targetPxlSize, p);
1675 XFreeFontNames(fonts);
1682 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
1686 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
1693 EnableNamedMenuItem (char *menuRef, int state)
1695 MenuItem *item = MenuNameToItem(menuRef);
1698 if(item) XtSetSensitive(item->handle, state);
1703 EnableButtonBar (int state)
1706 XtSetSensitive(optList[W_BUTTON].handle, state);
1712 SetMenuEnables (Enables *enab)
1714 while (enab->name != NULL) {
1715 EnableNamedMenuItem(enab->name, enab->value);
1722 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1723 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1725 if(*nprms == 0) return;
1726 item = MenuNameToItem(prms[0]);
1727 if(item) ((MenuProc *) item->proc) ();
1733 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1735 RecentEngineEvent((int) (intptr_t) addr);
1740 AppendMenuItem (char *msg, int n)
1743 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1757 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1758 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1759 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1760 dmEnables[i].piece);
1761 XtSetSensitive(entry, p != NULL || !appData.testLegality
1762 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1763 && !appData.icsActive));
1765 while (p && *p++ == dmEnables[i].piece) count++;
1766 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1768 XtSetArg(args[j], XtNlabel, label); j++;
1769 XtSetValues(entry, args, j);
1775 do_flash_delay (unsigned long msec)
1781 FlashDelay (int flash_delay)
1784 XSync(xDisplay, False);
1785 if(flash_delay) do_flash_delay(flash_delay);
1790 Fraction (int x, int start, int stop)
1792 double f = ((double) x - start)/(stop - start);
1793 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1797 static WindowPlacement wpNew;
1801 CoDrag (Widget sh, WindowPlacement *wp)
1804 int j=0, touch=0, fudge = 2;
1805 GetActualPlacement(sh, wp);
1806 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1807 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1808 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1809 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1810 if(!touch ) return; // only windows that touch co-move
1811 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1812 int heightInc = wpNew.height - wpMain.height;
1813 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1814 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1815 wp->y += fracTop * heightInc;
1816 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1817 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1818 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1819 int widthInc = wpNew.width - wpMain.width;
1820 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1821 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1822 wp->y += fracLeft * widthInc;
1823 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1824 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1826 wp->x += wpNew.x - wpMain.x;
1827 wp->y += wpNew.y - wpMain.y;
1828 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1829 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1831 XtSetArg(args[j], XtNx, wp->x); j++;
1832 XtSetArg(args[j], XtNy, wp->y); j++;
1833 XtSetValues(sh, args, j);
1838 ReSize (WindowPlacement *wp)
1841 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1842 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1843 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1844 if(sqy < sqx) sqx = sqy;
1845 if(sqx != squareSize) {
1846 squareSize = sqx; // adopt new square size
1847 CreatePNGPieces(); // make newly scaled pieces
1848 InitDrawingSizes(0, 0); // creates grid etc.
1849 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1850 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1851 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1852 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1853 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1857 static XtIntervalId delayedDragID = 0;
1859 static int delayedDragID = 0;
1869 GetActualPlacement(shellWidget, &wpNew);
1870 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1871 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1872 busy = 0; return; // false alarm
1875 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1876 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1877 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1878 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1880 DrawPosition(True, NULL);
1881 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1890 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1892 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1897 EventProc (Widget widget, caddr_t unused, XEvent *event)
1900 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1901 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1906 * event handler for redrawing the board
1909 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1911 DrawPosition(True, NULL);
1917 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1918 { // [HGM] pv: walk PV
1919 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1923 static int savedIndex; /* gross that this is global */
1926 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1930 XawTextPosition index, dummy;
1933 XawTextGetSelectionPos(w, &index, &dummy);
1934 XtSetArg(arg, XtNstring, &val);
1935 XtGetValues(w, &arg, 1);
1936 ReplaceComment(savedIndex, val);
1937 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1938 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1943 EditCommentPopUp (int index, char *title, char *text)
1946 if (text == NULL) text = "";
1947 NewCommentPopup(title, text, index);
1951 CommentPopUp (char *title, char *text)
1953 savedIndex = currentMove; // [HGM] vari
1954 NewCommentPopup(title, text, currentMove);
1960 PopDown(CommentDlg);
1964 /* Disable all user input other than deleting the window */
1965 static int frozen = 0;
1971 /* Grab by a widget that doesn't accept input */
1972 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1976 /* Undo a FreezeUI */
1980 if (!frozen) return;
1982 XtRemoveGrab(optList[W_MESSG].handle);
1990 static int oldPausing = FALSE;
1991 static GameMode oldmode = (GameMode) -1;
1996 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1998 if (pausing != oldPausing) {
1999 oldPausing = pausing;
2000 MarkMenuItem("Mode.Pause", pausing);
2002 if (appData.showButtonBar) {
2003 /* Always toggle, don't set. Previous code messes up when
2004 invoked while the button is pressed, as releasing it
2005 toggles the state again. */
2008 XtSetArg(args[0], XtNbackground, &oldbg);
2009 XtSetArg(args[1], XtNforeground, &oldfg);
2010 XtGetValues(optList[W_PAUSE].handle,
2012 XtSetArg(args[0], XtNbackground, oldfg);
2013 XtSetArg(args[1], XtNforeground, oldbg);
2015 XtSetValues(optList[W_PAUSE].handle, args, 2);
2020 wname = ModeToWidgetName(oldmode);
2021 if (wname != NULL) {
2022 MarkMenuItem(wname, False);
2024 wname = ModeToWidgetName(gameMode);
2025 if (wname != NULL) {
2026 MarkMenuItem(wname, True);
2029 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
2031 /* Maybe all the enables should be handled here, not just this one */
2032 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
2034 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
2039 * Button/menu procedures
2043 /* this variable is shared between CopyPositionProc and SendPositionSelection */
2044 char *selected_fen_position=NULL;
2047 SendPositionSelection (Widget w, Atom *selection, Atom *target,
2048 Atom *type_return, XtPointer *value_return,
2049 unsigned long *length_return, int *format_return)
2051 char *selection_tmp;
2053 // if (!selected_fen_position) return False; /* should never happen */
2054 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
2055 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
2056 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
2059 if (f == NULL) return False;
2063 selection_tmp = XtMalloc(len + 1);
2064 count = fread(selection_tmp, 1, len, f);
2067 XtFree(selection_tmp);
2070 selection_tmp[len] = NULLCHAR;
2072 /* note: since no XtSelectionDoneProc was registered, Xt will
2073 * automatically call XtFree on the value returned. So have to
2074 * make a copy of it allocated with XtMalloc */
2075 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
2076 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
2079 *value_return=selection_tmp;
2080 *length_return=strlen(selection_tmp);
2081 *type_return=*target;
2082 *format_return = 8; /* bits per byte */
2084 } else if (*target == XA_TARGETS(xDisplay)) {
2085 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
2086 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
2087 targets_tmp[1] = XA_STRING;
2088 *value_return = targets_tmp;
2089 *type_return = XA_ATOM;
2092 // This code leads to a read of value_return out of bounds on 64-bit systems.
2093 // Other code which I have seen always sets *format_return to 32 independent of
2094 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
2095 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
2096 *format_return = 8 * sizeof(Atom);
2097 if (*format_return > 32) {
2098 *length_return *= *format_return / 32;
2099 *format_return = 32;
2102 *format_return = 32;
2111 /* note: when called from menu all parameters are NULL, so no clue what the
2112 * Widget which was clicked on was, or what the click event was
2115 CopySomething (char *src)
2118 selected_fen_position = src;
2120 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
2121 * have a notion of a position that is selected but not copied.
2122 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
2124 XtOwnSelection(menuBarWidget, XA_PRIMARY,
2126 SendPositionSelection,
2127 NULL/* lose_ownership_proc */ ,
2128 NULL/* transfer_done_proc */);
2129 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2131 SendPositionSelection,
2132 NULL/* lose_ownership_proc */ ,
2133 NULL/* transfer_done_proc */);
2138 /* function called when the data to Paste is ready */
2140 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2141 Atom *type, XtPointer value, unsigned long *len, int *format)
2144 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2145 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2146 EditPositionPasteFEN(fenstr);
2151 /* called when Paste Position button is pressed,
2152 * all parameters will be NULL */
2154 PastePositionProc ()
2157 XtGetSelectionValue(menuBarWidget,
2158 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2159 /* (XtSelectionCallbackProc) */ PastePositionCB,
2160 NULL, /* client_data passed to PastePositionCB */
2162 /* better to use the time field from the event that triggered the
2163 * call to this function, but that isn't trivial to get
2172 /* note: when called from menu all parameters are NULL, so no clue what the
2173 * Widget which was clicked on was, or what the click event was
2175 /* function called when the data to Paste is ready */
2177 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2178 Atom *type, XtPointer value, unsigned long *len, int *format)
2181 if (value == NULL || *len == 0) {
2182 return; /* nothing had been selected to copy */
2184 f = fopen(gamePasteFilename, "w");
2186 DisplayError(_("Can't open temp file"), errno);
2189 fwrite(value, 1, *len, f);
2192 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2196 /* called when Paste Game button is pressed,
2197 * all parameters will be NULL */
2202 XtGetSelectionValue(menuBarWidget,
2203 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2204 /* (XtSelectionCallbackProc) */ PasteGameCB,
2205 NULL, /* client_data passed to PasteGameCB */
2207 /* better to use the time field from the event that triggered the
2208 * call to this function, but that isn't trivial to get
2218 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2225 { // bassic primitive for determining if modifier keys are pressed
2228 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2230 XQueryKeymap(xDisplay,keys);
2231 for(i=0; i<6; i++) {
2233 j = XKeysymToKeycode(xDisplay, codes[i]);
2234 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2241 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2246 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2247 if ( n == 1 && *buf >= 32 // printable
2248 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2249 ) BoxAutoPopUp (buf);
2255 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2256 { // [HGM] input: let up-arrow recall previous line from history
2261 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2262 { // [HGM] input: let down-arrow recall next line from history
2267 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2274 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2276 if (!TempBackwardActive) {
2277 TempBackwardActive = True;
2283 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2285 /* Check to see if triggered by a key release event for a repeating key.
2286 * If so the next queued event will be a key press of the same key at the same time */
2287 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2289 XPeekEvent(xDisplay, &next);
2290 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2291 next.xkey.keycode == event->xkey.keycode)
2295 TempBackwardActive = False;
2299 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2300 { // called as key binding
2303 if (nprms && *nprms > 0)
2307 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2314 { // called from menu
2316 ManInner(NULL, NULL, NULL, NULL);
2321 SetWindowTitle (char *text, char *title, char *icon)
2326 if (appData.titleInWindow) {
2328 XtSetArg(args[i], XtNlabel, text); i++;
2329 XtSetValues(titleWidget, args, i);
2332 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2333 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2334 XtSetValues(shellWidget, args, i);
2335 XSync(xDisplay, False);
2341 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2347 DisplayIcsInteractionTitle (String message)
2350 if (oldICSInteractionTitle == NULL) {
2351 /* Magic to find the old window title, adapted from vim */
2352 char *wina = getenv("WINDOWID");
2354 Window win = (Window) atoi(wina);
2355 Window root, parent, *children;
2356 unsigned int nchildren;
2357 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2359 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2360 if (!XQueryTree(xDisplay, win, &root, &parent,
2361 &children, &nchildren)) break;
2362 if (children) XFree((void *)children);
2363 if (parent == root || parent == 0) break;
2366 XSetErrorHandler(oldHandler);
2368 if (oldICSInteractionTitle == NULL) {
2369 oldICSInteractionTitle = "xterm";
2372 printf("\033]0;%s\007", message);
2379 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2384 Widget w = (Widget) opt->handle;
2386 /* check for low time warning */
2387 Pixel foregroundOrWarningColor = timerForegroundPixel;
2390 appData.lowTimeWarning &&
2391 (timer / 1000) < appData.icsAlarmTime)
2392 foregroundOrWarningColor = lowTimeWarningColor;
2394 if (appData.clockMode) {
2395 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2396 XtSetArg(args[0], XtNlabel, buf);
2398 snprintf(buf, MSG_SIZ, "%s ", color);
2399 XtSetArg(args[0], XtNlabel, buf);
2404 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2405 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2407 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2408 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2411 XtSetValues(w, args, 3);
2416 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2420 SetClockIcon (int color)
2424 Pixmap pm = *clockIcons[color];
2425 if (iconPixmap != pm) {
2427 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2428 XtSetValues(shellWidget, args, 1);
2435 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2437 InputSource *is = (InputSource *) closure;
2442 if (is->lineByLine) {
2443 count = read(is->fd, is->unused,
2444 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2446 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2449 is->unused += count;
2451 while (p < is->unused) {
2452 q = memchr(p, '\n', is->unused - p);
2453 if (q == NULL) break;
2455 (is->func)(is, is->closure, p, q - p, 0);
2459 while (p < is->unused) {
2464 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2469 (is->func)(is, is->closure, is->buf, count, error);
2475 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2479 ChildProc *cp = (ChildProc *) pr;
2481 is = (InputSource *) calloc(1, sizeof(InputSource));
2482 is->lineByLine = lineByLine;
2486 is->fd = fileno(stdin);
2488 is->kind = cp->kind;
2489 is->fd = cp->fdFrom;
2492 is->unused = is->buf;
2495 is->xid = XtAppAddInput(appContext, is->fd,
2496 (XtPointer) (XtInputReadMask),
2497 (XtInputCallbackProc) DoInputCallback,
2499 is->closure = closure;
2500 return (InputSourceRef) is;
2502 return (InputSourceRef) 0;
2507 RemoveInputSource (InputSourceRef isr)
2510 InputSource *is = (InputSource *) isr;
2512 if (is->xid == 0) return;
2513 XtRemoveInput(is->xid);
2520 static Boolean frameWaiting;
2523 FrameAlarm (int sig)
2525 frameWaiting = False;
2526 /* In case System-V style signals. Needed?? */
2527 signal(SIGALRM, FrameAlarm);
2531 FrameDelay (int time)
2534 struct itimerval delay;
2536 XSync(xDisplay, False);
2539 frameWaiting = True;
2540 signal(SIGALRM, FrameAlarm);
2541 delay.it_interval.tv_sec =
2542 delay.it_value.tv_sec = time / 1000;
2543 delay.it_interval.tv_usec =
2544 delay.it_value.tv_usec = (time % 1000) * 1000;
2545 setitimer(ITIMER_REAL, &delay, NULL);
2546 while (frameWaiting) pause();
2547 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2548 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2549 setitimer(ITIMER_REAL, &delay, NULL);
2557 FrameDelay (int time)
2560 XSync(xDisplay, False);
2563 usleep(time * 1000);
2569 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2571 char buf[MSG_SIZ], *logoName = buf;
2572 if(appData.logo[n][0]) {
2573 logoName = appData.logo[n];
2574 } else if(appData.autoLogo) {
2575 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2576 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2577 } else if(appData.directory[n] && appData.directory[n][0]) {
2578 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2582 { ASSIGN(cps->programLogo, logoName); }
2586 UpdateLogos (int displ)
2588 if(optList[W_WHITE-1].handle == NULL) return;
2589 LoadLogo(&first, 0, 0);
2590 LoadLogo(&second, 1, appData.icsActive);
2591 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);