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);
1330 xBoardWindow = XtWindow(boardWidget);
1333 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
1334 // not need to go into InitDrawingSizes().
1342 ReadBitmap(&wIconPixmap, "icon_white.bm",
1343 icon_white_bits, icon_white_width, icon_white_height);
1344 ReadBitmap(&bIconPixmap, "icon_black.bm",
1345 icon_black_bits, icon_black_width, icon_black_height);
1346 iconPixmap = wIconPixmap;
1348 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
1349 XtSetValues(shellWidget, args, i);
1353 * Create a cursor for the board widget.
1356 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
1357 XChangeWindowAttributes(xDisplay, xBoardWindow,
1358 CWCursor, &window_attributes);
1362 * Inhibit shell resizing.
1365 shellArgs[0].value = (XtArgVal) &w;
1366 shellArgs[1].value = (XtArgVal) &h;
1367 XtGetValues(shellWidget, shellArgs, 2);
1368 shellArgs[4].value = shellArgs[2].value = w;
1369 shellArgs[5].value = shellArgs[3].value = h;
1370 // XtSetValues(shellWidget, &shellArgs[2], 4);
1372 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
1373 marginH = h - boardHeight;
1376 CatchDeleteWindow(shellWidget, "QuitProc");
1382 if(appData.logoSize)
1383 { // locate and read user logo
1385 snprintf(buf, MSG_SIZ, "%s/%s.png", appData.logoDir, UserName());
1386 ASSIGN(userLogo, buf);
1389 if (appData.animate || appData.animateDragging)
1393 XtAugmentTranslations(formWidget,
1394 XtParseTranslationTable(globalTranslations));
1396 XtAddEventHandler(formWidget, KeyPressMask, False,
1397 (XtEventHandler) MoveTypeInProc, NULL);
1398 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
1399 (XtEventHandler) EventProc, NULL);
1402 /* [AS] Restore layout */
1403 if( wpMoveHistory.visible ) {
1407 if( wpEvalGraph.visible )
1412 if( wpEngineOutput.visible ) {
1413 EngineOutputPopUp();
1418 if (errorExitStatus == -1) {
1419 if (appData.icsActive) {
1420 /* We now wait until we see "login:" from the ICS before
1421 sending the logon script (problems with timestamp otherwise) */
1422 /*ICSInitScript();*/
1423 if (appData.icsInputBox) ICSInputBoxPopUp();
1427 signal(SIGWINCH, TermSizeSigHandler);
1429 signal(SIGINT, IntSigHandler);
1430 signal(SIGTERM, IntSigHandler);
1431 if (*appData.cmailGameName != NULLCHAR) {
1432 signal(SIGUSR1, CmailSigHandler);
1436 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1439 // XtSetKeyboardFocus(shellWidget, formWidget);
1441 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
1444 /* check for GTK events and process them */
1447 gtk_main_iteration();
1450 if (appData.debugMode) fclose(debugFP); // [DM] debug
1455 TermSizeSigHandler (int sig)
1461 IntSigHandler (int sig)
1467 CmailSigHandler (int sig)
1472 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1474 /* Activate call-back function CmailSigHandlerCallBack() */
1475 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1477 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
1481 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
1484 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
1486 /**** end signal code ****/
1489 #define Abs(n) ((n)<0 ? -(n) : (n))
1493 InsertPxlSize (char *pattern, int targetPxlSize)
1495 char *base_fnt_lst, strInt[12], *p, *q;
1496 int alternatives, i, len, strIntLen;
1499 * Replace the "*" (if present) in the pixel-size slot of each
1500 * alternative with the targetPxlSize.
1504 while ((p = strchr(p, ',')) != NULL) {
1508 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
1509 strIntLen = strlen(strInt);
1510 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
1514 while (alternatives--) {
1515 char *comma = strchr(p, ',');
1516 for (i=0; i<14; i++) {
1517 char *hyphen = strchr(p, '-');
1519 if (comma && hyphen > comma) break;
1520 len = hyphen + 1 - p;
1521 if (i == 7 && *p == '*' && len == 2) {
1523 memcpy(q, strInt, strIntLen);
1533 len = comma + 1 - p;
1540 return base_fnt_lst;
1545 CreateFontSet (char *base_fnt_lst)
1548 char **missing_list;
1552 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
1553 &missing_list, &missing_count, &def_string);
1554 if (appData.debugMode) {
1556 XFontStruct **font_struct_list;
1557 char **font_name_list;
1558 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
1560 fprintf(debugFP, " got list %s, locale %s\n",
1561 XBaseFontNameListOfFontSet(fntSet),
1562 XLocaleOfFontSet(fntSet));
1563 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
1564 for (i = 0; i < count; i++) {
1565 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
1568 for (i = 0; i < missing_count; i++) {
1569 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
1572 if (fntSet == NULL) {
1573 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
1579 #else // not ENABLE_NLS
1581 * Find a font that matches "pattern" that is as close as
1582 * possible to the targetPxlSize. Prefer fonts that are k
1583 * pixels smaller to fonts that are k pixels larger. The
1584 * pattern must be in the X Consortium standard format,
1585 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
1586 * The return value should be freed with XtFree when no
1590 FindFont (char *pattern, int targetPxlSize)
1592 char **fonts, *p, *best, *scalable, *scalableTail;
1593 int i, j, nfonts, minerr, err, pxlSize;
1596 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
1598 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
1599 programName, pattern);
1606 for (i=0; i<nfonts; i++) {
1609 if (*p != '-') continue;
1611 if (*p == NULLCHAR) break;
1612 if (*p++ == '-') j++;
1614 if (j < 7) continue;
1617 scalable = fonts[i];
1620 err = pxlSize - targetPxlSize;
1621 if (Abs(err) < Abs(minerr) ||
1622 (minerr > 0 && err < 0 && -err == minerr)) {
1628 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
1629 /* If the error is too big and there is a scalable font,
1630 use the scalable font. */
1631 int headlen = scalableTail - scalable;
1632 p = (char *) XtMalloc(strlen(scalable) + 10);
1633 while (isdigit(*scalableTail)) scalableTail++;
1634 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
1636 p = (char *) XtMalloc(strlen(best) + 2);
1637 safeStrCpy(p, best, strlen(best)+1 );
1639 if (appData.debugMode) {
1640 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
1641 pattern, targetPxlSize, p);
1643 XFreeFontNames(fonts);
1650 EnableNamedMenuItem (char *menuRef, int state)
1652 MenuItem *item = MenuNameToItem(menuRef);
1654 if(item) gtk_widget_set_sensitive(item->handle, state);
1658 EnableButtonBar (int state)
1661 XtSetSensitive(optList[W_BUTTON].handle, state);
1667 SetMenuEnables (Enables *enab)
1669 while (enab->name != NULL) {
1670 EnableNamedMenuItem(enab->name, enab->value);
1677 KeyBindingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1678 { // [HGM] new method of key binding: specify MenuItem(FlipView) in stead of FlipViewProc in translation string
1680 if(*nprms == 0) return;
1681 item = MenuNameToItem(prms[0]);
1682 if(item) ((MenuProc *) item->proc) ();
1696 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
1697 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
1698 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
1699 dmEnables[i].piece);
1700 XtSetSensitive(entry, p != NULL || !appData.testLegality
1701 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
1702 && !appData.icsActive));
1704 while (p && *p++ == dmEnables[i].piece) count++;
1705 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
1707 XtSetArg(args[j], XtNlabel, label); j++;
1708 XtSetValues(entry, args, j);
1714 do_flash_delay (unsigned long msec)
1720 FlashDelay (int flash_delay)
1723 XSync(xDisplay, False);
1724 if(flash_delay) do_flash_delay(flash_delay);
1729 Fraction (int x, int start, int stop)
1731 double f = ((double) x - start)/(stop - start);
1732 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
1736 static WindowPlacement wpNew;
1740 CoDrag (Widget sh, WindowPlacement *wp)
1743 int j=0, touch=0, fudge = 2;
1744 GetActualPlacement(sh, wp);
1745 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
1746 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
1747 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
1748 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
1749 if(!touch ) return; // only windows that touch co-move
1750 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
1751 int heightInc = wpNew.height - wpMain.height;
1752 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1753 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
1754 wp->y += fracTop * heightInc;
1755 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
1756 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
1757 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
1758 int widthInc = wpNew.width - wpMain.width;
1759 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1760 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
1761 wp->y += fracLeft * widthInc;
1762 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
1763 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
1765 wp->x += wpNew.x - wpMain.x;
1766 wp->y += wpNew.y - wpMain.y;
1767 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
1768 if(touch == 3) wp->y += wpNew.height - wpMain.height;
1770 XtSetArg(args[j], XtNx, wp->x); j++;
1771 XtSetArg(args[j], XtNy, wp->y); j++;
1772 XtSetValues(sh, args, j);
1777 ReSize (WindowPlacement *wp)
1780 if(wp->width == wpMain.width && wp->height == wpMain.height) return; // not sized
1781 sqx = (wp->width - lineGap - marginW) / BOARD_WIDTH - lineGap;
1782 sqy = (wp->height - lineGap - marginH) / BOARD_HEIGHT - lineGap;
1783 if(sqy < sqx) sqx = sqy;
1784 if(sqx != squareSize) {
1785 squareSize = sqx; // adopt new square size
1786 CreatePNGPieces(); // make newly scaled pieces
1787 InitDrawingSizes(0, 0); // creates grid etc.
1788 } else ResizeBoardWindow(BOARD_WIDTH * (squareSize + lineGap) + lineGap, BOARD_HEIGHT * (squareSize + lineGap) + lineGap, 0);
1789 w = BOARD_WIDTH * (squareSize + lineGap) + lineGap;
1790 h = BOARD_HEIGHT * (squareSize + lineGap) + lineGap;
1791 if(optList[W_BOARD].max > w) optList[W_BOARD].max = w;
1792 if(optList[W_BOARD].value > h) optList[W_BOARD].value = h;
1796 static XtIntervalId delayedDragID = 0;
1798 static int delayedDragID = 0;
1808 GetActualPlacement(shellWidget, &wpNew);
1809 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
1810 wpNew.width == wpMain.width && wpNew.height == wpMain.height) { // not sized
1811 busy = 0; return; // false alarm
1814 if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
1815 if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
1816 if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
1817 if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
1819 DrawPosition(True, NULL);
1820 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
1829 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
1831 XtAppAddTimeOut(appContext, 200, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
1836 EventProc (Widget widget, caddr_t unused, XEvent *event)
1839 if(XtIsRealized(widget) && event->type == ConfigureNotify || appData.useStickyWindows)
1840 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
1845 * event handler for redrawing the board
1848 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
1850 DrawPosition(True, NULL);
1856 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
1857 { // [HGM] pv: walk PV
1858 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
1862 static int savedIndex; /* gross that this is global */
1865 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
1869 XawTextPosition index, dummy;
1872 XawTextGetSelectionPos(w, &index, &dummy);
1873 XtSetArg(arg, XtNstring, &val);
1874 XtGetValues(w, &arg, 1);
1875 ReplaceComment(savedIndex, val);
1876 if(savedIndex != currentMove) ToNrEvent(savedIndex);
1877 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
1882 EditCommentPopUp (int index, char *title, char *text)
1885 if (text == NULL) text = "";
1886 NewCommentPopup(title, text, index);
1890 CommentPopUp (char *title, char *text)
1892 savedIndex = currentMove; // [HGM] vari
1893 NewCommentPopup(title, text, currentMove);
1899 PopDown(CommentDlg);
1903 /* Disable all user input other than deleting the window */
1904 static int frozen = 0;
1910 /* Grab by a widget that doesn't accept input */
1911 gtk_grab_add(optList[W_MESSG].handle);
1915 /* Undo a FreezeUI */
1919 if (!frozen) return;
1920 gtk_grab_remove(optList[W_MESSG].handle);
1927 static int oldPausing = FALSE;
1928 static GameMode oldmode = (GameMode) -1;
1933 if (!boardWidget || !XtIsRealized(boardWidget)) return;
1935 if (pausing != oldPausing) {
1936 oldPausing = pausing;
1937 MarkMenuItem("Mode.Pause", pausing);
1939 if (appData.showButtonBar) {
1940 /* Always toggle, don't set. Previous code messes up when
1941 invoked while the button is pressed, as releasing it
1942 toggles the state again. */
1945 XtSetArg(args[0], XtNbackground, &oldbg);
1946 XtSetArg(args[1], XtNforeground, &oldfg);
1947 XtGetValues(optList[W_PAUSE].handle,
1949 XtSetArg(args[0], XtNbackground, oldfg);
1950 XtSetArg(args[1], XtNforeground, oldbg);
1952 XtSetValues(optList[W_PAUSE].handle, args, 2);
1957 wname = ModeToWidgetName(oldmode);
1958 if (wname != NULL) {
1959 MarkMenuItem(wname, False);
1961 wname = ModeToWidgetName(gameMode);
1962 if (wname != NULL) {
1963 MarkMenuItem(wname, True);
1966 MarkMenuItem("Mode.MachineMatch", matchMode && matchGame < appData.matchGames);
1968 /* Maybe all the enables should be handled here, not just this one */
1969 EnableNamedMenuItem("Mode.Training", gameMode == Training || gameMode == PlayFromGameFile);
1971 DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);
1976 * Button/menu procedures
1980 /* this variable is shared between CopyPositionProc and SendPositionSelection */
1981 char *selected_fen_position=NULL;
1984 SendPositionSelection (Widget w, Atom *selection, Atom *target,
1985 Atom *type_return, XtPointer *value_return,
1986 unsigned long *length_return, int *format_return)
1988 char *selection_tmp;
1990 // if (!selected_fen_position) return False; /* should never happen */
1991 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
1992 if (!selected_fen_position) { // since it never happens, we use it for indicating a game is being sent
1993 FILE* f = fopen(gameCopyFilename, "r"); // This code, taken from SendGameSelection, now merges the two
1996 if (f == NULL) return False;
2000 selection_tmp = XtMalloc(len + 1);
2001 count = fread(selection_tmp, 1, len, f);
2004 XtFree(selection_tmp);
2007 selection_tmp[len] = NULLCHAR;
2009 /* note: since no XtSelectionDoneProc was registered, Xt will
2010 * automatically call XtFree on the value returned. So have to
2011 * make a copy of it allocated with XtMalloc */
2012 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
2013 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
2016 *value_return=selection_tmp;
2017 *length_return=strlen(selection_tmp);
2018 *type_return=*target;
2019 *format_return = 8; /* bits per byte */
2021 } else if (*target == XA_TARGETS(xDisplay)) {
2022 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
2023 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
2024 targets_tmp[1] = XA_STRING;
2025 *value_return = targets_tmp;
2026 *type_return = XA_ATOM;
2029 // This code leads to a read of value_return out of bounds on 64-bit systems.
2030 // Other code which I have seen always sets *format_return to 32 independent of
2031 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
2032 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
2033 *format_return = 8 * sizeof(Atom);
2034 if (*format_return > 32) {
2035 *length_return *= *format_return / 32;
2036 *format_return = 32;
2039 *format_return = 32;
2048 /* note: when called from menu all parameters are NULL, so no clue what the
2049 * Widget which was clicked on was, or what the click event was
2052 CopySomething (char *src)
2055 selected_fen_position = src;
2057 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
2058 * have a notion of a position that is selected but not copied.
2059 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
2061 XtOwnSelection(menuBarWidget, XA_PRIMARY,
2063 SendPositionSelection,
2064 NULL/* lose_ownership_proc */ ,
2065 NULL/* transfer_done_proc */);
2066 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
2068 SendPositionSelection,
2069 NULL/* lose_ownership_proc */ ,
2070 NULL/* transfer_done_proc */);
2075 /* function called when the data to Paste is ready */
2077 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
2078 Atom *type, XtPointer value, unsigned long *len, int *format)
2081 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
2082 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
2083 EditPositionPasteFEN(fenstr);
2088 /* called when Paste Position button is pressed,
2089 * all parameters will be NULL */
2091 PastePositionProc ()
2094 XtGetSelectionValue(menuBarWidget,
2095 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2096 /* (XtSelectionCallbackProc) */ PastePositionCB,
2097 NULL, /* client_data passed to PastePositionCB */
2099 /* better to use the time field from the event that triggered the
2100 * call to this function, but that isn't trivial to get
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
2112 /* function called when the data to Paste is ready */
2114 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
2115 Atom *type, XtPointer value, unsigned long *len, int *format)
2118 if (value == NULL || *len == 0) {
2119 return; /* nothing had been selected to copy */
2121 f = fopen(gamePasteFilename, "w");
2123 DisplayError(_("Can't open temp file"), errno);
2126 fwrite(value, 1, *len, f);
2129 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
2133 /* called when Paste Game button is pressed,
2134 * all parameters will be NULL */
2139 XtGetSelectionValue(menuBarWidget,
2140 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
2141 /* (XtSelectionCallbackProc) */ PasteGameCB,
2142 NULL, /* client_data passed to PasteGameCB */
2144 /* better to use the time field from the event that triggered the
2145 * call to this function, but that isn't trivial to get
2155 QuitWrapper (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2162 { // bassic primitive for determining if modifier keys are pressed
2165 long int codes[] = { XK_Meta_L, XK_Meta_R, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R };
2167 XQueryKeymap(xDisplay,keys);
2168 for(i=0; i<6; i++) {
2170 j = XKeysymToKeycode(xDisplay, codes[i]);
2171 k += ( (keys[j>>3]&1<<(j&7)) != 0 );
2178 MoveTypeInProc (Widget widget, caddr_t unused, XEvent *event)
2183 int n = XLookupString(&(event->xkey), buf, 10, &sym, NULL);
2184 if ( n == 1 && *buf >= 32 // printable
2185 && !(ShiftKeys() & 0x3C) // no Alt, Ctrl
2186 ) BoxAutoPopUp (buf);
2192 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2193 { // [HGM] input: let up-arrow recall previous line from history
2198 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2199 { // [HGM] input: let down-arrow recall next line from history
2204 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2211 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2213 if (!TempBackwardActive) {
2214 TempBackwardActive = True;
2220 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2222 /* Check to see if triggered by a key release event for a repeating key.
2223 * If so the next queued event will be a key press of the same key at the same time */
2224 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
2226 XPeekEvent(xDisplay, &next);
2227 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
2228 next.xkey.keycode == event->xkey.keycode)
2232 TempBackwardActive = False;
2236 ManInner (Widget w, XEvent *event, String *prms, Cardinal *nprms)
2237 { // called as key binding
2240 if (nprms && *nprms > 0)
2244 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
2251 { // called from menu
2253 ManInner(NULL, NULL, NULL, NULL);
2258 SetWindowTitle (char *text, char *title, char *icon)
2263 if (appData.titleInWindow) {
2265 XtSetArg(args[i], XtNlabel, text); i++;
2266 XtSetValues(titleWidget, args, i);
2269 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
2270 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
2271 XtSetValues(shellWidget, args, i);
2272 XSync(xDisplay, False);
2274 if (appData.titleInWindow) {
2275 SetWidgetLabel(titleWidget, text);
2277 gtk_window_set_title (GTK_WINDOW(shells[BoardWindow]), title);
2282 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
2288 DisplayIcsInteractionTitle (String message)
2291 if (oldICSInteractionTitle == NULL) {
2292 /* Magic to find the old window title, adapted from vim */
2293 char *wina = getenv("WINDOWID");
2295 Window win = (Window) atoi(wina);
2296 Window root, parent, *children;
2297 unsigned int nchildren;
2298 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
2300 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
2301 if (!XQueryTree(xDisplay, win, &root, &parent,
2302 &children, &nchildren)) break;
2303 if (children) XFree((void *)children);
2304 if (parent == root || parent == 0) break;
2307 XSetErrorHandler(oldHandler);
2309 if (oldICSInteractionTitle == NULL) {
2310 oldICSInteractionTitle = "xterm";
2313 printf("\033]0;%s\007", message);
2320 DisplayTimerLabel (Option *opt, char *color, long timer, int highlight)
2322 GtkWidget *w = (GtkWidget *) opt->handle;
2328 strcpy(bgcolor, "black");
2329 strcpy(fgcolor, "white");
2331 strcpy(bgcolor, "white");
2332 strcpy(fgcolor, "black");
2335 appData.lowTimeWarning &&
2336 (timer / 1000) < appData.icsAlarmTime) {
2337 strcpy(fgcolor, appData.lowTimeWarningColor);
2340 if (appData.clockMode) {
2341 markup = g_markup_printf_escaped("<span size=\"xx-large\" weight=\"heavy\" background=\"%s\" foreground=\"%s\">%s:%s%s</span>",
2342 bgcolor, fgcolor, color, appData.logoSize && !partnerUp ? "\n" : " ", TimeString(timer));
2344 markup = g_markup_printf_escaped("<span size=\"xx-large\" weight=\"heavy\" background=\"%s\" foreground=\"%s\">%s </span>",
2345 bgcolor, fgcolor, color);
2347 gtk_label_set_markup(GTK_LABEL(w), markup);
2352 static Pixmap *clockIcons[] = { &wIconPixmap, &bIconPixmap };
2356 SetClockIcon (int color)
2360 Pixmap pm = *clockIcons[color];
2361 if (iconPixmap != pm) {
2363 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
2364 XtSetValues(shellWidget, args, 1);
2369 #define INPUT_SOURCE_BUF_SIZE 8192
2378 char buf[INPUT_SOURCE_BUF_SIZE];
2383 DoInputCallback(io, cond, data)
2388 /* read input from one of the input source (for example a chess program, ICS, etc).
2389 * and call a function that will handle the input
2396 /* All information (callback function, file descriptor, etc) is
2397 * saved in an InputSource structure
2399 InputSource *is = (InputSource *) data;
2401 if (is->lineByLine) {
2402 count = read(is->fd, is->unused,
2403 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
2405 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
2408 is->unused += count;
2410 /* break input into lines and call the callback function on each
2413 while (p < is->unused) {
2414 q = memchr(p, '\n', is->unused - p);
2415 if (q == NULL) break;
2417 (is->func)(is, is->closure, p, q - p, 0);
2420 /* remember not yet used part of the buffer */
2422 while (p < is->unused) {
2427 /* read maximum length of input buffer and send the whole buffer
2428 * to the callback function
2430 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
2435 (is->func)(is, is->closure, is->buf, count, error);
2437 return True; // Must return true or the watch will be removed
2440 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
2447 GIOChannel *channel;
2448 ChildProc *cp = (ChildProc *) pr;
2450 is = (InputSource *) calloc(1, sizeof(InputSource));
2451 is->lineByLine = lineByLine;
2455 is->fd = fileno(stdin);
2457 is->kind = cp->kind;
2458 is->fd = cp->fdFrom;
2461 is->unused = is->buf;
2465 /* GTK-TODO: will this work on windows?*/
2467 channel = g_io_channel_unix_new(is->fd);
2468 g_io_channel_set_close_on_unref (channel, TRUE);
2469 is->sid = g_io_add_watch(channel, G_IO_IN,(GIOFunc) DoInputCallback, is);
2471 is->closure = closure;
2472 return (InputSourceRef) is;
2477 RemoveInputSource(isr)
2480 InputSource *is = (InputSource *) isr;
2482 if (is->sid == 0) return;
2483 g_source_remove(is->sid);
2490 static Boolean frameWaiting;
2493 FrameAlarm (int sig)
2495 frameWaiting = False;
2496 /* In case System-V style signals. Needed?? */
2497 signal(SIGALRM, FrameAlarm);
2501 FrameDelay (int time)
2504 struct itimerval delay;
2506 XSync(xDisplay, False);
2509 frameWaiting = True;
2510 signal(SIGALRM, FrameAlarm);
2511 delay.it_interval.tv_sec =
2512 delay.it_value.tv_sec = time / 1000;
2513 delay.it_interval.tv_usec =
2514 delay.it_value.tv_usec = (time % 1000) * 1000;
2515 setitimer(ITIMER_REAL, &delay, NULL);
2516 while (frameWaiting) pause();
2517 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
2518 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
2519 setitimer(ITIMER_REAL, &delay, NULL);
2527 FrameDelay (int time)
2530 XSync(xDisplay, False);
2533 usleep(time * 1000);
2539 LoadLogo (ChessProgramState *cps, int n, Boolean ics)
2541 char buf[MSG_SIZ], *logoName = buf;
2542 if(appData.logo[n][0]) {
2543 logoName = appData.logo[n];
2544 } else if(appData.autoLogo) {
2545 if(ics) { // [HGM] logo: in ICS mode second can be used for ICS
2546 sprintf(buf, "%s/%s.png", appData.logoDir, appData.icsHost);
2547 } else if(appData.directory[n] && appData.directory[n][0]) {
2548 sprintf(buf, "%s/%s.png", appData.logoDir, cps->tidy);
2552 { ASSIGN(cps->programLogo, logoName); }
2556 UpdateLogos (int displ)
2558 if(optList[W_WHITE-1].handle == NULL) return;
2559 LoadLogo(&first, 0, 0);
2560 LoadLogo(&second, 1, appData.icsActive);
2561 if(displ) DisplayLogos(&optList[W_WHITE-1], &optList[W_BLACK+1]);