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);
1697 if(item) gtk_widget_set_sensitive(item->handle, state);
1701 EnableButtonBar (int state)
1704 XtSetSensitive(optList[W_BUTTON].handle, state);
1710 SetMenuEnables (Enables *enab)
1712 while (enab->name != NULL) {
1713 EnableNamedMenuItem(enab->name, enab->value);
1720 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1721 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1723 if(*nprms == 0) return;
1724 item = MenuNameToItem(prms[0]);
1725 if(item) ((MenuProc *) item->proc) ();
1731 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1733 RecentEngineEvent((int) (intptr_t) addr);
1738 AppendMenuItem (char *msg, int n)
1741 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1755 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1756 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1757 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1758 dmEnables[i].piece);
1759 XtSetSensitive(entry, p != NULL || !appData.testLegality
1760 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1761 && !appData.icsActive));
1763 while (p && *p++ == dmEnables[i].piece) count++;
1764 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1766 XtSetArg(args[j], XtNlabel, label); j++;
1767 XtSetValues(entry, args, j);
1773 do_flash_delay (unsigned long msec)
1779 FlashDelay (int flash_delay)
1782 XSync(xDisplay, False);
1783 if(flash_delay) do_flash_delay(flash_delay);
1788 Fraction (int x, int start, int stop)
1790 double f = ((double) x - start)/(stop - start);
1791 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1795 static WindowPlacement wpNew;
1799 CoDrag (Widget sh, WindowPlacement *wp)
1802 int j=0, touch=0, fudge = 2;
1803 GetActualPlacement(sh, wp);
1804 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1805 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1806 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1807 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1808 if(!touch ) return; // only windows that touch co-move
1809 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1810 int heightInc = wpNew.height - wpMain.height;
1811 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1812 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1813 wp->y += fracTop * heightInc;
1814 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1815 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1816 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1817 int widthInc = wpNew.width - wpMain.width;
1818 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1819 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1820 wp->y += fracLeft * widthInc;
1821 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1822 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1824 wp->x += wpNew.x - wpMain.x;
1825 wp->y += wpNew.y - wpMain.y;
1826 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1827 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1829 XtSetArg(args[j], XtNx, wp->x); j++;
1830 XtSetArg(args[j], XtNy, wp->y); j++;
1831 XtSetValues(sh, args, j);
1836 ReSize (WindowPlacement *wp)
1839 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1840 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1841 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1842 if(sqy < sqx) sqx = sqy;
1843 if(sqx != squareSize) {
1844 squareSize = sqx; // adopt new square size
1845 CreatePNGPieces(); // make newly scaled pieces
1846 InitDrawingSizes(0, 0); // creates grid etc.
1847 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1848 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1849 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1850 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1851 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1855 static XtIntervalId delayedDragID = 0;
1857 static int delayedDragID = 0;
1867 GetActualPlacement(shellWidget, &wpNew);
1868 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1869 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1870 busy = 0; return; // false alarm
1873 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1874 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1875 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1876 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1878 DrawPosition(True, NULL);
1879 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1888 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1890 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1895 EventProc (Widget widget, caddr_t unused, XEvent *event)
1898 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1899 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1904 * event handler for redrawing the board
1907 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1909 DrawPosition(True, NULL);
1915 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1916 { // [HGM] pv: walk PV
1917 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1921 static int savedIndex; /* gross that this is global */
1924 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1928 XawTextPosition index, dummy;
1931 XawTextGetSelectionPos(w, &index, &dummy);
1932 XtSetArg(arg, XtNstring, &val);
1933 XtGetValues(w, &arg, 1);
1934 ReplaceComment(savedIndex, val);
1935 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1936 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1941 EditCommentPopUp (int index, char *title, char *text)
1944 if (text == NULL) text = "";
1945 NewCommentPopup(title, text, index);
1949 CommentPopUp (char *title, char *text)
1951 savedIndex = currentMove; // [HGM] vari
1952 NewCommentPopup(title, text, currentMove);
1958 PopDown(CommentDlg);
1962 /* Disable all user input other than deleting the window */
1963 static int frozen = 0;
1969 /* Grab by a widget that doesn't accept input */
1970 XtAddGrab(optList[W_MESSG].handle, TRUE, FALSE);
1974 /* Undo a FreezeUI */
1978 if (!frozen) return;
1980 XtRemoveGrab(optList[W_MESSG].handle);
1988 static int oldPausing = FALSE;
1989 static GameMode oldmode = (GameMode) -1;
1994 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1996 if (pausing != oldPausing) {
1997 oldPausing = pausing;
1998 MarkMenuItem("Mode.Pause", pausing);
2000 if (appData.showButtonBar) {
2001 /* Always toggle, don't set. Previous code messes up when
2002 invoked while the button is pressed, as releasing it
2003 toggles the state again. */
2006 XtSetArg(args[0], XtNbackground, &oldbg);
2007 XtSetArg(args[1], XtNforeground, &oldfg);
2008 XtGetValues(optList[W_PAUSE].handle,
2010 XtSetArg(args[0], XtNbackground, oldfg);
2011 XtSetArg(args[1], XtNforeground, oldbg);
2013 XtSetValues(optList[W_PAUSE].handle, args, 2);
2018 wname = ModeToWidgetName(oldmode);
2019 if (wname != NULL) {
2020 MarkMenuItem(wname, False);
2022 wname = ModeToWidgetName(gameMode);
2023 if (wname != NULL) {
2024 MarkMenuItem(wname, True);
2027 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
2029 /* Maybe all the enables should be handled here, not just this one */
2030 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
2032 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
2037 * Button/menu procedures
2041 /* this variable is shared between CopyPositionProc and SendPositionSelection */
2042 char *selected_fen_position=NULL;
2045 SendPositionSelection (Widget w, Atom *selection, Atom *target,
2046 Atom *type_return, XtPointer *value_return,
2047 unsigned long *length_return, int *format_return)
2049 char *selection_tmp;
2051 // if (!selected_fen_position) return False; /* should never happen */
2052 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
2053 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
2054 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
2057 if (f == NULL) return False;
2061 selection_tmp = XtMalloc(len + 1);
2062 count = fread(selection_tmp, 1, len, f);
2065 XtFree(selection_tmp);
2068 selection_tmp[len] = NULLCHAR;
2070 /* note: since no XtSelectionDoneProc was registered, Xt will
2071 * automatically call XtFree on the value returned. So have to
2072 * make a copy of it allocated with XtMalloc */
2073 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
2074 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
2077 *value_return=selection_tmp;
2078 *length_return=strlen(selection_tmp);
2079 *type_return=*target;
2080 *format_return = 8; /* bits per byte */
2082 } else if (*target == XA_TARGETS(xDisplay)) {
2083 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
2084 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
2085 targets_tmp[1] = XA_STRING;
2086 *value_return = targets_tmp;
2087 *type_return = XA_ATOM;
2090 // This code leads to a read of value_return out of bounds on 64-bit systems.
2091 // Other code which I have seen always sets *format_return to 32 independent of
2092 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
2093 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
2094 *format_return = 8 * sizeof(Atom);
2095 if (*format_return > 32) {
2096 *length_return *= *format_return / 32;
2097 *format_return = 32;
2100 *format_return = 32;
2109 /* note: when called from menu all parameters are NULL, so no clue what the
2110 * Widget which was clicked on was, or what the click event was
2113 CopySomething (char *src)
2116 selected_fen_position = src;
2118 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
2119 * have a notion of a position that is selected but not copied.
2120 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
2122 XtOwnSelection(menuBarWidget, XA_PRIMARY,
2124 SendPositionSelection,
2125 NULL/* lose_ownership_proc */ ,
2126 NULL/* transfer_done_proc */);
2127 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2129 SendPositionSelection,
2130 NULL/* lose_ownership_proc */ ,
2131 NULL/* transfer_done_proc */);
2136 /* function called when the data to Paste is ready */
2138 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2139 Atom *type, XtPointer value, unsigned long *len, int *format)
2142 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2143 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2144 EditPositionPasteFEN(fenstr);
2149 /* called when Paste Position button is pressed,
2150 * all parameters will be NULL */
2152 PastePositionProc ()
2155 XtGetSelectionValue(menuBarWidget,
2156 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2157 /* (XtSelectionCallbackProc) */ PastePositionCB,
2158 NULL, /* client_data passed to PastePositionCB */
2160 /* better to use the time field from the event that triggered the
2161 * call to this function, but that isn't trivial to get
2170 /* note: when called from menu all parameters are NULL, so no clue what the
2171 * Widget which was clicked on was, or what the click event was
2173 /* function called when the data to Paste is ready */
2175 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2176 Atom *type, XtPointer value, unsigned long *len, int *format)
2179 if (value == NULL || *len == 0) {
2180 return; /* nothing had been selected to copy */
2182 f = fopen(gamePasteFilename, "w");
2184 DisplayError(_("Can't open temp file"), errno);
2187 fwrite(value, 1, *len, f);
2190 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2194 /* called when Paste Game button is pressed,
2195 * all parameters will be NULL */
2200 XtGetSelectionValue(menuBarWidget,
2201 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2202 /* (XtSelectionCallbackProc) */ PasteGameCB,
2203 NULL, /* client_data passed to PasteGameCB */
2205 /* better to use the time field from the event that triggered the
2206 * call to this function, but that isn't trivial to get
2216 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2223 { // bassic primitive for determining if modifier keys are pressed
2226 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2228 XQueryKeymap(xDisplay,keys);
2229 for(i=0; i<6; i++) {
2231 j = XKeysymToKeycode(xDisplay, codes[i]);
2232 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2239 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2244 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2245 if ( n == 1 && *buf >= 32 // printable
2246 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2247 ) BoxAutoPopUp (buf);
2253 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2254 { // [HGM] input: let up-arrow recall previous line from history
2259 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2260 { // [HGM] input: let down-arrow recall next line from history
2265 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2272 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2274 if (!TempBackwardActive) {
2275 TempBackwardActive = True;
2281 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2283 /* Check to see if triggered by a key release event for a repeating key.
2284 * If so the next queued event will be a key press of the same key at the same time */
2285 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2287 XPeekEvent(xDisplay, &next);
2288 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2289 next.xkey.keycode == event->xkey.keycode)
2293 TempBackwardActive = False;
2297 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2298 { // called as key binding
2301 if (nprms && *nprms > 0)
2305 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2312 { // called from menu
2314 ManInner(NULL, NULL, NULL, NULL);
2319 SetWindowTitle (char *text, char *title, char *icon)
2324 if (appData.titleInWindow) {
2326 XtSetArg(args[i], XtNlabel, text); i++;
2327 XtSetValues(titleWidget, args, i);
2330 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2331 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2332 XtSetValues(shellWidget, args, i);
2333 XSync(xDisplay, False);
2339 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2345 DisplayIcsInteractionTitle (String message)
2348 if (oldICSInteractionTitle == NULL) {
2349 /* Magic to find the old window title, adapted from vim */
2350 char *wina = getenv("WINDOWID");
2352 Window win = (Window) atoi(wina);
2353 Window root, parent, *children;
2354 unsigned int nchildren;
2355 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2357 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2358 if (!XQueryTree(xDisplay, win, &root, &parent,
2359 &children, &nchildren)) break;
2360 if (children) XFree((void *)children);
2361 if (parent == root || parent == 0) break;
2364 XSetErrorHandler(oldHandler);
2366 if (oldICSInteractionTitle == NULL) {
2367 oldICSInteractionTitle = "xterm";
2370 printf("\033]0;%s\007", message);
2377 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2382 Widget w = (Widget) opt->handle;
2384 /* check for low time warning */
2385 Pixel foregroundOrWarningColor = timerForegroundPixel;
2388 appData.lowTimeWarning &&
2389 (timer / 1000) < appData.icsAlarmTime)
2390 foregroundOrWarningColor = lowTimeWarningColor;
2392 if (appData.clockMode) {
2393 snprintf(buf, MSG_SIZ, "%s:%s%s", color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2394 XtSetArg(args[0], XtNlabel, buf);
2396 snprintf(buf, MSG_SIZ, "%s ", color);
2397 XtSetArg(args[0], XtNlabel, buf);
2402 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
2403 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
2405 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
2406 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
2409 XtSetValues(w, args, 3);
2414 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2418 SetClockIcon (int color)
2422 Pixmap pm = *clockIcons[color];
2423 if (iconPixmap != pm) {
2425 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2426 XtSetValues(shellWidget, args, 1);
2433 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
2435 InputSource *is = (InputSource *) closure;
2440 if (is->lineByLine) {
2441 count = read(is->fd, is->unused,
2442 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2444 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2447 is->unused += count;
2449 while (p < is->unused) {
2450 q = memchr(p, '\n', is->unused - p);
2451 if (q == NULL) break;
2453 (is->func)(is, is->closure, p, q - p, 0);
2457 while (p < is->unused) {
2462 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2467 (is->func)(is, is->closure, is->buf, count, error);
2473 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
2477 ChildProc *cp = (ChildProc *) pr;
2479 is = (InputSource *) calloc(1, sizeof(InputSource));
2480 is->lineByLine = lineByLine;
2484 is->fd = fileno(stdin);
2486 is->kind = cp->kind;
2487 is->fd = cp->fdFrom;
2490 is->unused = is->buf;
2493 is->xid = XtAppAddInput(appContext, is->fd,
2494 (XtPointer) (XtInputReadMask),
2495 (XtInputCallbackProc) DoInputCallback,
2497 is->closure = closure;
2498 return (InputSourceRef) is;
2500 return (InputSourceRef) 0;
2505 RemoveInputSource (InputSourceRef isr)
2508 InputSource *is = (InputSource *) isr;
2510 if (is->xid == 0) return;
2511 XtRemoveInput(is->xid);
2518 static Boolean frameWaiting;
2521 FrameAlarm (int sig)
2523 frameWaiting = False;
2524 /* In case System-V style signals. Needed?? */
2525 signal(SIGALRM, FrameAlarm);
2529 FrameDelay (int time)
2532 struct itimerval delay;
2534 XSync(xDisplay, False);
2537 frameWaiting = True;
2538 signal(SIGALRM, FrameAlarm);
2539 delay.it_interval.tv_sec =
2540 delay.it_value.tv_sec = time / 1000;
2541 delay.it_interval.tv_usec =
2542 delay.it_value.tv_usec = (time % 1000) * 1000;
2543 setitimer(ITIMER_REAL, &delay, NULL);
2544 while (frameWaiting) pause();
2545 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2546 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2547 setitimer(ITIMER_REAL, &delay, NULL);
2555 FrameDelay (int time)
2558 XSync(xDisplay, False);
2561 usleep(time * 1000);
2567 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2569 char buf[MSG_SIZ], *logoName = buf;
2570 if(appData.logo[n][0]) {
2571 logoName = appData.logo[n];
2572 } else if(appData.autoLogo) {
2573 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2574 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2575 } else if(appData.directory[n] && appData.directory[n][0]) {
2576 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2580 { ASSIGN(cps->programLogo, logoName); }
2584 UpdateLogos (int displ)
2586 if(optList[W_WHITE-1].handle == NULL) return;
2587 LoadLogo(&first, 0, 0);
2588 LoadLogo(&second, 1, appData.icsActive);
2589 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);