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.
187 #include "frontend.h"
189 #include "backendz.h"
194 #include "xgamelist.h"
195 #include "xhistory.h"
199 #include "engineoutput.h"
209 #define usleep(t) _sleep2(((t)+500)/1000)
213 # define _(s) gettext (s)
214 # define N_(s) gettext_noop (s)
220 int main P((int argc, char **argv));
221 RETSIGTYPE CmailSigHandler P((int sig));
222 RETSIGTYPE IntSigHandler P((int sig));
223 RETSIGTYPE TermSizeSigHandler P((int sig));
224 Widget CreateMenuBar P((Menu *mb, int boardWidth));
226 char *InsertPxlSize P((char *pattern, int targetPxlSize));
227 XFontSet CreateFontSet P((char *base_fnt_lst));
229 char *FindFont P((char *pattern, int targetPxlSize));
231 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
232 void DelayedDrag P((void));
233 static void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
234 void HandlePV P((Widget w, XEvent * event,
235 String * params, Cardinal * nParams));
236 void DrawPositionProc P((Widget w, XEvent *event,
237 String *prms, Cardinal *nprms));
238 void CommentClick P((Widget w, XEvent * event,
239 String * params, Cardinal * nParams));
240 void ICSInputBoxPopUp P((void));
241 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
242 void KeyBindingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
243 void QuitWrapper P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
244 static void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
245 static void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
246 static void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
247 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
248 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
249 Boolean TempBackwardActive = False;
250 void ManInner P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
251 void DisplayMove P((int moveNumber));
252 void ICSInitScript P((void));
253 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
254 void update_ics_width P(());
255 int CopyMemoProc P(());
258 * XBoard depends on Xt R4 or higher
260 int xtVersion = XtSpecificationRelease;
266 Pixel lowTimeWarningColor, dialogColor, buttonColor; // used in widgets
267 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
268 Widget shellWidget, formWidget, boardWidget, titleWidget, dropMenu, menuBarWidget;
270 XFontSet fontSet, clockFontSet;
273 XFontStruct *clockFontStruct;
275 Font coordFontID, countFontID;
276 XFontStruct *coordFontStruct, *countFontStruct;
277 XtAppContext appContext;
279 void *shellWidget, *formWidget, *boardWidget, *titleWidget, *dropMenu, *menuBarWidget;
281 GtkWidget *mainwindow;
283 Option *optList; // contains all widgets of main window
286 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
288 Position commentX = -1, commentY = -1;
289 Dimension commentW, commentH;
290 typedef unsigned int BoardSize;
292 Boolean chessProgram;
294 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
295 int smallLayout = 0, tinyLayout = 0,
296 marginW, marginH, // [HGM] for run-time resizing
297 fromX = -1, fromY = -1, toX, toY, commentUp = False,
298 errorExitStatus = -1, defaultLineGap;
299 Dimension textHeight;
300 Pixel timerForegroundPixel, timerBackgroundPixel;
301 Pixel buttonForegroundPixel, buttonBackgroundPixel;
302 char *chessDir, *programName, *programVersion;
303 Boolean alwaysOnTop = False;
304 char *icsTextMenuString;
306 char *firstChessProgramNames;
307 char *secondChessProgramNames;
309 WindowPlacement wpMain;
310 WindowPlacement wpConsole;
311 WindowPlacement wpComment;
312 WindowPlacement wpMoveHistory;
313 WindowPlacement wpEvalGraph;
314 WindowPlacement wpEngineOutput;
315 WindowPlacement wpGameList;
316 WindowPlacement wpTags;
318 /* This magic number is the number of intermediate frames used
319 in each half of the animation. For short moves it's reduced
320 by 1. The total number of frames will be factor * 2 + 1. */
323 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
330 DropMenuEnables dmEnables[] = {
348 XtResource clientResources[] = {
349 { "flashCount", "flashCount", XtRInt, sizeof(int),
350 XtOffset(AppDataPtr, flashCount), XtRImmediate,
351 (XtPointer) FLASH_COUNT },
354 XrmOptionDescRec shellOptions[] = {
355 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
356 { "-flash", "flashCount", XrmoptionNoArg, "3" },
357 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
360 XtActionsRec boardActions[] = {
361 { "DrawPosition", DrawPositionProc },
362 { "HandlePV", HandlePV },
363 { "SelectPV", SelectPV },
364 { "StopPV", StopPV },
365 { "MenuItem", KeyBindingProc }, // [HGM] generic handler for key bindings
366 { "QuitProc", QuitWrapper },
367 { "ManProc", ManInner },
368 { "TempBackwardProc", TempBackwardProc },
369 { "TempForwardProc", TempForwardProc },
370 { "CommentClick", (XtActionProc) CommentClick },
371 { "GenericPopDown", (XtActionProc) GenericPopDown },
372 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
373 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
374 { "SelectMove", (XtActionProc) SelectMove },
375 { "LoadSelectedProc", LoadSelectedProc },
376 { "SetFilterProc", SetFilterProc },
377 { "TypeInProc", TypeInProc },
378 { "EnterKeyProc", EnterKeyProc },
379 { "UpKeyProc", UpKeyProc },
380 { "DownKeyProc", DownKeyProc },
381 { "WheelProc", WheelProc },
382 { "TabProc", TabProc },
386 char globalTranslations[] =
387 ":<Key>F9: MenuItem(Actions.Resign) \n \
388 :Ctrl<Key>n: MenuItem(File.NewGame) \n \
389 :Meta<Key>V: MenuItem(File.NewVariant) \n \
390 :Ctrl<Key>o: MenuItem(File.LoadGame) \n \
391 :Meta<Key>Next: MenuItem(LoadNextGameProc) \n \
392 :Meta<Key>Prior: MenuItem(LoadPrevGameProc) \n \
393 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
394 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
395 :Ctrl<Key>s: MenuItem(File.SaveGame) \n \
396 :Ctrl<Key>c: MenuItem(Edit.CopyGame) \n \
397 :Ctrl<Key>v: MenuItem(Edit.PasteGame) \n \
398 :Ctrl<Key>O: MenuItem(File.LoadPosition) \n \
399 :Shift<Key>Next: MenuItem(LoadNextPositionProc) \n \
400 :Shift<Key>Prior: MenuItem(LoadPrevPositionProc) \n \
401 :Ctrl<Key>S: MenuItem(File.SavePosition) \n \
402 :Ctrl<Key>C: MenuItem(Edit.CopyPosition) \n \
403 :Ctrl<Key>V: MenuItem(Edit.PastePosition) \n \
404 :Ctrl<Key>q: MenuItem(File.Quit) \n \
405 :Ctrl<Key>w: MenuItem(Mode.MachineWhite) \n \
406 :Ctrl<Key>b: MenuItem(Mode.MachineBlack) \n \
407 :Ctrl<Key>t: MenuItem(Mode.TwoMachines) \n \
408 :Ctrl<Key>a: MenuItem(Mode.AnalysisMode) \n \
409 :Ctrl<Key>g: MenuItem(Mode.AnalyzeFile) \n \
410 :Ctrl<Key>e: MenuItem(Mode.EditGame) \n \
411 :Ctrl<Key>E: MenuItem(Mode.EditPosition) \n \
412 :Meta<Key>O: MenuItem(View.EngineOutput) \n \
413 :Meta<Key>E: MenuItem(View.EvaluationGraph) \n \
414 :Meta<Key>G: MenuItem(View.GameList) \n \
415 :Meta<Key>H: MenuItem(View.MoveHistory) \n \
416 :<Key>Pause: MenuItem(Mode.Pause) \n \
417 :<Key>F3: MenuItem(Action.Accept) \n \
418 :<Key>F4: MenuItem(Action.Decline) \n \
419 :<Key>F12: MenuItem(Action.Rematch) \n \
420 :<Key>F5: MenuItem(Action.CallFlag) \n \
421 :<Key>F6: MenuItem(Action.Draw) \n \
422 :<Key>F7: MenuItem(Action.Adjourn) \n \
423 :<Key>F8: MenuItem(Action.Abort) \n \
424 :<Key>F10: MenuItem(Action.StopObserving) \n \
425 :<Key>F11: MenuItem(Action.StopExamining) \n \
426 :Ctrl<Key>d: MenuItem(DebugProc) \n \
427 :Meta Ctrl<Key>F12: MenuItem(DebugProc) \n \
428 :Meta<Key>End: MenuItem(Edit.ForwardtoEnd) \n \
429 :Meta<Key>Right: MenuItem(Edit.Forward) \n \
430 :Meta<Key>Home: MenuItem(Edit.BacktoStart) \n \
431 :Meta<Key>Left: MenuItem(Edit.Backward) \n \
432 :<Key>Left: MenuItem(Edit.Backward) \n \
433 :<Key>Right: MenuItem(Edit.Forward) \n \
434 :<Key>Home: MenuItem(Edit.Revert) \n \
435 :<Key>End: MenuItem(Edit.TruncateGame) \n \
436 :Ctrl<Key>m: MenuItem(Engine.MoveNow) \n \
437 :Ctrl<Key>x: MenuItem(Engine.RetractMove) \n \
438 :Meta<Key>J: MenuItem(Options.Adjudications) \n \
439 :Meta<Key>U: MenuItem(Options.CommonEngine) \n \
440 :Meta<Key>T: MenuItem(Options.TimeControl) \n \
441 :Ctrl<Key>P: MenuItem(PonderNextMove) \n "
442 #ifndef OPTIONSDIALOG
444 :Ctrl<Key>Q: MenuItem(AlwaysQueenProc) \n \
445 :Ctrl<Key>F: MenuItem(AutoflagProc) \n \
446 :Ctrl<Key>A: MenuItem(AnimateMovingProc) \n \
447 :Ctrl<Key>L: MenuItem(TestLegalityProc) \n \
448 :Ctrl<Key>H: MenuItem(HideThinkingProc) \n "
451 :<Key>F1: MenuItem(Help.ManXBoard) \n \
452 :<Key>F2: MenuItem(View.FlipView) \n \
453 :<KeyDown>Return: TempBackwardProc() \n \
454 :<KeyUp>Return: TempForwardProc() \n";
456 char ICSInputTranslations[] =
457 "<Key>Up: UpKeyProc() \n "
458 "<Key>Down: DownKeyProc() \n "
459 "<Key>Return: EnterKeyProc() \n";
461 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
462 // as the widget is destroyed before the up-click can call extend-end
463 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
466 String xboardResources[] = {
467 "*Error*translations: #override\\n <Key>Return: ErrorPopDown()",
472 /* Max possible square size */
473 #define MAXSQSIZE 256
475 static int xpm_avail[MAXSQSIZE];
477 #ifdef HAVE_DIR_STRUCT
479 /* Extract piece size from filename */
481 xpm_getsize (char *name, int len, char *ext)
489 if ((p=strchr(name, '.')) == NULL ||
490 StrCaseCmp(p+1, ext) != 0)
496 while (*p && isdigit(*p))
503 /* Setup xpm_avail */
505 xpm_getavail (char *dirname, char *ext)
511 for (i=0; i<MAXSQSIZE; ++i)
514 if (appData.debugMode)
515 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
517 dir = opendir(dirname);
520 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
521 programName, dirname);
525 while ((ent=readdir(dir)) != NULL) {
526 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
527 if (i > 0 && i < MAXSQSIZE)
537 xpm_print_avail (FILE *fp, char *ext)
541 fprintf(fp, _("Available `%s' sizes:\n"), ext);
542 for (i=1; i<MAXSQSIZE; ++i) {
548 /* Return XPM piecesize closest to size */
550 xpm_closest_to (char *dirname, int size, char *ext)
553 int sm_diff = MAXSQSIZE;
557 xpm_getavail(dirname, ext);
559 if (appData.debugMode)
560 xpm_print_avail(stderr, ext);
562 for (i=1; i<MAXSQSIZE; ++i) {
565 diff = (diff<0) ? -diff : diff;
566 if (diff < sm_diff) {
574 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
580 #else /* !HAVE_DIR_STRUCT */
581 /* If we are on a system without a DIR struct, we can't
582 read the directory, so we can't collect a list of
583 filenames, etc., so we can't do any size-fitting. */
585 xpm_closest_to (char *dirname, int size, char *ext)
588 Warning: No DIR structure found on this system --\n\
589 Unable to autosize for XPM/XIM pieces.\n\
590 Please report this error to %s.\n\
591 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
594 #endif /* HAVE_DIR_STRUCT */
598 /* Arrange to catch delete-window events */
599 Atom wm_delete_window;
601 CatchDeleteWindow (Widget w, String procname)
604 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
605 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
606 XtAugmentTranslations(w, XtParseTranslationTable(buf));
613 gtk_window_present(GTK_WINDOW(mainwindow));
616 //---------------------------------------------------------------------------------------------------------
617 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
620 #define CW_USEDEFAULT (1<<31)
621 #define ICS_TEXT_MENU_SIZE 90
622 #define DEBUG_FILE "xboard.debug"
623 #define SetCurrentDirectory chdir
624 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
628 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
631 // front-end part of option handling
633 // [HGM] This platform-dependent table provides the location for storing the color info
634 extern char *crWhite, * crBlack;
638 &appData.whitePieceColor,
639 &appData.blackPieceColor,
640 &appData.lightSquareColor,
641 &appData.darkSquareColor,
642 &appData.highlightSquareColor,
643 &appData.premoveHighlightColor,
644 &appData.lowTimeWarningColor,
655 // [HGM] font: keep a font for each square size, even non-stndard ones
658 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
659 char *fontTable[NUM_FONTS][MAX_SIZE];
662 ParseFont (char *name, int number)
663 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
665 if(sscanf(name, "size%d:", &size)) {
666 // [HGM] font: font is meant for specific boardSize (likely from settings file);
667 // defer processing it until we know if it matches our board size
668 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
669 fontTable[number][size] = strdup(strchr(name, ':')+1);
670 fontValid[number][size] = True;
675 case 0: // CLOCK_FONT
676 appData.clockFont = strdup(name);
678 case 1: // MESSAGE_FONT
679 appData.font = strdup(name);
681 case 2: // COORD_FONT
682 appData.coordFont = strdup(name);
687 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
692 { // only 2 fonts currently
693 appData.clockFont = CLOCK_FONT_NAME;
694 appData.coordFont = COORD_FONT_NAME;
695 appData.font = DEFAULT_FONT_NAME;
700 { // no-op, until we identify the code for this already in XBoard and move it here
704 ParseColor (int n, char *name)
705 { // in XBoard, just copy the color-name string
706 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
710 ParseTextAttribs (ColorClass cc, char *s)
712 (&appData.colorShout)[cc] = strdup(s);
716 ParseBoardSize (void *addr, char *name)
718 appData.boardSize = strdup(name);
723 { // In XBoard the sound-playing program takes care of obtaining the actual sound
727 SetCommPortDefaults ()
728 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
731 // [HGM] args: these three cases taken out to stay in front-end
733 SaveFontArg (FILE *f, ArgDescriptor *ad)
736 int i, n = (int)(intptr_t)ad->argLoc;
738 case 0: // CLOCK_FONT
739 name = appData.clockFont;
741 case 1: // MESSAGE_FONT
744 case 2: // COORD_FONT
745 name = appData.coordFont;
750 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
751 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
752 fontTable[n][squareSize] = strdup(name);
753 fontValid[n][squareSize] = True;
756 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
757 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
762 { // nothing to do, as the sounds are at all times represented by their text-string names already
766 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
767 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
768 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
772 SaveColor (FILE *f, ArgDescriptor *ad)
773 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
774 if(colorVariable[(int)(intptr_t)ad->argLoc])
775 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
779 SaveBoardSize (FILE *f, char *name, void *addr)
780 { // wrapper to shield back-end from BoardSize & sizeInfo
781 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
785 ParseCommPortSettings (char *s)
786 { // no such option in XBoard (yet)
793 GetActualPlacement (Widget wg, WindowPlacement *wp)
795 XWindowAttributes winAt;
802 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
803 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
804 wp->x = rx - winAt.x;
805 wp->y = ry - winAt.y;
806 wp->height = winAt.height;
807 wp->width = winAt.width;
808 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
814 { // wrapper to shield use of window handles from back-end (make addressible by number?)
815 // In XBoard this will have to wait until awareness of window parameters is implemented
817 GetActualPlacement(shellWidget, &wpMain);
818 if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
819 if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
820 if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
821 if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
822 if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
823 if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
828 PrintCommPortSettings (FILE *f, char *name)
829 { // This option does not exist in XBoard
833 EnsureOnScreen (int *x, int *y, int minX, int minY)
840 { // [HGM] args: allows testing if main window is realized from back-end
842 return xBoardWindow != 0;
849 PopUpStartupDialog ()
850 { // start menu not implemented in XBoard
854 ConvertToLine (int argc, char **argv)
856 static char line[128*1024], buf[1024];
860 for(i=1; i<argc; i++)
862 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
863 && argv[i][0] != '{' )
864 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
866 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
867 strncat(line, buf, 128*1024 - strlen(line) - 1 );
870 line[strlen(line)-1] = NULLCHAR;
874 //--------------------------------------------------------------------------------------------
877 ResizeBoardWindow (int w, int h, int inhibit)
880 w += marginW + 1; // [HGM] not sure why the +1 is (sometimes) needed...
882 shellArgs[0].value = w;
883 shellArgs[1].value = h;
884 shellArgs[4].value = shellArgs[2].value = w;
885 shellArgs[5].value = shellArgs[3].value = h;
886 XtSetValues(shellWidget, &shellArgs[0], inhibit ? 6 : 2);
888 XSync(xDisplay, False);
894 MakeOneColor (char *name, Pixel *color)
897 if (!appData.monoMode) {
898 vFrom.addr = (caddr_t) name;
899 vFrom.size = strlen(name);
900 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
901 if (vTo.addr == NULL) {
902 appData.monoMode = True;
905 *color = *(Pixel *) vTo.addr;
914 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
915 int forceMono = False;
918 if (appData.lowTimeWarning)
919 forceMono |= MakeOneColor(appData.lowTimeWarningColor, &lowTimeWarningColor);
920 if(appData.dialogColor[0]) MakeOneColor(appData.dialogColor, &dialogColor);
921 if(appData.buttonColor[0]) MakeOneColor(appData.buttonColor, &buttonColor);
928 InitializeFonts (int clockFontPxlSize, int coordFontPxlSize, int fontPxlSize)
929 { // detervtomine what fonts to use, and create them
934 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
935 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
936 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
937 appData.font = fontTable[MESSAGE_FONT][squareSize];
938 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
939 appData.coordFont = fontTable[COORD_FONT][squareSize];
942 appData.font = InsertPxlSize(appData.font, fontPxlSize);
943 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
944 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
945 fontSet = CreateFontSet(appData.font);
946 clockFontSet = CreateFontSet(appData.clockFont);
948 /* For the coordFont, use the 0th font of the fontset. */
949 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
950 XFontStruct **font_struct_list;
951 XFontSetExtents *fontSize;
952 char **font_name_list;
953 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
954 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
955 coordFontStruct = XQueryFont(xDisplay, coordFontID);
956 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
957 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
960 appData.font = FindFont(appData.font, fontPxlSize);
961 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
962 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
963 clockFontID = XLoadFont(xDisplay, appData.clockFont);
964 clockFontStruct = XQueryFont(xDisplay, clockFontID);
965 coordFontID = XLoadFont(xDisplay, appData.coordFont);
966 coordFontStruct = XQueryFont(xDisplay, coordFontID);
967 // textHeight in !NLS mode!
969 countFontID = coordFontID; // [HGM] holdings
970 countFontStruct = coordFontStruct;
972 xdb = XtDatabase(xDisplay);
974 XrmPutLineResource(&xdb, "*international: True");
975 vTo.size = sizeof(XFontSet);
976 vTo.addr = (XtPointer) &fontSet;
977 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
979 XrmPutStringResource(&xdb, "*font", appData.font);
990 case ArgInt: p = " N"; break;
991 case ArgString: p = " STR"; break;
992 case ArgBoolean: p = " TF"; break;
993 case ArgSettingsFilename:
994 case ArgFilename: p = " FILE"; break;
995 case ArgX: p = " Nx"; break;
996 case ArgY: p = " Ny"; break;
997 case ArgAttribs: p = " TEXTCOL"; break;
998 case ArgColor: p = " COL"; break;
999 case ArgFont: p = " FONT"; break;
1000 case ArgBoardSize: p = " SIZE"; break;
1001 case ArgFloat: p = " FLOAT"; break;
1006 case ArgCommSettings:
1017 ArgDescriptor *q, *p = argDescriptors+5;
1018 printf("\nXBoard accepts the following options:\n"
1019 "(N = integer, TF = true or false, STR = text string, FILE = filename,\n"
1020 " Nx, Ny = relative coordinates, COL = color, FONT = X-font spec,\n"
1021 " SIZE = board-size spec(s)\n"
1022 " Within parentheses are short forms, or options to set to true or false.\n"
1023 " Persistent options (saved in the settings file) are marked with *)\n\n");
1025 if(p->argType == ArgCommSettings) { p++; continue; } // XBoard has no comm port
1026 snprintf(buf+len, MSG_SIZ, "-%s%s", p->argName, PrintArg(p->argType));
1027 if(p->save) strcat(buf+len, "*");
1028 for(q=p+1; q->argLoc == p->argLoc; q++) {
1029 if(q->argName[0] == '-') continue;
1030 strcat(buf+len, q == p+1 ? " (" : " ");
1031 sprintf(buf+strlen(buf), "-%s%s", q->argName, PrintArg(q->argType));
1033 if(q != p+1) strcat(buf+len, ")");
1035 if(len > 39) len = 0, printf("%s\n", buf); else while(len < 39) buf[len++] = ' ';
1038 if(len) buf[len] = NULLCHAR, printf("%s\n", buf);
1042 main (int argc, char **argv)
1044 int i, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1046 XSetWindowAttributes window_attributes;
1050 Dimension boardWidth, boardHeight, w, h;
1052 int forceMono = False;
1053 GError *gtkerror=NULL;
1055 srandom(time(0)); // [HGM] book: make random truly random
1057 setbuf(stdout, NULL);
1058 setbuf(stderr, NULL);
1061 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1062 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1066 if(argc > 1 && !strcmp(argv[1], "--help" )) {
1072 gtk_init (&argc, &argv);
1074 programName = strrchr(argv[0], '/');
1075 if (programName == NULL)
1076 programName = argv[0];
1081 // if (appData.debugMode) {
1082 // fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1085 bindtextdomain(PACKAGE, LOCALEDIR);
1086 textdomain(PACKAGE);
1089 appData.boardSize = "";
1090 InitAppData(ConvertToLine(argc, argv));
1092 if (p == NULL) p = "/tmp";
1093 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1094 gameCopyFilename = (char*) malloc(i);
1095 gamePasteFilename = (char*) malloc(i);
1096 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1097 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1099 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1100 static char buf[MSG_SIZ];
1101 EscapeExpand(buf, appData.firstInitString);
1102 appData.firstInitString = strdup(buf);
1103 EscapeExpand(buf, appData.secondInitString);
1104 appData.secondInitString = strdup(buf);
1105 EscapeExpand(buf, appData.firstComputerString);
1106 appData.firstComputerString = strdup(buf);
1107 EscapeExpand(buf, appData.secondComputerString);
1108 appData.secondComputerString = strdup(buf);
1111 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1114 if (chdir(chessDir) != 0) {
1115 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1121 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1122 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1123 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1124 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1127 setbuf(debugFP, NULL);
1131 if (appData.debugMode) {
1132 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
1136 /* [HGM,HR] make sure board size is acceptable */
1137 if(appData.NrFiles > BOARD_FILES ||
1138 appData.NrRanks > BOARD_RANKS )
1139 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1142 /* This feature does not work; animation needs a rewrite */
1143 appData.highlightDragging = FALSE;
1147 gameInfo.variant = StringToVariant(appData.variant);
1148 InitPosition(FALSE);
1152 builder = gtk_builder_new();
1153 filename = get_glade_filename ("mainboard.glade");
1154 if(! gtk_builder_add_from_file (builder, filename, >kerror) )
1157 printf ("Error: %d %s\n",gtkerror->code,gtkerror->message);
1159 mainwindow = GTK_WIDGET(gtk_builder_get_object (builder, "mainwindow"));
1162 XtAppInitialize(&appContext, "XBoard", shellOptions,
1163 XtNumber(shellOptions),
1164 &argc, argv, xboardResources, NULL, 0);
1166 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1167 clientResources, XtNumber(clientResources),
1170 xDisplay = XtDisplay(shellWidget);
1171 xScreen = DefaultScreen(xDisplay);
1172 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1176 * determine size, based on supplied or remembered -size, or screen size
1178 if (isdigit(appData.boardSize[0])) {
1179 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1180 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1181 &fontPxlSize, &smallLayout, &tinyLayout);
1183 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1184 programName, appData.boardSize);
1188 /* Find some defaults; use the nearest known size */
1189 SizeDefaults *szd, *nearest;
1190 int distance = 99999;
1191 nearest = szd = sizeDefaults;
1192 while (szd->name != NULL) {
1193 if (abs(szd->squareSize - squareSize) < distance) {
1195 distance = abs(szd->squareSize - squareSize);
1196 if (distance == 0) break;
1200 if (i < 2) lineGap = nearest->lineGap;
1201 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1202 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1203 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1204 if (i < 6) smallLayout = nearest->smallLayout;
1205 if (i < 7) tinyLayout = nearest->tinyLayout;
1208 SizeDefaults *szd = sizeDefaults;
1209 if (*appData.boardSize == NULLCHAR) {
1211 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1212 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1216 GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(mainwindow));
1217 guint screenwidth = gdk_screen_get_width(screen);
1218 guint screenheight = gdk_screen_get_height(screen);
1219 while (screenwidth < szd->minScreenSize ||
1220 screenheight < szd->minScreenSize) {
1224 if (szd->name == NULL) szd--;
1225 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1227 while (szd->name != NULL &&
1228 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1229 if (szd->name == NULL) {
1230 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1231 programName, appData.boardSize);
1235 squareSize = szd->squareSize;
1236 lineGap = szd->lineGap;
1237 clockFontPxlSize = szd->clockFontPxlSize;
1238 coordFontPxlSize = szd->coordFontPxlSize;
1239 fontPxlSize = szd->fontPxlSize;
1240 smallLayout = szd->smallLayout;
1241 tinyLayout = szd->tinyLayout;
1242 // [HGM] font: use defaults from settings file if available and not overruled
1245 defaultLineGap = lineGap;
1246 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1248 /* [HR] height treated separately (hacked) */
1249 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1250 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1253 * Determine what fonts to use.
1256 InitializeFonts(clockFontPxlSize, coordFontPxlSize, fontPxlSize);
1260 * Detect if there are not enough colors available and adapt.
1263 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1264 appData.monoMode = True;
1268 forceMono = MakeColors();
1271 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1273 appData.monoMode = True;
1276 if (appData.monoMode && appData.debugMode) {
1278 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1279 (unsigned long) XWhitePixel(xDisplay, xScreen),
1280 (unsigned long) XBlackPixel(xDisplay, xScreen));
1284 ParseIcsTextColors();
1287 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1294 layoutName = "tinyLayout";
1295 } else if (smallLayout) {
1296 layoutName = "smallLayout";
1298 layoutName = "normalLayout";
1301 optList = BoardPopUp(squareSize, lineGap, (void*)
1311 InitDrawingHandle(optList + W_BOARD);
1312 currBoard = &optList[W_BOARD];
1313 boardWidget = optList[W_BOARD].handle;
1314 menuBarWidget = optList[W_MENU].handle;
1315 dropMenu = optList[W_DROP].handle;
1316 titleWidget = optList[optList[W_TITLE].type != -1 ? W_TITLE : W_SMALL].handle;
1318 formWidget = XtParent(boardWidget);
1319 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
1320 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
1321 XtGetValues(optList[W_WHITE].handle, args, 2);
1322 if (appData.showButtonBar) { // can't we use timer pixels for this? (Or better yet, just black & white?)
1323 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
1324 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
1325 XtGetValues(optList[W_PAUSE].handle, args, 2);
1328 AppendEnginesToMenu(appData.recentEngineList);
1331 xBoardWindow = XtWindow(boardWidget);
1334 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1335 // not need to go into InitDrawingSizes().
1343 ReadBitmap(&wIconPixmap, "icon_white.bm",
1344 icon_white_bits, icon_white_width, icon_white_height);
1345 ReadBitmap(&bIconPixmap, "icon_black.bm",
1346 icon_black_bits, icon_black_width, icon_black_height);
1347 iconPixmap = wIconPixmap;
1349 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1350 XtSetValues(shellWidget, args, i);
1354 * Create a cursor for the board widget.
1357 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1358 XChangeWindowAttributes(xDisplay, xBoardWindow,
1359 CWCursor, &window_attributes);
1363 * Inhibit shell resizing.
1366 shellArgs[0].value = (XtArgVal) &w;
1367 shellArgs[1].value = (XtArgVal) &h;
1368 XtGetValues(shellWidget, shellArgs, 2);
1369 shellArgs[4].value = shellArgs[2].value = w;
1370 shellArgs[5].value = shellArgs[3].value = h;
1371 // XtSetValues(shellWidget, &shellArgs[2], 4);
1373 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1374 marginH = h - boardHeight;
1377 CatchDeleteWindow(shellWidget, "QuitProc");
1383 if(appData.logoSize)
1384 { // locate and read user logo
1386 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1387 ASSIGN(userLogo, buf);
1390 if (appData.animate || appData.animateDragging)
1394 XtAugmentTranslations(formWidget,
1395 XtParseTranslationTable(globalTranslations));
1397 XtAddEventHandler(formWidget, KeyPressMask, False,
1398 (XtEventHandler) MoveTypeInProc, NULL);
1399 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1400 (XtEventHandler) EventProc, NULL);
1403 /* [AS] Restore layout */
1404 if( wpMoveHistory.visible ) {
1408 if( wpEvalGraph.visible )
1413 if( wpEngineOutput.visible ) {
1414 EngineOutputPopUp();
1419 if (errorExitStatus == -1) {
1420 if (appData.icsActive) {
1421 /* We now wait until we see "login:" from the ICS before
1422 sending the logon script (problems with timestamp otherwise) */
1423 /*ICSInitScript();*/
1424 if (appData.icsInputBox) ICSInputBoxPopUp();
1428 signal(SIGWINCH, TermSizeSigHandler);
1430 signal(SIGINT, IntSigHandler);
1431 signal(SIGTERM, IntSigHandler);
1432 if (*appData.cmailGameName != NULLCHAR) {
1433 signal(SIGUSR1, CmailSigHandler);
1437 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1440 // XtSetKeyboardFocus(shellWidget, formWidget);
1442 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1445 /* check for GTK events and process them */
1448 gtk_main_iteration();
1451 if (appData.debugMode) fclose(debugFP); // [DM] debug
1456 TermSizeSigHandler (int sig)
1462 IntSigHandler (int sig)
1468 CmailSigHandler (int sig)
1473 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1475 /* Activate call-back function CmailSigHandlerCallBack() */
1476 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1478 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1482 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1485 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1487 /**** end signal code ****/
1490 #define Abs(n) ((n)<0 ? -(n) : (n))
1494 InsertPxlSize (char *pattern, int targetPxlSize)
1496 char *base_fnt_lst, strInt[12], *p, *q;
1497 int alternatives, i, len, strIntLen;
1500 * Replace the "*" (if present) in the pixel-size slot of each
1501 * alternative with the targetPxlSize.
1505 while ((p = strchr(p, ',')) != NULL) {
1509 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1510 strIntLen = strlen(strInt);
1511 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1515 while (alternatives--) {
1516 char *comma = strchr(p, ',');
1517 for (i=0; i<14; i++) {
1518 char *hyphen = strchr(p, '-');
1520 if (comma && hyphen > comma) break;
1521 len = hyphen + 1 - p;
1522 if (i == 7 && *p == '*' && len == 2) {
1524 memcpy(q, strInt, strIntLen);
1534 len = comma + 1 - p;
1541 return base_fnt_lst;
1546 CreateFontSet (char *base_fnt_lst)
1549 char **missing_list;
1553 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1554 &missing_list, &missing_count, &def_string);
1555 if (appData.debugMode) {
1557 XFontStruct **font_struct_list;
1558 char **font_name_list;
1559 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1561 fprintf(debugFP, " got list %s, locale %s\n",
1562 XBaseFontNameListOfFontSet(fntSet),
1563 XLocaleOfFontSet(fntSet));
1564 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1565 for (i = 0; i < count; i++) {
1566 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1569 for (i = 0; i < missing_count; i++) {
1570 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1573 if (fntSet == NULL) {
1574 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1580 #else // not ENABLE_NLS
1582 * Find a font that matches "pattern" that is as close as
1583 * possible to the targetPxlSize. Prefer fonts that are k
1584 * pixels smaller to fonts that are k pixels larger. The
1585 * pattern must be in the X Consortium standard format,
1586 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1587 * The return value should be freed with XtFree when no
1591 FindFont (char *pattern, int targetPxlSize)
1593 char **fonts, *p, *best, *scalable, *scalableTail;
1594 int i, j, nfonts, minerr, err, pxlSize;
1597 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1599 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1600 programName, pattern);
1607 for (i=0; i<nfonts; i++) {
1610 if (*p != '-') continue;
1612 if (*p == NULLCHAR) break;
1613 if (*p++ == '-') j++;
1615 if (j < 7) continue;
1618 scalable = fonts[i];
1621 err = pxlSize - targetPxlSize;
1622 if (Abs(err) < Abs(minerr) ||
1623 (minerr > 0 && err < 0 && -err == minerr)) {
1629 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1630 /* If the error is too big and there is a scalable font,
1631 use the scalable font. */
1632 int headlen = scalableTail - scalable;
1633 p = (char *) XtMalloc(strlen(scalable) + 10);
1634 while (isdigit(*scalableTail)) scalableTail++;
1635 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1637 p = (char *) XtMalloc(strlen(best) + 2);
1638 safeStrCpy(p, best, strlen(best)+1 );
1640 if (appData.debugMode) {
1641 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1642 pattern, targetPxlSize, p);
1644 XFreeFontNames(fonts);
1651 EnableNamedMenuItem (char *menuRef, int state)
1653 MenuItem *item = MenuNameToItem(menuRef);
1655 if(item) gtk_widget_set_sensitive(item->handle, state);
1659 EnableButtonBar (int state)
1662 XtSetSensitive(optList[W_BUTTON].handle, state);
1668 SetMenuEnables (Enables *enab)
1670 while (enab->name != NULL) {
1671 EnableNamedMenuItem(enab->name, enab->value);
1678 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1679 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1681 if(*nprms == 0) return;
1682 item = MenuNameToItem(prms[0]);
1683 if(item) ((MenuProc *) item->proc) ();
1689 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
1691 RecentEngineEvent((int) (intptr_t) addr);
1696 AppendMenuItem (char *msg, int n)
1699 CreateMenuItem((Widget) optList[W_ENGIN].textValue, msg, (XtCallbackProc) MenuEngineSelect, n);
1713 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1714 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1715 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1716 dmEnables[i].piece);
1717 XtSetSensitive(entry, p != NULL || !appData.testLegality
1718 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1719 && !appData.icsActive));
1721 while (p && *p++ == dmEnables[i].piece) count++;
1722 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1724 XtSetArg(args[j], XtNlabel, label); j++;
1725 XtSetValues(entry, args, j);
1731 do_flash_delay (unsigned long msec)
1737 FlashDelay (int flash_delay)
1740 XSync(xDisplay, False);
1741 if(flash_delay) do_flash_delay(flash_delay);
1746 Fraction (int x, int start, int stop)
1748 double f = ((double) x - start)/(stop - start);
1749 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1753 static WindowPlacement wpNew;
1757 CoDrag (Widget sh, WindowPlacement *wp)
1760 int j=0, touch=0, fudge = 2;
1761 GetActualPlacement(sh, wp);
1762 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1763 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1764 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1765 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1766 if(!touch ) return; // only windows that touch co-move
1767 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1768 int heightInc = wpNew.height - wpMain.height;
1769 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1770 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1771 wp->y += fracTop * heightInc;
1772 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1773 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1774 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1775 int widthInc = wpNew.width - wpMain.width;
1776 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1777 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1778 wp->y += fracLeft * widthInc;
1779 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1780 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1782 wp->x += wpNew.x - wpMain.x;
1783 wp->y += wpNew.y - wpMain.y;
1784 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1785 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1787 XtSetArg(args[j], XtNx, wp->x); j++;
1788 XtSetArg(args[j], XtNy, wp->y); j++;
1789 XtSetValues(sh, args, j);
1794 ReSize (WindowPlacement *wp)
1797 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1798 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1799 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1800 if(sqy < sqx) sqx = sqy;
1801 if(sqx != squareSize) {
1802 squareSize = sqx; // adopt new square size
1803 CreatePNGPieces(); // make newly scaled pieces
1804 InitDrawingSizes(0, 0); // creates grid etc.
1805 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1806 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1807 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1808 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1809 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1813 static XtIntervalId delayedDragID = 0;
1815 static int delayedDragID = 0;
1825 GetActualPlacement(shellWidget, &wpNew);
1826 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1827 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1828 busy = 0; return; // false alarm
1831 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1832 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1833 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1834 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1836 DrawPosition(True, NULL);
1837 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1846 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1848 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1853 EventProc (Widget widget, caddr_t unused, XEvent *event)
1856 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1857 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1862 * event handler for redrawing the board
1865 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1867 DrawPosition(True, NULL);
1873 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1874 { // [HGM] pv: walk PV
1875 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1879 static int savedIndex; /* gross that this is global */
1882 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1886 XawTextPosition index, dummy;
1889 XawTextGetSelectionPos(w, &index, &dummy);
1890 XtSetArg(arg, XtNstring, &val);
1891 XtGetValues(w, &arg, 1);
1892 ReplaceComment(savedIndex, val);
1893 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1894 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1899 EditCommentPopUp (int index, char *title, char *text)
1902 if (text == NULL) text = "";
1903 NewCommentPopup(title, text, index);
1907 CommentPopUp (char *title, char *text)
1909 savedIndex = currentMove; // [HGM] vari
1910 NewCommentPopup(title, text, currentMove);
1916 PopDown(CommentDlg);
1920 /* Disable all user input other than deleting the window */
1921 static int frozen = 0;
1927 /* Grab by a widget that doesn't accept input */
1928 gtk_grab_add(optList[W_MESSG].handle);
1932 /* Undo a FreezeUI */
1936 if (!frozen) return;
1937 gtk_grab_remove(optList[W_MESSG].handle);
1944 static int oldPausing = FALSE;
1945 static GameMode oldmode = (GameMode) -1;
1950 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1952 if (pausing != oldPausing) {
1953 oldPausing = pausing;
1954 MarkMenuItem("Mode.Pause", pausing);
1956 if (appData.showButtonBar) {
1957 /* Always toggle, don't set. Previous code messes up when
1958 invoked while the button is pressed, as releasing it
1959 toggles the state again. */
1962 XtSetArg(args[0], XtNbackground, &oldbg);
1963 XtSetArg(args[1], XtNforeground, &oldfg);
1964 XtGetValues(optList[W_PAUSE].handle,
1966 XtSetArg(args[0], XtNbackground, oldfg);
1967 XtSetArg(args[1], XtNforeground, oldbg);
1969 XtSetValues(optList[W_PAUSE].handle, args, 2);
1974 wname = ModeToWidgetName(oldmode);
1975 if (wname != NULL) {
1976 MarkMenuItem(wname, False);
1978 wname = ModeToWidgetName(gameMode);
1979 if (wname != NULL) {
1980 MarkMenuItem(wname, True);
1983 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1985 /* Maybe all the enables should be handled here, not just this one */
1986 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1988 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1993 * Button/menu procedures
1997 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1998 char *selected_fen_position=NULL;
2001 SendPositionSelection (Widget w, Atom *selection, Atom *target,
2002 Atom *type_return, XtPointer *value_return,
2003 unsigned long *length_return, int *format_return)
2005 char *selection_tmp;
2007 // if (!selected_fen_position) return False; /* should never happen */
2008 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
2009 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
2010 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
2013 if (f == NULL) return False;
2017 selection_tmp = XtMalloc(len + 1);
2018 count = fread(selection_tmp, 1, len, f);
2021 XtFree(selection_tmp);
2024 selection_tmp[len] = NULLCHAR;
2026 /* note: since no XtSelectionDoneProc was registered, Xt will
2027 * automatically call XtFree on the value returned. So have to
2028 * make a copy of it allocated with XtMalloc */
2029 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
2030 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
2033 *value_return=selection_tmp;
2034 *length_return=strlen(selection_tmp);
2035 *type_return=*target;
2036 *format_return = 8; /* bits per byte */
2038 } else if (*target == XA_TARGETS(xDisplay)) {
2039 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
2040 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
2041 targets_tmp[1] = XA_STRING;
2042 *value_return = targets_tmp;
2043 *type_return = XA_ATOM;
2046 // This code leads to a read of value_return out of bounds on 64-bit systems.
2047 // Other code which I have seen always sets *format_return to 32 independent of
2048 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
2049 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
2050 *format_return = 8 * sizeof(Atom);
2051 if (*format_return > 32) {
2052 *length_return *= *format_return / 32;
2053 *format_return = 32;
2056 *format_return = 32;
2065 /* note: when called from menu all parameters are NULL, so no clue what the
2066 * Widget which was clicked on was, or what the click event was
2069 CopySomething (char *src)
2072 selected_fen_position = src;
2074 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
2075 * have a notion of a position that is selected but not copied.
2076 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
2078 XtOwnSelection(menuBarWidget, XA_PRIMARY,
2080 SendPositionSelection,
2081 NULL/* lose_ownership_proc */ ,
2082 NULL/* transfer_done_proc */);
2083 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2085 SendPositionSelection,
2086 NULL/* lose_ownership_proc */ ,
2087 NULL/* transfer_done_proc */);
2092 /* function called when the data to Paste is ready */
2094 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2095 Atom *type, XtPointer value, unsigned long *len, int *format)
2098 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2099 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2100 EditPositionPasteFEN(fenstr);
2105 /* called when Paste Position button is pressed,
2106 * all parameters will be NULL */
2108 PastePositionProc ()
2111 XtGetSelectionValue(menuBarWidget,
2112 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2113 /* (XtSelectionCallbackProc) */ PastePositionCB,
2114 NULL, /* client_data passed to PastePositionCB */
2116 /* better to use the time field from the event that triggered the
2117 * call to this function, but that isn't trivial to get
2126 /* note: when called from menu all parameters are NULL, so no clue what the
2127 * Widget which was clicked on was, or what the click event was
2129 /* function called when the data to Paste is ready */
2131 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2132 Atom *type, XtPointer value, unsigned long *len, int *format)
2135 if (value == NULL || *len == 0) {
2136 return; /* nothing had been selected to copy */
2138 f = fopen(gamePasteFilename, "w");
2140 DisplayError(_("Can't open temp file"), errno);
2143 fwrite(value, 1, *len, f);
2146 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2150 /* called when Paste Game button is pressed,
2151 * all parameters will be NULL */
2156 XtGetSelectionValue(menuBarWidget,
2157 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2158 /* (XtSelectionCallbackProc) */ PasteGameCB,
2159 NULL, /* client_data passed to PasteGameCB */
2161 /* better to use the time field from the event that triggered the
2162 * call to this function, but that isn't trivial to get
2172 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2179 { // bassic primitive for determining if modifier keys are pressed
2182 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2184 XQueryKeymap(xDisplay,keys);
2185 for(i=0; i<6; i++) {
2187 j = XKeysymToKeycode(xDisplay, codes[i]);
2188 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2195 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2200 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2201 if ( n == 1 && *buf >= 32 // printable
2202 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2203 ) BoxAutoPopUp (buf);
2209 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2210 { // [HGM] input: let up-arrow recall previous line from history
2215 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2216 { // [HGM] input: let down-arrow recall next line from history
2221 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2228 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2230 if (!TempBackwardActive) {
2231 TempBackwardActive = True;
2237 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2239 /* Check to see if triggered by a key release event for a repeating key.
2240 * If so the next queued event will be a key press of the same key at the same time */
2241 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2243 XPeekEvent(xDisplay, &next);
2244 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2245 next.xkey.keycode == event->xkey.keycode)
2249 TempBackwardActive = False;
2253 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2254 { // called as key binding
2257 if (nprms && *nprms > 0)
2261 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2268 { // called from menu
2270 ManInner(NULL, NULL, NULL, NULL);
2275 SetWindowTitle (char *text, char *title, char *icon)
2280 if (appData.titleInWindow) {
2282 XtSetArg(args[i], XtNlabel, text); i++;
2283 XtSetValues(titleWidget, args, i);
2286 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2287 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2288 XtSetValues(shellWidget, args, i);
2289 XSync(xDisplay, False);
2291 if (appData.titleInWindow) {
2292 SetWidgetLabel(titleWidget, text);
2294 gtk_window_set_title (GTK_WINDOW(shells[BoardWindow]), title);
2299 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2305 DisplayIcsInteractionTitle (String message)
2308 if (oldICSInteractionTitle == NULL) {
2309 /* Magic to find the old window title, adapted from vim */
2310 char *wina = getenv("WINDOWID");
2312 Window win = (Window) atoi(wina);
2313 Window root, parent, *children;
2314 unsigned int nchildren;
2315 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2317 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2318 if (!XQueryTree(xDisplay, win, &root, &parent,
2319 &children, &nchildren)) break;
2320 if (children) XFree((void *)children);
2321 if (parent == root || parent == 0) break;
2324 XSetErrorHandler(oldHandler);
2326 if (oldICSInteractionTitle == NULL) {
2327 oldICSInteractionTitle = "xterm";
2330 printf("\033]0;%s\007", message);
2337 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2339 GtkWidget *w = (GtkWidget *) opt->handle;
2345 strcpy(bgcolor, "black");
2346 strcpy(fgcolor, "white");
2348 strcpy(bgcolor, "white");
2349 strcpy(fgcolor, "black");
2352 appData.lowTimeWarning &&
2353 (timer / 1000) < appData.icsAlarmTime) {
2354 strcpy(fgcolor, appData.lowTimeWarningColor);
2357 if (appData.clockMode) {
2358 markup = g_markup_printf_escaped("<span size=\"xx-large\" weight=\"heavy\" background=\"%s\" foreground=\"%s\">%s:%s%s</span>",
2359 bgcolor, fgcolor, color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2361 markup = g_markup_printf_escaped("<span size=\"xx-large\" weight=\"heavy\" background=\"%s\" foreground=\"%s\">%s </span>",
2362 bgcolor, fgcolor, color);
2364 gtk_label_set_markup(GTK_LABEL(w), markup);
2369 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2373 SetClockIcon (int color)
2377 Pixmap pm = *clockIcons[color];
2378 if (iconPixmap != pm) {
2380 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2381 XtSetValues(shellWidget, args, 1);
2386 #define INPUT_SOURCE_BUF_SIZE 8192
2395 char buf[INPUT_SOURCE_BUF_SIZE];
2400 DoInputCallback(io, cond, data)
2405 /* read input from one of the input source (for example a chess program, ICS, etc).
2406 * and call a function that will handle the input
2413 /* All information (callback function, file descriptor, etc) is
2414 * saved in an InputSource structure
2416 InputSource *is = (InputSource *) data;
2418 if (is->lineByLine) {
2419 count = read(is->fd, is->unused,
2420 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2422 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2425 is->unused += count;
2427 /* break input into lines and call the callback function on each
2430 while (p < is->unused) {
2431 q = memchr(p, '\n', is->unused - p);
2432 if (q == NULL) break;
2434 (is->func)(is, is->closure, p, q - p, 0);
2437 /* remember not yet used part of the buffer */
2439 while (p < is->unused) {
2444 /* read maximum length of input buffer and send the whole buffer
2445 * to the callback function
2447 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2452 (is->func)(is, is->closure, is->buf, count, error);
2454 return True; // Must return true or the watch will be removed
2457 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
2464 GIOChannel *channel;
2465 ChildProc *cp = (ChildProc *) pr;
2467 is = (InputSource *) calloc(1, sizeof(InputSource));
2468 is->lineByLine = lineByLine;
2472 is->fd = fileno(stdin);
2474 is->kind = cp->kind;
2475 is->fd = cp->fdFrom;
2478 is->unused = is->buf;
2482 /* GTK-TODO: will this work on windows?*/
2484 channel = g_io_channel_unix_new(is->fd);
2485 g_io_channel_set_close_on_unref (channel, TRUE);
2486 is->sid = g_io_add_watch(channel, G_IO_IN,(GIOFunc) DoInputCallback, is);
2488 is->closure = closure;
2489 return (InputSourceRef) is;
2494 RemoveInputSource(isr)
2497 InputSource *is = (InputSource *) isr;
2499 if (is->sid == 0) return;
2500 g_source_remove(is->sid);
2507 static Boolean frameWaiting;
2510 FrameAlarm (int sig)
2512 frameWaiting = False;
2513 /* In case System-V style signals. Needed?? */
2514 signal(SIGALRM, FrameAlarm);
2518 FrameDelay (int time)
2521 struct itimerval delay;
2523 XSync(xDisplay, False);
2526 frameWaiting = True;
2527 signal(SIGALRM, FrameAlarm);
2528 delay.it_interval.tv_sec =
2529 delay.it_value.tv_sec = time / 1000;
2530 delay.it_interval.tv_usec =
2531 delay.it_value.tv_usec = (time % 1000) * 1000;
2532 setitimer(ITIMER_REAL, &delay, NULL);
2533 while (frameWaiting) pause();
2534 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2535 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2536 setitimer(ITIMER_REAL, &delay, NULL);
2544 FrameDelay (int time)
2547 XSync(xDisplay, False);
2550 usleep(time * 1000);
2556 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2558 char buf[MSG_SIZ], *logoName = buf;
2559 if(appData.logo[n][0]) {
2560 logoName = appData.logo[n];
2561 } else if(appData.autoLogo) {
2562 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2563 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2564 } else if(appData.directory[n] && appData.directory[n][0]) {
2565 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2569 { ASSIGN(cps->programLogo, logoName); }
2573 UpdateLogos (int displ)
2575 if(optList[W_WHITE-1].handle == NULL) return;
2576 LoadLogo(&first, 0, 0);
2577 LoadLogo(&second, 1, appData.icsActive);
2578 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);