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 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>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
237 char *init_path, char *mode, int (*show_entry)(), char **name_return));
238 RETSIGTYPE CmailSigHandler P((int sig));
239 RETSIGTYPE IntSigHandler P((int sig));
240 RETSIGTYPE TermSizeSigHandler P((int sig));
241 void CreateGCs P((void));
242 void CreateXIMPieces P((void));
243 void CreateXPMPieces P((void));
244 void CreatePieces P((void));
245 void CreatePieceMenus P((void));
246 Widget CreateMenuBar P((Menu *mb));
247 Widget CreateButtonBar P ((MenuItem *mi));
248 char *FindFont P((char *pattern, int targetPxlSize));
249 void PieceMenuPopup P((Widget w, XEvent *event,
250 String *params, Cardinal *num_params));
251 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
252 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
254 u_int wreq, u_int hreq));
255 void CreateGrid P((void));
256 int EventToSquare P((int x, int limit));
257 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
258 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
259 void HandleUserMove P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void AnimateUserMove P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void HandlePV P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void WhiteClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void BlackClock P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void DrawPositionProc P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
273 void CommentPopUp P((char *title, char *label));
274 void CommentPopDown P((void));
275 void CommentCallback P((Widget w, XtPointer client_data,
276 XtPointer call_data));
277 void ICSInputBoxPopUp P((void));
278 void ICSInputBoxPopDown P((void));
279 void FileNamePopUp P((char *label, char *def,
280 FileProc proc, char *openMode));
281 void FileNamePopDown P((void));
282 void FileNameCallback P((Widget w, XtPointer client_data,
283 XtPointer call_data));
284 void FileNameAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionReplyAction P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionProc P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void AskQuestionPopDown P((void));
291 void PromotionPopDown P((void));
292 void PromotionCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void EditCommentPopDown P((void));
295 void EditCommentCallback P((Widget w, XtPointer client_data,
296 XtPointer call_data));
297 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
298 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
299 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
300 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
304 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
306 void LoadPositionProc P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
310 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
312 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
314 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
316 void PastePositionProc P((Widget w, XEvent *event, String *prms,
318 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void SavePositionProc P((Widget w, XEvent *event,
322 String *prms, Cardinal *nprms));
323 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
326 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
330 void MachineWhiteProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeModeProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void AnalyzeFileProc P((Widget w, XEvent *event,
335 String *prms, Cardinal *nprms));
336 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
338 void IcsClientProc P((Widget w, XEvent *event, String *prms,
340 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void EditPositionProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void EditCommentProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void IcsInputBoxProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void StopObservingProc P((Widget w, XEvent *event, String *prms,
364 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
366 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
375 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
377 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
380 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
382 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
384 void AutocommProc P((Widget w, XEvent *event, String *prms,
386 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void AutobsProc P((Widget w, XEvent *event, String *prms,
390 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
395 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
398 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
400 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
402 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
406 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
408 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
410 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
412 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
414 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
418 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
420 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
422 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
424 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void DisplayMove P((int moveNumber));
436 void DisplayTitle P((char *title));
437 void ICSInitScript P((void));
438 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
439 void ErrorPopUp P((char *title, char *text, int modal));
440 void ErrorPopDown P((void));
441 static char *ExpandPathName P((char *path));
442 static void CreateAnimVars P((void));
443 static void DragPieceMove P((int x, int y));
444 static void DrawDragPiece P((void));
445 char *ModeToWidgetName P((GameMode mode));
446 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void GameListOptionsPopDown P(());
455 void ShufflePopDown P(());
456 void EnginePopDown P(());
457 void UciPopDown P(());
458 void TimeControlPopDown P(());
459 void NewVariantPopDown P(());
460 void SettingsPopDown P(());
461 void update_ics_width P(());
462 int get_term_width P(());
463 int CopyMemoProc P(());
465 * XBoard depends on Xt R4 or higher
467 int xtVersion = XtSpecificationRelease;
472 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
473 jailSquareColor, highlightSquareColor, premoveHighlightColor;
474 Pixel lowTimeWarningColor;
475 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
476 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
477 wjPieceGC, bjPieceGC, prelineGC, countGC;
478 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
479 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
480 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
481 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
482 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
483 ICSInputShell, fileNameShell, askQuestionShell;
484 Widget historyShell, evalGraphShell, gameListShell;
485 int hOffset; // [HGM] dual
486 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
487 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
488 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
489 Font clockFontID, coordFontID, countFontID;
490 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
491 XtAppContext appContext;
493 char *oldICSInteractionTitle;
497 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
499 Position commentX = -1, commentY = -1;
500 Dimension commentW, commentH;
501 typedef unsigned int BoardSize;
503 Boolean chessProgram;
505 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
506 int squareSize, smallLayout = 0, tinyLayout = 0,
507 marginW, marginH, // [HGM] for run-time resizing
508 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
509 ICSInputBoxUp = False, askQuestionUp = False,
510 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
511 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
512 Pixel timerForegroundPixel, timerBackgroundPixel;
513 Pixel buttonForegroundPixel, buttonBackgroundPixel;
514 char *chessDir, *programName, *programVersion,
515 *gameCopyFilename, *gamePasteFilename;
516 Boolean alwaysOnTop = False;
517 Boolean saveSettingsOnExit;
518 char *settingsFileName;
519 char *icsTextMenuString;
521 char *firstChessProgramNames;
522 char *secondChessProgramNames;
524 WindowPlacement wpMain;
525 WindowPlacement wpConsole;
526 WindowPlacement wpComment;
527 WindowPlacement wpMoveHistory;
528 WindowPlacement wpEvalGraph;
529 WindowPlacement wpEngineOutput;
530 WindowPlacement wpGameList;
531 WindowPlacement wpTags;
535 Pixmap pieceBitmap[2][(int)BlackPawn];
536 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
537 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
538 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
539 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
540 int useImages, useImageSqs;
541 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
542 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
543 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
544 XImage *ximLightSquare, *ximDarkSquare;
547 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
548 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
550 #define White(piece) ((int)(piece) < (int)BlackPawn)
552 /* Variables for doing smooth animation. This whole thing
553 would be much easier if the board was double-buffered,
554 but that would require a fairly major rewrite. */
559 GC blitGC, pieceGC, outlineGC;
560 XPoint startSquare, prevFrame, mouseDelta;
564 int startBoardX, startBoardY;
567 /* There can be two pieces being animated at once: a player
568 can begin dragging a piece before the remote opponent has moved. */
570 static AnimState game, player;
572 /* Bitmaps for use as masks when drawing XPM pieces.
573 Need one for each black and white piece. */
574 static Pixmap xpmMask[BlackKing + 1];
576 /* This magic number is the number of intermediate frames used
577 in each half of the animation. For short moves it's reduced
578 by 1. The total number of frames will be factor * 2 + 1. */
581 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
583 MenuItem fileMenu[] = {
584 {N_("New Game"), ResetProc},
585 {N_("New Shuffle Game ..."), ShuffleMenuProc},
586 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
587 {"----", NothingProc},
588 {N_("Load Game"), LoadGameProc},
589 {N_("Load Next Game"), LoadNextGameProc},
590 {N_("Load Previous Game"), LoadPrevGameProc},
591 {N_("Reload Same Game"), ReloadGameProc},
592 {N_("Save Game"), SaveGameProc},
593 {"----", NothingProc},
594 {N_("Copy Game"), CopyGameProc},
595 {N_("Paste Game"), PasteGameProc},
596 {"----", NothingProc},
597 {N_("Load Position"), LoadPositionProc},
598 {N_("Load Next Position"), LoadNextPositionProc},
599 {N_("Load Previous Position"), LoadPrevPositionProc},
600 {N_("Reload Same Position"), ReloadPositionProc},
601 {N_("Save Position"), SavePositionProc},
602 {"----", NothingProc},
603 {N_("Copy Position"), CopyPositionProc},
604 {N_("Paste Position"), PastePositionProc},
605 {"----", NothingProc},
606 {N_("Mail Move"), MailMoveProc},
607 {N_("Reload CMail Message"), ReloadCmailMsgProc},
608 {"----", NothingProc},
609 {N_("Exit"), QuitProc},
613 MenuItem modeMenu[] = {
614 {N_("Machine White"), MachineWhiteProc},
615 {N_("Machine Black"), MachineBlackProc},
616 {N_("Two Machines"), TwoMachinesProc},
617 {N_("Analysis Mode"), AnalyzeModeProc},
618 {N_("Analyze File"), AnalyzeFileProc },
619 {N_("ICS Client"), IcsClientProc},
620 {N_("Edit Game"), EditGameProc},
621 {N_("Edit Position"), EditPositionProc},
622 {N_("Training"), TrainingProc},
623 {"----", NothingProc},
624 {N_("Show Engine Output"), EngineOutputProc},
625 {N_("Show Evaluation Graph"), EvalGraphProc},
626 {N_("Show Game List"), ShowGameListProc},
627 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
628 {"----", NothingProc},
629 {N_("Edit Tags"), EditTagsProc},
630 {N_("Edit Comment"), EditCommentProc},
631 {N_("ICS Input Box"), IcsInputBoxProc},
632 {N_("Pause"), PauseProc},
636 MenuItem actionMenu[] = {
637 {N_("Accept"), AcceptProc},
638 {N_("Decline"), DeclineProc},
639 {N_("Rematch"), RematchProc},
640 {"----", NothingProc},
641 {N_("Call Flag"), CallFlagProc},
642 {N_("Draw"), DrawProc},
643 {N_("Adjourn"), AdjournProc},
644 {N_("Abort"), AbortProc},
645 {N_("Resign"), ResignProc},
646 {"----", NothingProc},
647 {N_("Stop Observing"), StopObservingProc},
648 {N_("Stop Examining"), StopExaminingProc},
649 {N_("Upload to Examine"), UploadProc},
650 {"----", NothingProc},
651 {N_("Adjudicate to White"), AdjuWhiteProc},
652 {N_("Adjudicate to Black"), AdjuBlackProc},
653 {N_("Adjudicate Draw"), AdjuDrawProc},
657 MenuItem stepMenu[] = {
658 {N_("Backward"), BackwardProc},
659 {N_("Forward"), ForwardProc},
660 {N_("Back to Start"), ToStartProc},
661 {N_("Forward to End"), ToEndProc},
662 {N_("Revert"), RevertProc},
663 {N_("Annotate"), AnnotateProc},
664 {N_("Truncate Game"), TruncateGameProc},
665 {"----", NothingProc},
666 {N_("Move Now"), MoveNowProc},
667 {N_("Retract Move"), RetractMoveProc},
671 MenuItem optionsMenu[] = {
672 {N_("Flip View"), FlipViewProc},
673 {"----", NothingProc},
674 {N_("Adjudications ..."), EngineMenuProc},
675 {N_("General Settings ..."), UciMenuProc},
676 {N_("Engine #1 Settings ..."), FirstSettingsProc},
677 {N_("Engine #2 Settings ..."), SecondSettingsProc},
678 {N_("Time Control ..."), TimeControlProc},
679 {N_("Game List ..."), GameListOptionsPopUp},
680 {"----", NothingProc},
681 {N_("Always Queen"), AlwaysQueenProc},
682 {N_("Animate Dragging"), AnimateDraggingProc},
683 {N_("Animate Moving"), AnimateMovingProc},
684 {N_("Auto Comment"), AutocommProc},
685 {N_("Auto Flag"), AutoflagProc},
686 {N_("Auto Flip View"), AutoflipProc},
687 {N_("Auto Observe"), AutobsProc},
688 {N_("Auto Raise Board"), AutoraiseProc},
689 {N_("Auto Save"), AutosaveProc},
690 {N_("Blindfold"), BlindfoldProc},
691 {N_("Flash Moves"), FlashMovesProc},
692 {N_("Get Move List"), GetMoveListProc},
694 {N_("Highlight Dragging"), HighlightDraggingProc},
696 {N_("Highlight Last Move"), HighlightLastMoveProc},
697 {N_("Move Sound"), MoveSoundProc},
698 {N_("ICS Alarm"), IcsAlarmProc},
699 {N_("Old Save Style"), OldSaveStyleProc},
700 {N_("Periodic Updates"), PeriodicUpdatesProc},
701 {N_("Ponder Next Move"), PonderNextMoveProc},
702 {N_("Popup Exit Message"), PopupExitMessageProc},
703 {N_("Popup Move Errors"), PopupMoveErrorsProc},
704 {N_("Premove"), PremoveProc},
705 {N_("Quiet Play"), QuietPlayProc},
706 {N_("Show Coords"), ShowCoordsProc},
707 {N_("Hide Thinking"), HideThinkingProc},
708 {N_("Test Legality"), TestLegalityProc},
709 {"----", NothingProc},
710 {N_("Save Settings Now"), SaveSettingsProc},
711 {N_("Save Settings on Exit"), SaveOnExitProc},
715 MenuItem helpMenu[] = {
716 {N_("Info XBoard"), InfoProc},
717 {N_("Man XBoard"), ManProc},
718 {"----", NothingProc},
719 {N_("Hint"), HintProc},
720 {N_("Book"), BookProc},
721 {"----", NothingProc},
722 {N_("About XBoard"), AboutProc},
727 {N_("File"), fileMenu},
728 {N_("Mode"), modeMenu},
729 {N_("Action"), actionMenu},
730 {N_("Step"), stepMenu},
731 {N_("Options"), optionsMenu},
732 {N_("Help"), helpMenu},
736 #define PAUSE_BUTTON N_("P")
737 MenuItem buttonBar[] = {
740 {PAUSE_BUTTON, PauseProc},
746 #define PIECE_MENU_SIZE 18
747 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
748 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
749 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
750 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
751 N_("Empty square"), N_("Clear board") },
752 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
753 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
754 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
755 N_("Empty square"), N_("Clear board") }
757 /* must be in same order as PieceMenuStrings! */
758 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
759 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
760 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
761 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
762 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
763 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
764 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
765 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
766 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
769 #define DROP_MENU_SIZE 6
770 String dropMenuStrings[DROP_MENU_SIZE] = {
771 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
773 /* must be in same order as PieceMenuStrings! */
774 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
775 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
776 WhiteRook, WhiteQueen
784 DropMenuEnables dmEnables[] = {
802 { XtNborderWidth, 0 },
803 { XtNdefaultDistance, 0 },
807 { XtNborderWidth, 0 },
808 { XtNresizable, (XtArgVal) True },
812 { XtNborderWidth, 0 },
818 { XtNjustify, (XtArgVal) XtJustifyRight },
819 { XtNlabel, (XtArgVal) "..." },
820 { XtNresizable, (XtArgVal) True },
821 { XtNresize, (XtArgVal) False }
824 Arg messageArgs[] = {
825 { XtNjustify, (XtArgVal) XtJustifyLeft },
826 { XtNlabel, (XtArgVal) "..." },
827 { XtNresizable, (XtArgVal) True },
828 { XtNresize, (XtArgVal) False }
832 { XtNborderWidth, 0 },
833 { XtNjustify, (XtArgVal) XtJustifyLeft }
836 XtResource clientResources[] = {
837 { "flashCount", "flashCount", XtRInt, sizeof(int),
838 XtOffset(AppDataPtr, flashCount), XtRImmediate,
839 (XtPointer) FLASH_COUNT },
842 XrmOptionDescRec shellOptions[] = {
843 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
844 { "-flash", "flashCount", XrmoptionNoArg, "3" },
845 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
848 XtActionsRec boardActions[] = {
849 { "DrawPosition", DrawPositionProc },
850 { "HandleUserMove", HandleUserMove },
851 { "AnimateUserMove", AnimateUserMove },
852 { "HandlePV", HandlePV },
853 { "UnLoadPV", UnLoadPV },
854 { "FileNameAction", FileNameAction },
855 { "AskQuestionProc", AskQuestionProc },
856 { "AskQuestionReplyAction", AskQuestionReplyAction },
857 { "PieceMenuPopup", PieceMenuPopup },
858 { "WhiteClock", WhiteClock },
859 { "BlackClock", BlackClock },
860 { "Iconify", Iconify },
861 { "ResetProc", ResetProc },
862 { "LoadGameProc", LoadGameProc },
863 { "LoadNextGameProc", LoadNextGameProc },
864 { "LoadPrevGameProc", LoadPrevGameProc },
865 { "LoadSelectedProc", LoadSelectedProc },
866 { "SetFilterProc", SetFilterProc },
867 { "ReloadGameProc", ReloadGameProc },
868 { "LoadPositionProc", LoadPositionProc },
869 { "LoadNextPositionProc", LoadNextPositionProc },
870 { "LoadPrevPositionProc", LoadPrevPositionProc },
871 { "ReloadPositionProc", ReloadPositionProc },
872 { "CopyPositionProc", CopyPositionProc },
873 { "PastePositionProc", PastePositionProc },
874 { "CopyGameProc", CopyGameProc },
875 { "PasteGameProc", PasteGameProc },
876 { "SaveGameProc", SaveGameProc },
877 { "SavePositionProc", SavePositionProc },
878 { "MailMoveProc", MailMoveProc },
879 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
880 { "QuitProc", QuitProc },
881 { "MachineWhiteProc", MachineWhiteProc },
882 { "MachineBlackProc", MachineBlackProc },
883 { "AnalysisModeProc", AnalyzeModeProc },
884 { "AnalyzeFileProc", AnalyzeFileProc },
885 { "TwoMachinesProc", TwoMachinesProc },
886 { "IcsClientProc", IcsClientProc },
887 { "EditGameProc", EditGameProc },
888 { "EditPositionProc", EditPositionProc },
889 { "TrainingProc", EditPositionProc },
890 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
891 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
892 { "ShowGameListProc", ShowGameListProc },
893 { "ShowMoveListProc", HistoryShowProc},
894 { "EditTagsProc", EditCommentProc },
895 { "EditCommentProc", EditCommentProc },
896 { "IcsAlarmProc", IcsAlarmProc },
897 { "IcsInputBoxProc", IcsInputBoxProc },
898 { "PauseProc", PauseProc },
899 { "AcceptProc", AcceptProc },
900 { "DeclineProc", DeclineProc },
901 { "RematchProc", RematchProc },
902 { "CallFlagProc", CallFlagProc },
903 { "DrawProc", DrawProc },
904 { "AdjournProc", AdjournProc },
905 { "AbortProc", AbortProc },
906 { "ResignProc", ResignProc },
907 { "AdjuWhiteProc", AdjuWhiteProc },
908 { "AdjuBlackProc", AdjuBlackProc },
909 { "AdjuDrawProc", AdjuDrawProc },
910 { "EnterKeyProc", EnterKeyProc },
911 { "UpKeyProc", UpKeyProc },
912 { "DownKeyProc", DownKeyProc },
913 { "StopObservingProc", StopObservingProc },
914 { "StopExaminingProc", StopExaminingProc },
915 { "UploadProc", UploadProc },
916 { "BackwardProc", BackwardProc },
917 { "ForwardProc", ForwardProc },
918 { "ToStartProc", ToStartProc },
919 { "ToEndProc", ToEndProc },
920 { "RevertProc", RevertProc },
921 { "AnnotateProc", AnnotateProc },
922 { "TruncateGameProc", TruncateGameProc },
923 { "MoveNowProc", MoveNowProc },
924 { "RetractMoveProc", RetractMoveProc },
925 { "AlwaysQueenProc", AlwaysQueenProc },
926 { "AnimateDraggingProc", AnimateDraggingProc },
927 { "AnimateMovingProc", AnimateMovingProc },
928 { "AutoflagProc", AutoflagProc },
929 { "AutoflipProc", AutoflipProc },
930 { "AutobsProc", AutobsProc },
931 { "AutoraiseProc", AutoraiseProc },
932 { "AutosaveProc", AutosaveProc },
933 { "BlindfoldProc", BlindfoldProc },
934 { "FlashMovesProc", FlashMovesProc },
935 { "FlipViewProc", FlipViewProc },
936 { "GetMoveListProc", GetMoveListProc },
938 { "HighlightDraggingProc", HighlightDraggingProc },
940 { "HighlightLastMoveProc", HighlightLastMoveProc },
941 { "IcsAlarmProc", IcsAlarmProc },
942 { "MoveSoundProc", MoveSoundProc },
943 { "OldSaveStyleProc", OldSaveStyleProc },
944 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
945 { "PonderNextMoveProc", PonderNextMoveProc },
946 { "PopupExitMessageProc", PopupExitMessageProc },
947 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
948 { "PremoveProc", PremoveProc },
949 { "QuietPlayProc", QuietPlayProc },
950 { "ShowCoordsProc", ShowCoordsProc },
951 { "ShowThinkingProc", ShowThinkingProc },
952 { "HideThinkingProc", HideThinkingProc },
953 { "TestLegalityProc", TestLegalityProc },
954 { "SaveSettingsProc", SaveSettingsProc },
955 { "SaveOnExitProc", SaveOnExitProc },
956 { "InfoProc", InfoProc },
957 { "ManProc", ManProc },
958 { "HintProc", HintProc },
959 { "BookProc", BookProc },
960 { "AboutGameProc", AboutGameProc },
961 { "AboutProc", AboutProc },
962 { "DebugProc", DebugProc },
963 { "NothingProc", NothingProc },
964 { "CommentPopDown", (XtActionProc) CommentPopDown },
965 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
966 { "TagsPopDown", (XtActionProc) TagsPopDown },
967 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
968 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
969 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
970 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
971 { "GameListPopDown", (XtActionProc) GameListPopDown },
972 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
973 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
974 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
975 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
976 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
977 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
978 { "EnginePopDown", (XtActionProc) EnginePopDown },
979 { "UciPopDown", (XtActionProc) UciPopDown },
980 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
981 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
982 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
983 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
986 char globalTranslations[] =
987 ":<Key>R: ResignProc() \n \
988 :<Key>r: ResetProc() \n \
989 :<Key>g: LoadGameProc() \n \
990 :<Key>N: LoadNextGameProc() \n \
991 :<Key>P: LoadPrevGameProc() \n \
992 :<Key>Q: QuitProc() \n \
993 :<Key>F: ToEndProc() \n \
994 :<Key>f: ForwardProc() \n \
995 :<Key>B: ToStartProc() \n \
996 :<Key>b: BackwardProc() \n \
997 :<Key>p: PauseProc() \n \
998 :<Key>d: DrawProc() \n \
999 :<Key>t: CallFlagProc() \n \
1000 :<Key>i: Iconify() \n \
1001 :<Key>c: Iconify() \n \
1002 :<Key>v: FlipViewProc() \n \
1003 <KeyDown>Control_L: BackwardProc() \n \
1004 <KeyUp>Control_L: ForwardProc() \n \
1005 <KeyDown>Control_R: BackwardProc() \n \
1006 <KeyUp>Control_R: ForwardProc() \n \
1007 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1008 \"Send to chess program:\",,1) \n \
1009 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1010 \"Send to second chess program:\",,2) \n";
1012 char boardTranslations[] =
1013 "<Btn1Down>: HandleUserMove() \n \
1014 <Btn1Up>: HandleUserMove() \n \
1015 <Btn1Motion>: AnimateUserMove() \n \
1016 <Btn3Motion>: HandlePV() \n \
1017 <Btn3Up>: PieceMenuPopup(menuB) \n \
1018 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1019 PieceMenuPopup(menuB) \n \
1020 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1021 PieceMenuPopup(menuW) \n \
1022 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1023 PieceMenuPopup(menuW) \n \
1024 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1025 PieceMenuPopup(menuB) \n";
1027 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1028 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1030 char ICSInputTranslations[] =
1031 "<Key>Up: UpKeyProc() \n "
1032 "<Key>Down: DownKeyProc() \n "
1033 "<Key>Return: EnterKeyProc() \n";
1035 String xboardResources[] = {
1036 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1037 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1038 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1043 /* Max possible square size */
1044 #define MAXSQSIZE 256
1046 static int xpm_avail[MAXSQSIZE];
1048 #ifdef HAVE_DIR_STRUCT
1050 /* Extract piece size from filename */
1052 xpm_getsize(name, len, ext)
1063 if ((p=strchr(name, '.')) == NULL ||
1064 StrCaseCmp(p+1, ext) != 0)
1070 while (*p && isdigit(*p))
1077 /* Setup xpm_avail */
1079 xpm_getavail(dirname, ext)
1087 for (i=0; i<MAXSQSIZE; ++i)
1090 if (appData.debugMode)
1091 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1093 dir = opendir(dirname);
1096 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1097 programName, dirname);
1101 while ((ent=readdir(dir)) != NULL) {
1102 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1103 if (i > 0 && i < MAXSQSIZE)
1113 xpm_print_avail(fp, ext)
1119 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1120 for (i=1; i<MAXSQSIZE; ++i) {
1126 /* Return XPM piecesize closest to size */
1128 xpm_closest_to(dirname, size, ext)
1134 int sm_diff = MAXSQSIZE;
1138 xpm_getavail(dirname, ext);
1140 if (appData.debugMode)
1141 xpm_print_avail(stderr, ext);
1143 for (i=1; i<MAXSQSIZE; ++i) {
1146 diff = (diff<0) ? -diff : diff;
1147 if (diff < sm_diff) {
1155 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1161 #else /* !HAVE_DIR_STRUCT */
1162 /* If we are on a system without a DIR struct, we can't
1163 read the directory, so we can't collect a list of
1164 filenames, etc., so we can't do any size-fitting. */
1166 xpm_closest_to(dirname, size, ext)
1171 fprintf(stderr, _("\
1172 Warning: No DIR structure found on this system --\n\
1173 Unable to autosize for XPM/XIM pieces.\n\
1174 Please report this error to frankm@hiwaay.net.\n\
1175 Include system type & operating system in message.\n"));
1178 #endif /* HAVE_DIR_STRUCT */
1180 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1181 "magenta", "cyan", "white" };
1185 TextColors textColors[(int)NColorClasses];
1187 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1189 parse_color(str, which)
1193 char *p, buf[100], *d;
1196 if (strlen(str) > 99) /* watch bounds on buf */
1201 for (i=0; i<which; ++i) {
1208 /* Could be looking at something like:
1210 .. in which case we want to stop on a comma also */
1211 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1215 return -1; /* Use default for empty field */
1218 if (which == 2 || isdigit(*p))
1221 while (*p && isalpha(*p))
1226 for (i=0; i<8; ++i) {
1227 if (!StrCaseCmp(buf, cnames[i]))
1228 return which? (i+40) : (i+30);
1230 if (!StrCaseCmp(buf, "default")) return -1;
1232 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1237 parse_cpair(cc, str)
1241 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1242 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1247 /* bg and attr are optional */
1248 textColors[(int)cc].bg = parse_color(str, 1);
1249 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1250 textColors[(int)cc].attr = 0;
1256 /* Arrange to catch delete-window events */
1257 Atom wm_delete_window;
1259 CatchDeleteWindow(Widget w, String procname)
1262 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1263 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1264 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1271 XtSetArg(args[0], XtNiconic, False);
1272 XtSetValues(shellWidget, args, 1);
1274 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1277 //---------------------------------------------------------------------------------------------------------
1278 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1281 #define CW_USEDEFAULT (1<<31)
1282 #define ICS_TEXT_MENU_SIZE 90
1283 #define DEBUG_FILE "xboard.debug"
1284 #define SetCurrentDirectory chdir
1285 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1289 // these two must some day move to frontend.h, when they are implemented
1290 Boolean GameListIsUp();
1292 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1295 // front-end part of option handling
1297 // [HGM] This platform-dependent table provides the location for storing the color info
1298 extern char *crWhite, * crBlack;
1302 &appData.whitePieceColor,
1303 &appData.blackPieceColor,
1304 &appData.lightSquareColor,
1305 &appData.darkSquareColor,
1306 &appData.highlightSquareColor,
1307 &appData.premoveHighlightColor,
1308 &appData.lowTimeWarningColor,
1319 // [HGM] font: keep a font for each square size, even non-stndard ones
1320 #define NUM_SIZES 18
1321 #define MAX_SIZE 130
1322 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1323 char *fontTable[NUM_FONTS][MAX_SIZE];
1326 ParseFont(char *name, int number)
1327 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1329 if(sscanf(name, "size%d:", &size)) {
1330 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1331 // defer processing it until we know if it matches our board size
1332 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1333 fontTable[number][size] = strdup(strchr(name, ':')+1);
1334 fontValid[number][size] = True;
1339 case 0: // CLOCK_FONT
1340 appData.clockFont = strdup(name);
1342 case 1: // MESSAGE_FONT
1343 appData.font = strdup(name);
1345 case 2: // COORD_FONT
1346 appData.coordFont = strdup(name);
1351 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1356 { // only 2 fonts currently
1357 appData.clockFont = CLOCK_FONT_NAME;
1358 appData.coordFont = COORD_FONT_NAME;
1359 appData.font = DEFAULT_FONT_NAME;
1364 { // no-op, until we identify the code for this already in XBoard and move it here
1368 ParseColor(int n, char *name)
1369 { // in XBoard, just copy the color-name string
1370 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1374 ParseTextAttribs(ColorClass cc, char *s)
1376 (&appData.colorShout)[cc] = strdup(s);
1380 ParseBoardSize(void *addr, char *name)
1382 appData.boardSize = strdup(name);
1387 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1391 SetCommPortDefaults()
1392 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1395 // [HGM] args: these three cases taken out to stay in front-end
1397 SaveFontArg(FILE *f, ArgDescriptor *ad)
1399 char *name, buf[MSG_SIZ];
1400 int i, n = (int)ad->argLoc;
1402 case 0: // CLOCK_FONT
1403 name = appData.clockFont;
1405 case 1: // MESSAGE_FONT
1406 name = appData.font;
1408 case 2: // COORD_FONT
1409 name = appData.coordFont;
1414 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1415 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1416 fontTable[n][squareSize] = strdup(name);
1417 fontValid[n][squareSize] = True;
1420 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1421 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1426 { // nothing to do, as the sounds are at all times represented by their text-string names already
1430 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1431 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1432 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1436 SaveColor(FILE *f, ArgDescriptor *ad)
1437 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1438 if(colorVariable[(int)ad->argLoc])
1439 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1443 SaveBoardSize(FILE *f, char *name, void *addr)
1444 { // wrapper to shield back-end from BoardSize & sizeInfo
1445 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1449 ParseCommPortSettings(char *s)
1450 { // no such option in XBoard (yet)
1453 extern Widget engineOutputShell;
1454 extern Widget tagsShell, editTagsShell;
1456 GetActualPlacement(Widget wg, WindowPlacement *wp)
1466 XtSetArg(args[i], XtNx, &x); i++;
1467 XtSetArg(args[i], XtNy, &y); i++;
1468 XtSetArg(args[i], XtNwidth, &w); i++;
1469 XtSetArg(args[i], XtNheight, &h); i++;
1470 XtGetValues(wg, args, i);
1479 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1480 // In XBoard this will have to wait until awareness of window parameters is implemented
1481 GetActualPlacement(shellWidget, &wpMain);
1482 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1483 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1484 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1485 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1486 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1487 else GetActualPlacement(editShell, &wpComment);
1488 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1489 else GetActualPlacement(editTagsShell, &wpTags);
1493 PrintCommPortSettings(FILE *f, char *name)
1494 { // This option does not exist in XBoard
1498 MySearchPath(char *installDir, char *name, char *fullname)
1499 { // just append installDir and name. Perhaps ExpandPath should be used here?
1500 name = ExpandPathName(name);
1501 if(name && name[0] == '/') strcpy(fullname, name); else {
1502 sprintf(fullname, "%s%c%s", installDir, '/', name);
1508 MyGetFullPathName(char *name, char *fullname)
1509 { // should use ExpandPath?
1510 name = ExpandPathName(name);
1511 strcpy(fullname, name);
1516 EnsureOnScreen(int *x, int *y, int minX, int minY)
1523 { // [HGM] args: allows testing if main window is realized from back-end
1524 return xBoardWindow != 0;
1528 PopUpStartupDialog()
1529 { // start menu not implemented in XBoard
1532 ConvertToLine(int argc, char **argv)
1534 static char line[128*1024], buf[1024];
1538 for(i=1; i<argc; i++) {
1539 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1540 && argv[i][0] != '{' )
1541 sprintf(buf, "{%s} ", argv[i]);
1542 else sprintf(buf, "%s ", argv[i]);
1545 line[strlen(line)-1] = NULLCHAR;
1549 //--------------------------------------------------------------------------------------------
1551 extern Boolean twoBoards, partnerUp;
1554 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1556 #define BoardSize int
1557 void InitDrawingSizes(BoardSize boardSize, int flags)
1558 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1559 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1561 XtGeometryResult gres;
1564 if(!formWidget) return;
1567 * Enable shell resizing.
1569 shellArgs[0].value = (XtArgVal) &w;
1570 shellArgs[1].value = (XtArgVal) &h;
1571 XtGetValues(shellWidget, shellArgs, 2);
1573 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1574 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1575 XtSetValues(shellWidget, &shellArgs[2], 4);
1577 XtSetArg(args[0], XtNdefaultDistance, &sep);
1578 XtGetValues(formWidget, args, 1);
1580 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1581 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1583 hOffset = boardWidth + 10;
1584 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1585 secondSegments[i] = gridSegments[i];
1586 secondSegments[i].x1 += hOffset;
1587 secondSegments[i].x2 += hOffset;
1590 XtSetArg(args[0], XtNwidth, boardWidth);
1591 XtSetArg(args[1], XtNheight, boardHeight);
1592 XtSetValues(boardWidget, args, 2);
1594 timerWidth = (boardWidth - sep) / 2;
1595 XtSetArg(args[0], XtNwidth, timerWidth);
1596 XtSetValues(whiteTimerWidget, args, 1);
1597 XtSetValues(blackTimerWidget, args, 1);
1599 XawFormDoLayout(formWidget, False);
1601 if (appData.titleInWindow) {
1603 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1604 XtSetArg(args[i], XtNheight, &h); i++;
1605 XtGetValues(titleWidget, args, i);
1607 w = boardWidth - 2*bor;
1609 XtSetArg(args[0], XtNwidth, &w);
1610 XtGetValues(menuBarWidget, args, 1);
1611 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1614 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1615 if (gres != XtGeometryYes && appData.debugMode) {
1617 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1618 programName, gres, w, h, wr, hr);
1622 XawFormDoLayout(formWidget, True);
1625 * Inhibit shell resizing.
1627 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1628 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1629 shellArgs[4].value = shellArgs[2].value = w;
1630 shellArgs[5].value = shellArgs[3].value = h;
1631 XtSetValues(shellWidget, &shellArgs[0], 6);
1633 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1636 for(i=0; i<4; i++) {
1638 for(p=0; p<=(int)WhiteKing; p++)
1639 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1640 if(gameInfo.variant == VariantShogi) {
1641 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1642 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1643 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1644 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1645 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1648 if(gameInfo.variant == VariantGothic) {
1649 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1653 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1654 for(p=0; p<=(int)WhiteKing; p++)
1655 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1656 if(gameInfo.variant == VariantShogi) {
1657 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1658 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1659 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1660 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1661 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1664 if(gameInfo.variant == VariantGothic) {
1665 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1671 for(i=0; i<2; i++) {
1673 for(p=0; p<=(int)WhiteKing; p++)
1674 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1675 if(gameInfo.variant == VariantShogi) {
1676 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1677 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1678 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1679 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1680 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1683 if(gameInfo.variant == VariantGothic) {
1684 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1695 void EscapeExpand(char *p, char *q)
1696 { // [HGM] initstring: routine to shape up string arguments
1697 while(*p++ = *q++) if(p[-1] == '\\')
1699 case 'n': p[-1] = '\n'; break;
1700 case 'r': p[-1] = '\r'; break;
1701 case 't': p[-1] = '\t'; break;
1702 case '\\': p[-1] = '\\'; break;
1703 case 0: *p = 0; return;
1704 default: p[-1] = q[-1]; break;
1713 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1714 XSetWindowAttributes window_attributes;
1716 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1717 XrmValue vFrom, vTo;
1718 XtGeometryResult gres;
1721 int forceMono = False;
1723 srandom(time(0)); // [HGM] book: make random truly random
1725 setbuf(stdout, NULL);
1726 setbuf(stderr, NULL);
1729 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1730 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1734 programName = strrchr(argv[0], '/');
1735 if (programName == NULL)
1736 programName = argv[0];
1741 XtSetLanguageProc(NULL, NULL, NULL);
1742 bindtextdomain(PACKAGE, LOCALEDIR);
1743 textdomain(PACKAGE);
1747 XtAppInitialize(&appContext, "XBoard", shellOptions,
1748 XtNumber(shellOptions),
1749 &argc, argv, xboardResources, NULL, 0);
1750 appData.boardSize = "";
1751 InitAppData(ConvertToLine(argc, argv));
1753 if (p == NULL) p = "/tmp";
1754 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1755 gameCopyFilename = (char*) malloc(i);
1756 gamePasteFilename = (char*) malloc(i);
1757 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1758 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1760 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1761 clientResources, XtNumber(clientResources),
1764 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1765 static char buf[MSG_SIZ];
1766 EscapeExpand(buf, appData.initString);
1767 appData.initString = strdup(buf);
1768 EscapeExpand(buf, appData.secondInitString);
1769 appData.secondInitString = strdup(buf);
1770 EscapeExpand(buf, appData.firstComputerString);
1771 appData.firstComputerString = strdup(buf);
1772 EscapeExpand(buf, appData.secondComputerString);
1773 appData.secondComputerString = strdup(buf);
1776 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1779 if (chdir(chessDir) != 0) {
1780 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1786 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1787 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1788 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1789 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1792 setbuf(debugFP, NULL);
1795 /* [HGM,HR] make sure board size is acceptable */
1796 if(appData.NrFiles > BOARD_FILES ||
1797 appData.NrRanks > BOARD_RANKS )
1798 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1801 /* This feature does not work; animation needs a rewrite */
1802 appData.highlightDragging = FALSE;
1806 xDisplay = XtDisplay(shellWidget);
1807 xScreen = DefaultScreen(xDisplay);
1808 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1810 gameInfo.variant = StringToVariant(appData.variant);
1811 InitPosition(FALSE);
1814 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1816 if (isdigit(appData.boardSize[0])) {
1817 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1818 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1819 &fontPxlSize, &smallLayout, &tinyLayout);
1821 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1822 programName, appData.boardSize);
1826 /* Find some defaults; use the nearest known size */
1827 SizeDefaults *szd, *nearest;
1828 int distance = 99999;
1829 nearest = szd = sizeDefaults;
1830 while (szd->name != NULL) {
1831 if (abs(szd->squareSize - squareSize) < distance) {
1833 distance = abs(szd->squareSize - squareSize);
1834 if (distance == 0) break;
1838 if (i < 2) lineGap = nearest->lineGap;
1839 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1840 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1841 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1842 if (i < 6) smallLayout = nearest->smallLayout;
1843 if (i < 7) tinyLayout = nearest->tinyLayout;
1846 SizeDefaults *szd = sizeDefaults;
1847 if (*appData.boardSize == NULLCHAR) {
1848 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1849 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1852 if (szd->name == NULL) szd--;
1853 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1855 while (szd->name != NULL &&
1856 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1857 if (szd->name == NULL) {
1858 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1859 programName, appData.boardSize);
1863 squareSize = szd->squareSize;
1864 lineGap = szd->lineGap;
1865 clockFontPxlSize = szd->clockFontPxlSize;
1866 coordFontPxlSize = szd->coordFontPxlSize;
1867 fontPxlSize = szd->fontPxlSize;
1868 smallLayout = szd->smallLayout;
1869 tinyLayout = szd->tinyLayout;
1870 // [HGM] font: use defaults from settings file if available and not overruled
1872 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1873 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1874 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1875 appData.font = fontTable[MESSAGE_FONT][squareSize];
1876 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1877 appData.coordFont = fontTable[COORD_FONT][squareSize];
1879 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1880 if (strlen(appData.pixmapDirectory) > 0) {
1881 p = ExpandPathName(appData.pixmapDirectory);
1883 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1884 appData.pixmapDirectory);
1887 if (appData.debugMode) {
1888 fprintf(stderr, _("\
1889 XBoard square size (hint): %d\n\
1890 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1892 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1893 if (appData.debugMode) {
1894 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1898 /* [HR] height treated separately (hacked) */
1899 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1900 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1901 if (appData.showJail == 1) {
1902 /* Jail on top and bottom */
1903 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1904 XtSetArg(boardArgs[2], XtNheight,
1905 boardHeight + 2*(lineGap + squareSize));
1906 } else if (appData.showJail == 2) {
1908 XtSetArg(boardArgs[1], XtNwidth,
1909 boardWidth + 2*(lineGap + squareSize));
1910 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1913 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1914 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1918 * Determine what fonts to use.
1920 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1921 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1922 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1923 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1924 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1925 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1926 appData.font = FindFont(appData.font, fontPxlSize);
1927 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1928 countFontStruct = XQueryFont(xDisplay, countFontID);
1929 // appData.font = FindFont(appData.font, fontPxlSize);
1931 xdb = XtDatabase(xDisplay);
1932 XrmPutStringResource(&xdb, "*font", appData.font);
1935 * Detect if there are not enough colors available and adapt.
1937 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1938 appData.monoMode = True;
1941 if (!appData.monoMode) {
1942 vFrom.addr = (caddr_t) appData.lightSquareColor;
1943 vFrom.size = strlen(appData.lightSquareColor);
1944 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1945 if (vTo.addr == NULL) {
1946 appData.monoMode = True;
1949 lightSquareColor = *(Pixel *) vTo.addr;
1952 if (!appData.monoMode) {
1953 vFrom.addr = (caddr_t) appData.darkSquareColor;
1954 vFrom.size = strlen(appData.darkSquareColor);
1955 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1956 if (vTo.addr == NULL) {
1957 appData.monoMode = True;
1960 darkSquareColor = *(Pixel *) vTo.addr;
1963 if (!appData.monoMode) {
1964 vFrom.addr = (caddr_t) appData.whitePieceColor;
1965 vFrom.size = strlen(appData.whitePieceColor);
1966 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1967 if (vTo.addr == NULL) {
1968 appData.monoMode = True;
1971 whitePieceColor = *(Pixel *) vTo.addr;
1974 if (!appData.monoMode) {
1975 vFrom.addr = (caddr_t) appData.blackPieceColor;
1976 vFrom.size = strlen(appData.blackPieceColor);
1977 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1978 if (vTo.addr == NULL) {
1979 appData.monoMode = True;
1982 blackPieceColor = *(Pixel *) vTo.addr;
1986 if (!appData.monoMode) {
1987 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1988 vFrom.size = strlen(appData.highlightSquareColor);
1989 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1990 if (vTo.addr == NULL) {
1991 appData.monoMode = True;
1994 highlightSquareColor = *(Pixel *) vTo.addr;
1998 if (!appData.monoMode) {
1999 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2000 vFrom.size = strlen(appData.premoveHighlightColor);
2001 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2002 if (vTo.addr == NULL) {
2003 appData.monoMode = True;
2006 premoveHighlightColor = *(Pixel *) vTo.addr;
2011 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2014 if (appData.bitmapDirectory == NULL ||
2015 appData.bitmapDirectory[0] == NULLCHAR)
2016 appData.bitmapDirectory = DEF_BITMAP_DIR;
2019 if (appData.lowTimeWarning && !appData.monoMode) {
2020 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2021 vFrom.size = strlen(appData.lowTimeWarningColor);
2022 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2023 if (vTo.addr == NULL)
2024 appData.monoMode = True;
2026 lowTimeWarningColor = *(Pixel *) vTo.addr;
2029 if (appData.monoMode && appData.debugMode) {
2030 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2031 (unsigned long) XWhitePixel(xDisplay, xScreen),
2032 (unsigned long) XBlackPixel(xDisplay, xScreen));
2035 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2036 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2037 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2038 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2039 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2040 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2041 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2042 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2043 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2044 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2046 if (appData.colorize) {
2048 _("%s: can't parse color names; disabling colorization\n"),
2051 appData.colorize = FALSE;
2053 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2054 textColors[ColorNone].attr = 0;
2056 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2062 layoutName = "tinyLayout";
2063 } else if (smallLayout) {
2064 layoutName = "smallLayout";
2066 layoutName = "normalLayout";
2068 /* Outer layoutWidget is there only to provide a name for use in
2069 resources that depend on the layout style */
2071 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2072 layoutArgs, XtNumber(layoutArgs));
2074 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2075 formArgs, XtNumber(formArgs));
2076 XtSetArg(args[0], XtNdefaultDistance, &sep);
2077 XtGetValues(formWidget, args, 1);
2080 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2081 XtSetArg(args[0], XtNtop, XtChainTop);
2082 XtSetArg(args[1], XtNbottom, XtChainTop);
2083 XtSetArg(args[2], XtNright, XtChainLeft);
2084 XtSetValues(menuBarWidget, args, 3);
2086 widgetList[j++] = whiteTimerWidget =
2087 XtCreateWidget("whiteTime", labelWidgetClass,
2088 formWidget, timerArgs, XtNumber(timerArgs));
2089 XtSetArg(args[0], XtNfont, clockFontStruct);
2090 XtSetArg(args[1], XtNtop, XtChainTop);
2091 XtSetArg(args[2], XtNbottom, XtChainTop);
2092 XtSetValues(whiteTimerWidget, args, 3);
2094 widgetList[j++] = blackTimerWidget =
2095 XtCreateWidget("blackTime", labelWidgetClass,
2096 formWidget, timerArgs, XtNumber(timerArgs));
2097 XtSetArg(args[0], XtNfont, clockFontStruct);
2098 XtSetArg(args[1], XtNtop, XtChainTop);
2099 XtSetArg(args[2], XtNbottom, XtChainTop);
2100 XtSetValues(blackTimerWidget, args, 3);
2102 if (appData.titleInWindow) {
2103 widgetList[j++] = titleWidget =
2104 XtCreateWidget("title", labelWidgetClass, formWidget,
2105 titleArgs, XtNumber(titleArgs));
2106 XtSetArg(args[0], XtNtop, XtChainTop);
2107 XtSetArg(args[1], XtNbottom, XtChainTop);
2108 XtSetValues(titleWidget, args, 2);
2111 if (appData.showButtonBar) {
2112 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2113 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2114 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2115 XtSetArg(args[2], XtNtop, XtChainTop);
2116 XtSetArg(args[3], XtNbottom, XtChainTop);
2117 XtSetValues(buttonBarWidget, args, 4);
2120 widgetList[j++] = messageWidget =
2121 XtCreateWidget("message", labelWidgetClass, formWidget,
2122 messageArgs, XtNumber(messageArgs));
2123 XtSetArg(args[0], XtNtop, XtChainTop);
2124 XtSetArg(args[1], XtNbottom, XtChainTop);
2125 XtSetValues(messageWidget, args, 2);
2127 widgetList[j++] = boardWidget =
2128 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2129 XtNumber(boardArgs));
2131 XtManageChildren(widgetList, j);
2133 timerWidth = (boardWidth - sep) / 2;
2134 XtSetArg(args[0], XtNwidth, timerWidth);
2135 XtSetValues(whiteTimerWidget, args, 1);
2136 XtSetValues(blackTimerWidget, args, 1);
2138 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2139 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2140 XtGetValues(whiteTimerWidget, args, 2);
2142 if (appData.showButtonBar) {
2143 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2144 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2145 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2149 * formWidget uses these constraints but they are stored
2153 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2154 XtSetValues(menuBarWidget, args, i);
2155 if (appData.titleInWindow) {
2158 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2159 XtSetValues(whiteTimerWidget, args, i);
2161 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2162 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2163 XtSetValues(blackTimerWidget, args, i);
2165 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2166 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2167 XtSetValues(titleWidget, args, i);
2169 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2170 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2171 XtSetValues(messageWidget, args, i);
2172 if (appData.showButtonBar) {
2174 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2175 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2176 XtSetValues(buttonBarWidget, args, i);
2180 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2181 XtSetValues(whiteTimerWidget, args, i);
2183 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2184 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2185 XtSetValues(blackTimerWidget, args, i);
2187 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2188 XtSetValues(titleWidget, args, i);
2190 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2191 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2192 XtSetValues(messageWidget, args, i);
2193 if (appData.showButtonBar) {
2195 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2196 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2197 XtSetValues(buttonBarWidget, args, i);
2202 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2203 XtSetValues(whiteTimerWidget, args, i);
2205 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2206 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2207 XtSetValues(blackTimerWidget, args, i);
2209 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2210 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2211 XtSetValues(messageWidget, args, i);
2212 if (appData.showButtonBar) {
2214 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2215 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2216 XtSetValues(buttonBarWidget, args, i);
2220 XtSetArg(args[0], XtNfromVert, messageWidget);
2221 XtSetArg(args[1], XtNtop, XtChainTop);
2222 XtSetArg(args[2], XtNbottom, XtChainBottom);
2223 XtSetArg(args[3], XtNleft, XtChainLeft);
2224 XtSetArg(args[4], XtNright, XtChainRight);
2225 XtSetValues(boardWidget, args, 5);
2227 XtRealizeWidget(shellWidget);
2230 XtSetArg(args[0], XtNx, wpMain.x);
2231 XtSetArg(args[1], XtNy, wpMain.y);
2232 XtSetValues(shellWidget, args, 2);
2236 * Correct the width of the message and title widgets.
2237 * It is not known why some systems need the extra fudge term.
2238 * The value "2" is probably larger than needed.
2240 XawFormDoLayout(formWidget, False);
2242 #define WIDTH_FUDGE 2
2244 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2245 XtSetArg(args[i], XtNheight, &h); i++;
2246 XtGetValues(messageWidget, args, i);
2247 if (appData.showButtonBar) {
2249 XtSetArg(args[i], XtNwidth, &w); i++;
2250 XtGetValues(buttonBarWidget, args, i);
2251 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2253 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2256 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2257 if (gres != XtGeometryYes && appData.debugMode) {
2258 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2259 programName, gres, w, h, wr, hr);
2262 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2263 /* The size used for the child widget in layout lags one resize behind
2264 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2266 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2267 if (gres != XtGeometryYes && appData.debugMode) {
2268 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2269 programName, gres, w, h, wr, hr);
2272 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2273 XtSetArg(args[1], XtNright, XtChainRight);
2274 XtSetValues(messageWidget, args, 2);
2276 if (appData.titleInWindow) {
2278 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2279 XtSetArg(args[i], XtNheight, &h); i++;
2280 XtGetValues(titleWidget, args, i);
2282 w = boardWidth - 2*bor;
2284 XtSetArg(args[0], XtNwidth, &w);
2285 XtGetValues(menuBarWidget, args, 1);
2286 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2289 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2290 if (gres != XtGeometryYes && appData.debugMode) {
2292 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2293 programName, gres, w, h, wr, hr);
2296 XawFormDoLayout(formWidget, True);
2298 xBoardWindow = XtWindow(boardWidget);
2300 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2301 // not need to go into InitDrawingSizes().
2305 * Create X checkmark bitmap and initialize option menu checks.
2307 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2308 checkmark_bits, checkmark_width, checkmark_height);
2309 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2310 if (appData.alwaysPromoteToQueen) {
2311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2314 if (appData.animateDragging) {
2315 XtSetValues(XtNameToWidget(menuBarWidget,
2316 "menuOptions.Animate Dragging"),
2319 if (appData.animate) {
2320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2323 if (appData.autoComment) {
2324 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2327 if (appData.autoCallFlag) {
2328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2331 if (appData.autoFlipView) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2335 if (appData.autoObserve) {
2336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2339 if (appData.autoRaiseBoard) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Auto Raise Board"), args, 1);
2343 if (appData.autoSaveGames) {
2344 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2347 if (appData.saveGameFile[0] != NULLCHAR) {
2348 /* Can't turn this off from menu */
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2351 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2355 if (appData.blindfold) {
2356 XtSetValues(XtNameToWidget(menuBarWidget,
2357 "menuOptions.Blindfold"), args, 1);
2359 if (appData.flashCount > 0) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,
2361 "menuOptions.Flash Moves"),
2364 if (appData.getMoveList) {
2365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2369 if (appData.highlightDragging) {
2370 XtSetValues(XtNameToWidget(menuBarWidget,
2371 "menuOptions.Highlight Dragging"),
2375 if (appData.highlightLastMove) {
2376 XtSetValues(XtNameToWidget(menuBarWidget,
2377 "menuOptions.Highlight Last Move"),
2380 if (appData.icsAlarm) {
2381 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2384 if (appData.ringBellAfterMoves) {
2385 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2388 if (appData.oldSaveStyle) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,
2390 "menuOptions.Old Save Style"), args, 1);
2392 if (appData.periodicUpdates) {
2393 XtSetValues(XtNameToWidget(menuBarWidget,
2394 "menuOptions.Periodic Updates"), args, 1);
2396 if (appData.ponderNextMove) {
2397 XtSetValues(XtNameToWidget(menuBarWidget,
2398 "menuOptions.Ponder Next Move"), args, 1);
2400 if (appData.popupExitMessage) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,
2402 "menuOptions.Popup Exit Message"), args, 1);
2404 if (appData.popupMoveErrors) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,
2406 "menuOptions.Popup Move Errors"), args, 1);
2408 if (appData.premove) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,
2410 "menuOptions.Premove"), args, 1);
2412 if (appData.quietPlay) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,
2414 "menuOptions.Quiet Play"), args, 1);
2416 if (appData.showCoords) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2420 if (appData.hideThinkingFromHuman) {
2421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2424 if (appData.testLegality) {
2425 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2428 if (saveSettingsOnExit) {
2429 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2436 ReadBitmap(&wIconPixmap, "icon_white.bm",
2437 icon_white_bits, icon_white_width, icon_white_height);
2438 ReadBitmap(&bIconPixmap, "icon_black.bm",
2439 icon_black_bits, icon_black_width, icon_black_height);
2440 iconPixmap = wIconPixmap;
2442 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2443 XtSetValues(shellWidget, args, i);
2446 * Create a cursor for the board widget.
2448 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2449 XChangeWindowAttributes(xDisplay, xBoardWindow,
2450 CWCursor, &window_attributes);
2453 * Inhibit shell resizing.
2455 shellArgs[0].value = (XtArgVal) &w;
2456 shellArgs[1].value = (XtArgVal) &h;
2457 XtGetValues(shellWidget, shellArgs, 2);
2458 shellArgs[4].value = shellArgs[2].value = w;
2459 shellArgs[5].value = shellArgs[3].value = h;
2460 XtSetValues(shellWidget, &shellArgs[2], 4);
2461 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2462 marginH = h - boardHeight;
2464 CatchDeleteWindow(shellWidget, "QuitProc");
2469 if (appData.bitmapDirectory[0] != NULLCHAR) {
2476 /* Create regular pieces */
2477 if (!useImages) CreatePieces();
2482 if (appData.animate || appData.animateDragging)
2485 XtAugmentTranslations(formWidget,
2486 XtParseTranslationTable(globalTranslations));
2487 XtAugmentTranslations(boardWidget,
2488 XtParseTranslationTable(boardTranslations));
2489 XtAugmentTranslations(whiteTimerWidget,
2490 XtParseTranslationTable(whiteTranslations));
2491 XtAugmentTranslations(blackTimerWidget,
2492 XtParseTranslationTable(blackTranslations));
2494 /* Why is the following needed on some versions of X instead
2495 * of a translation? */
2496 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2497 (XtEventHandler) EventProc, NULL);
2500 /* [AS] Restore layout */
2501 if( wpMoveHistory.visible ) {
2505 if( wpEvalGraph.visible )
2510 if( wpEngineOutput.visible ) {
2511 EngineOutputPopUp();
2516 if (errorExitStatus == -1) {
2517 if (appData.icsActive) {
2518 /* We now wait until we see "login:" from the ICS before
2519 sending the logon script (problems with timestamp otherwise) */
2520 /*ICSInitScript();*/
2521 if (appData.icsInputBox) ICSInputBoxPopUp();
2525 signal(SIGWINCH, TermSizeSigHandler);
2527 signal(SIGINT, IntSigHandler);
2528 signal(SIGTERM, IntSigHandler);
2529 if (*appData.cmailGameName != NULLCHAR) {
2530 signal(SIGUSR1, CmailSigHandler);
2533 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2536 XtAppMainLoop(appContext);
2537 if (appData.debugMode) fclose(debugFP); // [DM] debug
2544 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2545 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2547 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2548 unlink(gameCopyFilename);
2549 unlink(gamePasteFilename);
2552 RETSIGTYPE TermSizeSigHandler(int sig)
2565 CmailSigHandler(sig)
2571 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2573 /* Activate call-back function CmailSigHandlerCallBack() */
2574 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2576 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2580 CmailSigHandlerCallBack(isr, closure, message, count, error)
2588 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2590 /**** end signal code ****/
2600 f = fopen(appData.icsLogon, "r");
2606 strcat(buf, appData.icsLogon);
2607 f = fopen(buf, "r");
2611 ProcessICSInitScript(f);
2618 EditCommentPopDown();
2633 if (!menuBarWidget) return;
2634 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2636 DisplayError("menuStep.Revert", 0);
2638 XtSetSensitive(w, !grey);
2640 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2642 DisplayError("menuStep.Annotate", 0);
2644 XtSetSensitive(w, !grey);
2649 SetMenuEnables(enab)
2653 if (!menuBarWidget) return;
2654 while (enab->name != NULL) {
2655 w = XtNameToWidget(menuBarWidget, enab->name);
2657 DisplayError(enab->name, 0);
2659 XtSetSensitive(w, enab->value);
2665 Enables icsEnables[] = {
2666 { "menuFile.Mail Move", False },
2667 { "menuFile.Reload CMail Message", False },
2668 { "menuMode.Machine Black", False },
2669 { "menuMode.Machine White", False },
2670 { "menuMode.Analysis Mode", False },
2671 { "menuMode.Analyze File", False },
2672 { "menuMode.Two Machines", False },
2674 { "menuHelp.Hint", False },
2675 { "menuHelp.Book", False },
2676 { "menuStep.Move Now", False },
2677 { "menuOptions.Periodic Updates", False },
2678 { "menuOptions.Hide Thinking", False },
2679 { "menuOptions.Ponder Next Move", False },
2681 { "menuStep.Annotate", False },
2685 Enables ncpEnables[] = {
2686 { "menuFile.Mail Move", False },
2687 { "menuFile.Reload CMail Message", False },
2688 { "menuMode.Machine White", False },
2689 { "menuMode.Machine Black", False },
2690 { "menuMode.Analysis Mode", False },
2691 { "menuMode.Analyze File", False },
2692 { "menuMode.Two Machines", False },
2693 { "menuMode.ICS Client", False },
2694 { "menuMode.ICS Input Box", False },
2695 { "Action", False },
2696 { "menuStep.Revert", False },
2697 { "menuStep.Annotate", False },
2698 { "menuStep.Move Now", False },
2699 { "menuStep.Retract Move", False },
2700 { "menuOptions.Auto Comment", False },
2701 { "menuOptions.Auto Flag", False },
2702 { "menuOptions.Auto Flip View", False },
2703 { "menuOptions.Auto Observe", False },
2704 { "menuOptions.Auto Raise Board", False },
2705 { "menuOptions.Get Move List", False },
2706 { "menuOptions.ICS Alarm", False },
2707 { "menuOptions.Move Sound", False },
2708 { "menuOptions.Quiet Play", False },
2709 { "menuOptions.Hide Thinking", False },
2710 { "menuOptions.Periodic Updates", False },
2711 { "menuOptions.Ponder Next Move", False },
2712 { "menuHelp.Hint", False },
2713 { "menuHelp.Book", False },
2717 Enables gnuEnables[] = {
2718 { "menuMode.ICS Client", False },
2719 { "menuMode.ICS Input Box", False },
2720 { "menuAction.Accept", False },
2721 { "menuAction.Decline", False },
2722 { "menuAction.Rematch", False },
2723 { "menuAction.Adjourn", False },
2724 { "menuAction.Stop Examining", False },
2725 { "menuAction.Stop Observing", False },
2726 { "menuAction.Upload to Examine", False },
2727 { "menuStep.Revert", False },
2728 { "menuStep.Annotate", False },
2729 { "menuOptions.Auto Comment", False },
2730 { "menuOptions.Auto Observe", False },
2731 { "menuOptions.Auto Raise Board", False },
2732 { "menuOptions.Get Move List", False },
2733 { "menuOptions.Premove", False },
2734 { "menuOptions.Quiet Play", False },
2736 /* The next two options rely on SetCmailMode being called *after* */
2737 /* SetGNUMode so that when GNU is being used to give hints these */
2738 /* menu options are still available */
2740 { "menuFile.Mail Move", False },
2741 { "menuFile.Reload CMail Message", False },
2745 Enables cmailEnables[] = {
2747 { "menuAction.Call Flag", False },
2748 { "menuAction.Draw", True },
2749 { "menuAction.Adjourn", False },
2750 { "menuAction.Abort", False },
2751 { "menuAction.Stop Observing", False },
2752 { "menuAction.Stop Examining", False },
2753 { "menuFile.Mail Move", True },
2754 { "menuFile.Reload CMail Message", True },
2758 Enables trainingOnEnables[] = {
2759 { "menuMode.Edit Comment", False },
2760 { "menuMode.Pause", False },
2761 { "menuStep.Forward", False },
2762 { "menuStep.Backward", False },
2763 { "menuStep.Forward to End", False },
2764 { "menuStep.Back to Start", False },
2765 { "menuStep.Move Now", False },
2766 { "menuStep.Truncate Game", False },
2770 Enables trainingOffEnables[] = {
2771 { "menuMode.Edit Comment", True },
2772 { "menuMode.Pause", True },
2773 { "menuStep.Forward", True },
2774 { "menuStep.Backward", True },
2775 { "menuStep.Forward to End", True },
2776 { "menuStep.Back to Start", True },
2777 { "menuStep.Move Now", True },
2778 { "menuStep.Truncate Game", True },
2782 Enables machineThinkingEnables[] = {
2783 { "menuFile.Load Game", False },
2784 { "menuFile.Load Next Game", False },
2785 { "menuFile.Load Previous Game", False },
2786 { "menuFile.Reload Same Game", False },
2787 { "menuFile.Paste Game", False },
2788 { "menuFile.Load Position", False },
2789 { "menuFile.Load Next Position", False },
2790 { "menuFile.Load Previous Position", False },
2791 { "menuFile.Reload Same Position", False },
2792 { "menuFile.Paste Position", False },
2793 { "menuMode.Machine White", False },
2794 { "menuMode.Machine Black", False },
2795 { "menuMode.Two Machines", False },
2796 { "menuStep.Retract Move", False },
2800 Enables userThinkingEnables[] = {
2801 { "menuFile.Load Game", True },
2802 { "menuFile.Load Next Game", True },
2803 { "menuFile.Load Previous Game", True },
2804 { "menuFile.Reload Same Game", True },
2805 { "menuFile.Paste Game", True },
2806 { "menuFile.Load Position", True },
2807 { "menuFile.Load Next Position", True },
2808 { "menuFile.Load Previous Position", True },
2809 { "menuFile.Reload Same Position", True },
2810 { "menuFile.Paste Position", True },
2811 { "menuMode.Machine White", True },
2812 { "menuMode.Machine Black", True },
2813 { "menuMode.Two Machines", True },
2814 { "menuStep.Retract Move", True },
2820 SetMenuEnables(icsEnables);
2823 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2824 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2831 SetMenuEnables(ncpEnables);
2837 SetMenuEnables(gnuEnables);
2843 SetMenuEnables(cmailEnables);
2849 SetMenuEnables(trainingOnEnables);
2850 if (appData.showButtonBar) {
2851 XtSetSensitive(buttonBarWidget, False);
2857 SetTrainingModeOff()
2859 SetMenuEnables(trainingOffEnables);
2860 if (appData.showButtonBar) {
2861 XtSetSensitive(buttonBarWidget, True);
2866 SetUserThinkingEnables()
2868 if (appData.noChessProgram) return;
2869 SetMenuEnables(userThinkingEnables);
2873 SetMachineThinkingEnables()
2875 if (appData.noChessProgram) return;
2876 SetMenuEnables(machineThinkingEnables);
2878 case MachinePlaysBlack:
2879 case MachinePlaysWhite:
2880 case TwoMachinesPlay:
2881 XtSetSensitive(XtNameToWidget(menuBarWidget,
2882 ModeToWidgetName(gameMode)), True);
2889 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2890 #define HISTORY_SIZE 64
\r
2891 static char *history[HISTORY_SIZE];
\r
2892 int histIn = 0, histP = 0;
\r
2895 SaveInHistory(char *cmd)
\r
2897 if (history[histIn] != NULL) {
\r
2898 free(history[histIn]);
\r
2899 history[histIn] = NULL;
\r
2901 if (*cmd == NULLCHAR) return;
\r
2902 history[histIn] = StrSave(cmd);
\r
2903 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2904 if (history[histIn] != NULL) {
\r
2905 free(history[histIn]);
\r
2906 history[histIn] = NULL;
\r
2912 PrevInHistory(char *cmd)
\r
2915 if (histP == histIn) {
\r
2916 if (history[histIn] != NULL) free(history[histIn]);
\r
2917 history[histIn] = StrSave(cmd);
\r
2919 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2920 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2922 return history[histP];
\r
2928 if (histP == histIn) return NULL;
\r
2929 histP = (histP + 1) % HISTORY_SIZE;
\r
2930 return history[histP];
\r
2932 // end of borrowed code
\r
2934 #define Abs(n) ((n)<0 ? -(n) : (n))
2937 * Find a font that matches "pattern" that is as close as
2938 * possible to the targetPxlSize. Prefer fonts that are k
2939 * pixels smaller to fonts that are k pixels larger. The
2940 * pattern must be in the X Consortium standard format,
2941 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2942 * The return value should be freed with XtFree when no
2945 char *FindFont(pattern, targetPxlSize)
2949 char **fonts, *p, *best, *scalable, *scalableTail;
2950 int i, j, nfonts, minerr, err, pxlSize;
2953 char **missing_list;
2955 char *def_string, *base_fnt_lst, strInt[3];
2957 XFontStruct **fnt_list;
2959 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2960 sprintf(strInt, "%d", targetPxlSize);
2961 p = strstr(pattern, "--");
2962 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2963 strcat(base_fnt_lst, strInt);
2964 strcat(base_fnt_lst, strchr(p + 2, '-'));
2966 if ((fntSet = XCreateFontSet(xDisplay,
2970 &def_string)) == NULL) {
2972 fprintf(stderr, _("Unable to create font set.\n"));
2976 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2978 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2980 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2981 programName, pattern);
2989 for (i=0; i<nfonts; i++) {
2992 if (*p != '-') continue;
2994 if (*p == NULLCHAR) break;
2995 if (*p++ == '-') j++;
2997 if (j < 7) continue;
3000 scalable = fonts[i];
3003 err = pxlSize - targetPxlSize;
3004 if (Abs(err) < Abs(minerr) ||
3005 (minerr > 0 && err < 0 && -err == minerr)) {
3011 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3012 /* If the error is too big and there is a scalable font,
3013 use the scalable font. */
3014 int headlen = scalableTail - scalable;
3015 p = (char *) XtMalloc(strlen(scalable) + 10);
3016 while (isdigit(*scalableTail)) scalableTail++;
3017 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3019 p = (char *) XtMalloc(strlen(best) + 1);
3022 if (appData.debugMode) {
3023 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3024 pattern, targetPxlSize, p);
3027 if (missing_count > 0)
3028 XFreeStringList(missing_list);
3029 XFreeFontSet(xDisplay, fntSet);
3031 XFreeFontNames(fonts);
3038 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3039 | GCBackground | GCFunction | GCPlaneMask;
3040 XGCValues gc_values;
3043 gc_values.plane_mask = AllPlanes;
3044 gc_values.line_width = lineGap;
3045 gc_values.line_style = LineSolid;
3046 gc_values.function = GXcopy;
3048 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3049 gc_values.background = XBlackPixel(xDisplay, xScreen);
3050 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3052 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3053 gc_values.background = XWhitePixel(xDisplay, xScreen);
3054 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3055 XSetFont(xDisplay, coordGC, coordFontID);
3057 // [HGM] make font for holdings counts (white on black0
3058 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3059 gc_values.background = XBlackPixel(xDisplay, xScreen);
3060 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3061 XSetFont(xDisplay, countGC, countFontID);
3063 if (appData.monoMode) {
3064 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3065 gc_values.background = XWhitePixel(xDisplay, xScreen);
3066 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3068 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3069 gc_values.background = XBlackPixel(xDisplay, xScreen);
3070 lightSquareGC = wbPieceGC
3071 = XtGetGC(shellWidget, value_mask, &gc_values);
3073 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3074 gc_values.background = XWhitePixel(xDisplay, xScreen);
3075 darkSquareGC = bwPieceGC
3076 = XtGetGC(shellWidget, value_mask, &gc_values);
3078 if (DefaultDepth(xDisplay, xScreen) == 1) {
3079 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3080 gc_values.function = GXcopyInverted;
3081 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3082 gc_values.function = GXcopy;
3083 if (XBlackPixel(xDisplay, xScreen) == 1) {
3084 bwPieceGC = darkSquareGC;
3085 wbPieceGC = copyInvertedGC;
3087 bwPieceGC = copyInvertedGC;
3088 wbPieceGC = lightSquareGC;
3092 gc_values.foreground = highlightSquareColor;
3093 gc_values.background = highlightSquareColor;
3094 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3096 gc_values.foreground = premoveHighlightColor;
3097 gc_values.background = premoveHighlightColor;
3098 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3100 gc_values.foreground = lightSquareColor;
3101 gc_values.background = darkSquareColor;
3102 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3104 gc_values.foreground = darkSquareColor;
3105 gc_values.background = lightSquareColor;
3106 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3108 gc_values.foreground = jailSquareColor;
3109 gc_values.background = jailSquareColor;
3110 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3112 gc_values.foreground = whitePieceColor;
3113 gc_values.background = darkSquareColor;
3114 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3116 gc_values.foreground = whitePieceColor;
3117 gc_values.background = lightSquareColor;
3118 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3120 gc_values.foreground = whitePieceColor;
3121 gc_values.background = jailSquareColor;
3122 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3124 gc_values.foreground = blackPieceColor;
3125 gc_values.background = darkSquareColor;
3126 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3128 gc_values.foreground = blackPieceColor;
3129 gc_values.background = lightSquareColor;
3130 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3132 gc_values.foreground = blackPieceColor;
3133 gc_values.background = jailSquareColor;
3134 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3138 void loadXIM(xim, xmask, filename, dest, mask)
3151 fp = fopen(filename, "rb");
3153 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3160 for (y=0; y<h; ++y) {
3161 for (x=0; x<h; ++x) {
3166 XPutPixel(xim, x, y, blackPieceColor);
3168 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3171 XPutPixel(xim, x, y, darkSquareColor);
3173 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3176 XPutPixel(xim, x, y, whitePieceColor);
3178 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3181 XPutPixel(xim, x, y, lightSquareColor);
3183 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3189 /* create Pixmap of piece */
3190 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3192 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3195 /* create Pixmap of clipmask
3196 Note: We assume the white/black pieces have the same
3197 outline, so we make only 6 masks. This is okay
3198 since the XPM clipmask routines do the same. */
3200 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3202 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3205 /* now create the 1-bit version */
3206 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3209 values.foreground = 1;
3210 values.background = 0;
3212 /* Don't use XtGetGC, not read only */
3213 maskGC = XCreateGC(xDisplay, *mask,
3214 GCForeground | GCBackground, &values);
3215 XCopyPlane(xDisplay, temp, *mask, maskGC,
3216 0, 0, squareSize, squareSize, 0, 0, 1);
3217 XFreePixmap(xDisplay, temp);
3222 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3224 void CreateXIMPieces()
3229 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3234 /* The XSynchronize calls were copied from CreatePieces.
3235 Not sure if needed, but can't hurt */
3236 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3239 /* temp needed by loadXIM() */
3240 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3241 0, 0, ss, ss, AllPlanes, XYPixmap);
3243 if (strlen(appData.pixmapDirectory) == 0) {
3247 if (appData.monoMode) {
3248 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3252 fprintf(stderr, _("\nLoading XIMs...\n"));
3254 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3255 fprintf(stderr, "%d", piece+1);
3256 for (kind=0; kind<4; kind++) {
3257 fprintf(stderr, ".");
3258 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3259 ExpandPathName(appData.pixmapDirectory),
3260 piece <= (int) WhiteKing ? "" : "w",
3261 pieceBitmapNames[piece],
3263 ximPieceBitmap[kind][piece] =
3264 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3265 0, 0, ss, ss, AllPlanes, XYPixmap);
3266 if (appData.debugMode)
3267 fprintf(stderr, _("(File:%s:) "), buf);
3268 loadXIM(ximPieceBitmap[kind][piece],
3270 &(xpmPieceBitmap2[kind][piece]),
3271 &(ximMaskPm2[piece]));
3272 if(piece <= (int)WhiteKing)
3273 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3275 fprintf(stderr," ");
3277 /* Load light and dark squares */
3278 /* If the LSQ and DSQ pieces don't exist, we will
3279 draw them with solid squares. */
3280 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3281 if (access(buf, 0) != 0) {
3285 fprintf(stderr, _("light square "));
3287 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3288 0, 0, ss, ss, AllPlanes, XYPixmap);
3289 if (appData.debugMode)
3290 fprintf(stderr, _("(File:%s:) "), buf);
3292 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3293 fprintf(stderr, _("dark square "));
3294 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3295 ExpandPathName(appData.pixmapDirectory), ss);
3296 if (appData.debugMode)
3297 fprintf(stderr, _("(File:%s:) "), buf);
3299 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3300 0, 0, ss, ss, AllPlanes, XYPixmap);
3301 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3302 xpmJailSquare = xpmLightSquare;
3304 fprintf(stderr, _("Done.\n"));
3306 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3310 void CreateXPMPieces()
3314 u_int ss = squareSize;
3316 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3317 XpmColorSymbol symbols[4];
3319 /* The XSynchronize calls were copied from CreatePieces.
3320 Not sure if needed, but can't hurt */
3321 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3323 /* Setup translations so piece colors match square colors */
3324 symbols[0].name = "light_piece";
3325 symbols[0].value = appData.whitePieceColor;
3326 symbols[1].name = "dark_piece";
3327 symbols[1].value = appData.blackPieceColor;
3328 symbols[2].name = "light_square";
3329 symbols[2].value = appData.lightSquareColor;
3330 symbols[3].name = "dark_square";
3331 symbols[3].value = appData.darkSquareColor;
3333 attr.valuemask = XpmColorSymbols;
3334 attr.colorsymbols = symbols;
3335 attr.numsymbols = 4;
3337 if (appData.monoMode) {
3338 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3342 if (strlen(appData.pixmapDirectory) == 0) {
3343 XpmPieces* pieces = builtInXpms;
3346 while (pieces->size != squareSize && pieces->size) pieces++;
3347 if (!pieces->size) {
3348 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3351 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3352 for (kind=0; kind<4; kind++) {
3354 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3355 pieces->xpm[piece][kind],
3356 &(xpmPieceBitmap2[kind][piece]),
3357 NULL, &attr)) != 0) {
3358 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3362 if(piece <= (int) WhiteKing)
3363 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3367 xpmJailSquare = xpmLightSquare;
3371 fprintf(stderr, _("\nLoading XPMs...\n"));
3374 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3375 fprintf(stderr, "%d ", piece+1);
3376 for (kind=0; kind<4; kind++) {
3377 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3378 ExpandPathName(appData.pixmapDirectory),
3379 piece > (int) WhiteKing ? "w" : "",
3380 pieceBitmapNames[piece],
3382 if (appData.debugMode) {
3383 fprintf(stderr, _("(File:%s:) "), buf);
3385 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3386 &(xpmPieceBitmap2[kind][piece]),
3387 NULL, &attr)) != 0) {
3388 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3389 // [HGM] missing: read of unorthodox piece failed; substitute King.
3390 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3391 ExpandPathName(appData.pixmapDirectory),
3393 if (appData.debugMode) {
3394 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3396 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3397 &(xpmPieceBitmap2[kind][piece]),
3401 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3406 if(piece <= (int) WhiteKing)
3407 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3410 /* Load light and dark squares */
3411 /* If the LSQ and DSQ pieces don't exist, we will
3412 draw them with solid squares. */
3413 fprintf(stderr, _("light square "));
3414 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3415 if (access(buf, 0) != 0) {
3419 if (appData.debugMode)
3420 fprintf(stderr, _("(File:%s:) "), buf);
3422 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3423 &xpmLightSquare, NULL, &attr)) != 0) {
3424 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3427 fprintf(stderr, _("dark square "));
3428 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3429 ExpandPathName(appData.pixmapDirectory), ss);
3430 if (appData.debugMode) {
3431 fprintf(stderr, _("(File:%s:) "), buf);
3433 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3434 &xpmDarkSquare, NULL, &attr)) != 0) {
3435 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3439 xpmJailSquare = xpmLightSquare;
3440 fprintf(stderr, _("Done.\n"));
3442 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3445 #endif /* HAVE_LIBXPM */
3448 /* No built-in bitmaps */
3453 u_int ss = squareSize;
3455 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3458 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3459 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3460 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3461 pieceBitmapNames[piece],
3462 ss, kind == SOLID ? 's' : 'o');
3463 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3464 if(piece <= (int)WhiteKing)
3465 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3469 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3473 /* With built-in bitmaps */
3476 BuiltInBits* bib = builtInBits;
3479 u_int ss = squareSize;
3481 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3484 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3486 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3487 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3488 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3489 pieceBitmapNames[piece],
3490 ss, kind == SOLID ? 's' : 'o');
3491 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3492 bib->bits[kind][piece], ss, ss);
3493 if(piece <= (int)WhiteKing)
3494 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3498 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3503 void ReadBitmap(pm, name, bits, wreq, hreq)
3506 unsigned char bits[];
3512 char msg[MSG_SIZ], fullname[MSG_SIZ];
3514 if (*appData.bitmapDirectory != NULLCHAR) {
3515 strcpy(fullname, appData.bitmapDirectory);
3516 strcat(fullname, "/");
3517 strcat(fullname, name);
3518 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3519 &w, &h, pm, &x_hot, &y_hot);
3520 fprintf(stderr, "load %s\n", name);
3521 if (errcode != BitmapSuccess) {
3523 case BitmapOpenFailed:
3524 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3526 case BitmapFileInvalid:
3527 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3529 case BitmapNoMemory:
3530 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3534 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3538 fprintf(stderr, _("%s: %s...using built-in\n"),
3540 } else if (w != wreq || h != hreq) {
3542 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3543 programName, fullname, w, h, wreq, hreq);
3549 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3558 if (lineGap == 0) return;
3560 /* [HR] Split this into 2 loops for non-square boards. */
3562 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3563 gridSegments[i].x1 = 0;
3564 gridSegments[i].x2 =
3565 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3566 gridSegments[i].y1 = gridSegments[i].y2
3567 = lineGap / 2 + (i * (squareSize + lineGap));
3570 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3571 gridSegments[j + i].y1 = 0;
3572 gridSegments[j + i].y2 =
3573 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3574 gridSegments[j + i].x1 = gridSegments[j + i].x2
3575 = lineGap / 2 + (j * (squareSize + lineGap));
3579 static void MenuBarSelect(w, addr, index)
3584 XtActionProc proc = (XtActionProc) addr;
3586 (proc)(NULL, NULL, NULL, NULL);
3589 void CreateMenuBarPopup(parent, name, mb)
3599 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3602 XtSetArg(args[j], XtNleftMargin, 20); j++;
3603 XtSetArg(args[j], XtNrightMargin, 20); j++;
3605 while (mi->string != NULL) {
3606 if (strcmp(mi->string, "----") == 0) {
3607 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3610 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3611 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3613 XtAddCallback(entry, XtNcallback,
3614 (XtCallbackProc) MenuBarSelect,
3615 (caddr_t) mi->proc);
3621 Widget CreateMenuBar(mb)
3625 Widget anchor, menuBar;
3627 char menuName[MSG_SIZ];
3630 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3631 XtSetArg(args[j], XtNvSpace, 0); j++;
3632 XtSetArg(args[j], XtNborderWidth, 0); j++;
3633 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3634 formWidget, args, j);
3636 while (mb->name != NULL) {
3637 strcpy(menuName, "menu");
3638 strcat(menuName, mb->name);
3640 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3643 shortName[0] = _(mb->name)[0];
3644 shortName[1] = NULLCHAR;
3645 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3648 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3651 XtSetArg(args[j], XtNborderWidth, 0); j++;
3652 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3654 CreateMenuBarPopup(menuBar, menuName, mb);
3660 Widget CreateButtonBar(mi)
3664 Widget button, buttonBar;
3668 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3670 XtSetArg(args[j], XtNhSpace, 0); j++;
3672 XtSetArg(args[j], XtNborderWidth, 0); j++;
3673 XtSetArg(args[j], XtNvSpace, 0); j++;
3674 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3675 formWidget, args, j);
3677 while (mi->string != NULL) {
3680 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3681 XtSetArg(args[j], XtNborderWidth, 0); j++;
3683 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3684 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3685 buttonBar, args, j);
3686 XtAddCallback(button, XtNcallback,
3687 (XtCallbackProc) MenuBarSelect,
3688 (caddr_t) mi->proc);
3695 CreatePieceMenu(name, color)
3702 ChessSquare selection;
3704 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3705 boardWidget, args, 0);
3707 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3708 String item = pieceMenuStrings[color][i];
3710 if (strcmp(item, "----") == 0) {
3711 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3714 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3715 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3717 selection = pieceMenuTranslation[color][i];
3718 XtAddCallback(entry, XtNcallback,
3719 (XtCallbackProc) PieceMenuSelect,
3720 (caddr_t) selection);
3721 if (selection == WhitePawn || selection == BlackPawn) {
3722 XtSetArg(args[0], XtNpopupOnEntry, entry);
3723 XtSetValues(menu, args, 1);
3736 ChessSquare selection;
3738 whitePieceMenu = CreatePieceMenu("menuW", 0);
3739 blackPieceMenu = CreatePieceMenu("menuB", 1);
3741 XtRegisterGrabAction(PieceMenuPopup, True,
3742 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3743 GrabModeAsync, GrabModeAsync);
3745 XtSetArg(args[0], XtNlabel, _("Drop"));
3746 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3747 boardWidget, args, 1);
3748 for (i = 0; i < DROP_MENU_SIZE; i++) {
3749 String item = dropMenuStrings[i];
3751 if (strcmp(item, "----") == 0) {
3752 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3755 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3756 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3758 selection = dropMenuTranslation[i];
3759 XtAddCallback(entry, XtNcallback,
3760 (XtCallbackProc) DropMenuSelect,
3761 (caddr_t) selection);
3766 void SetupDropMenu()
3774 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3775 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3776 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3777 dmEnables[i].piece);
3778 XtSetSensitive(entry, p != NULL || !appData.testLegality
3779 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3780 && !appData.icsActive));
3782 while (p && *p++ == dmEnables[i].piece) count++;
3783 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3785 XtSetArg(args[j], XtNlabel, label); j++;
3786 XtSetValues(entry, args, j);
3790 void PieceMenuPopup(w, event, params, num_params)
3794 Cardinal *num_params;
3796 String whichMenu; int menuNr;
3797 if (event->type == ButtonRelease)
3798 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3799 else if (event->type == ButtonPress)
3800 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3802 case 0: whichMenu = params[0]; break;
3803 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3805 case -1: if (errorUp) ErrorPopDown();
3808 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3811 static void PieceMenuSelect(w, piece, junk)
3816 if (pmFromX < 0 || pmFromY < 0) return;
3817 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3820 static void DropMenuSelect(w, piece, junk)
3825 if (pmFromX < 0 || pmFromY < 0) return;
3826 DropMenuEvent(piece, pmFromX, pmFromY);
3829 void WhiteClock(w, event, prms, nprms)
3835 if (gameMode == EditPosition || gameMode == IcsExamining) {
3836 SetWhiteToPlayEvent();
3837 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3842 void BlackClock(w, event, prms, nprms)
3848 if (gameMode == EditPosition || gameMode == IcsExamining) {
3849 SetBlackToPlayEvent();
3850 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3857 * If the user selects on a border boundary, return -1; if off the board,
3858 * return -2. Otherwise map the event coordinate to the square.
3860 int EventToSquare(x, limit)
3868 if ((x % (squareSize + lineGap)) >= squareSize)
3870 x /= (squareSize + lineGap);
3876 static void do_flash_delay(msec)
3882 static void drawHighlight(file, rank, gc)
3888 if (lineGap == 0 || appData.blindfold) return;
3891 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3892 (squareSize + lineGap);
3893 y = lineGap/2 + rank * (squareSize + lineGap);
3895 x = lineGap/2 + file * (squareSize + lineGap);
3896 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3897 (squareSize + lineGap);
3900 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3901 squareSize+lineGap, squareSize+lineGap);
3904 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3905 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3908 SetHighlights(fromX, fromY, toX, toY)
3909 int fromX, fromY, toX, toY;
3911 if (hi1X != fromX || hi1Y != fromY) {
3912 if (hi1X >= 0 && hi1Y >= 0) {
3913 drawHighlight(hi1X, hi1Y, lineGC);
3915 } // [HGM] first erase both, then draw new!
3916 if (hi2X != toX || hi2Y != toY) {
3917 if (hi2X >= 0 && hi2Y >= 0) {
3918 drawHighlight(hi2X, hi2Y, lineGC);
3921 if (hi1X != fromX || hi1Y != fromY) {
3922 if (fromX >= 0 && fromY >= 0) {
3923 drawHighlight(fromX, fromY, highlineGC);
3926 if (hi2X != toX || hi2Y != toY) {
3927 if (toX >= 0 && toY >= 0) {
3928 drawHighlight(toX, toY, highlineGC);
3940 SetHighlights(-1, -1, -1, -1);
3945 SetPremoveHighlights(fromX, fromY, toX, toY)
3946 int fromX, fromY, toX, toY;
3948 if (pm1X != fromX || pm1Y != fromY) {
3949 if (pm1X >= 0 && pm1Y >= 0) {
3950 drawHighlight(pm1X, pm1Y, lineGC);
3952 if (fromX >= 0 && fromY >= 0) {
3953 drawHighlight(fromX, fromY, prelineGC);
3956 if (pm2X != toX || pm2Y != toY) {
3957 if (pm2X >= 0 && pm2Y >= 0) {
3958 drawHighlight(pm2X, pm2Y, lineGC);
3960 if (toX >= 0 && toY >= 0) {
3961 drawHighlight(toX, toY, prelineGC);
3971 ClearPremoveHighlights()
3973 SetPremoveHighlights(-1, -1, -1, -1);
3976 static void BlankSquare(x, y, color, piece, dest)
3981 if (useImages && useImageSqs) {
3985 pm = xpmLightSquare;
3990 case 2: /* neutral */
3995 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3996 squareSize, squareSize, x, y);
4006 case 2: /* neutral */
4011 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4016 I split out the routines to draw a piece so that I could
4017 make a generic flash routine.
4019 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4021 int square_color, x, y;
4024 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4025 switch (square_color) {
4027 case 2: /* neutral */
4029 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4030 ? *pieceToOutline(piece)
4031 : *pieceToSolid(piece),
4032 dest, bwPieceGC, 0, 0,
4033 squareSize, squareSize, x, y);
4036 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4037 ? *pieceToSolid(piece)
4038 : *pieceToOutline(piece),
4039 dest, wbPieceGC, 0, 0,
4040 squareSize, squareSize, x, y);
4045 static void monoDrawPiece(piece, square_color, x, y, dest)
4047 int square_color, x, y;
4050 switch (square_color) {
4052 case 2: /* neutral */
4054 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4055 ? *pieceToOutline(piece)
4056 : *pieceToSolid(piece),
4057 dest, bwPieceGC, 0, 0,
4058 squareSize, squareSize, x, y, 1);
4061 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4062 ? *pieceToSolid(piece)
4063 : *pieceToOutline(piece),
4064 dest, wbPieceGC, 0, 0,
4065 squareSize, squareSize, x, y, 1);
4070 static void colorDrawPiece(piece, square_color, x, y, dest)
4072 int square_color, x, y;
4075 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4076 switch (square_color) {
4078 XCopyPlane(xDisplay, *pieceToSolid(piece),
4079 dest, (int) piece < (int) BlackPawn
4080 ? wlPieceGC : blPieceGC, 0, 0,
4081 squareSize, squareSize, x, y, 1);
4084 XCopyPlane(xDisplay, *pieceToSolid(piece),
4085 dest, (int) piece < (int) BlackPawn
4086 ? wdPieceGC : bdPieceGC, 0, 0,
4087 squareSize, squareSize, x, y, 1);
4089 case 2: /* neutral */
4091 XCopyPlane(xDisplay, *pieceToSolid(piece),
4092 dest, (int) piece < (int) BlackPawn
4093 ? wjPieceGC : bjPieceGC, 0, 0,
4094 squareSize, squareSize, x, y, 1);
4099 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4101 int square_color, x, y;
4106 switch (square_color) {
4108 case 2: /* neutral */
4110 if ((int)piece < (int) BlackPawn) {
4118 if ((int)piece < (int) BlackPawn) {
4126 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4127 dest, wlPieceGC, 0, 0,
4128 squareSize, squareSize, x, y);
4131 typedef void (*DrawFunc)();
4133 DrawFunc ChooseDrawFunc()
4135 if (appData.monoMode) {
4136 if (DefaultDepth(xDisplay, xScreen) == 1) {
4137 return monoDrawPiece_1bit;
4139 return monoDrawPiece;
4143 return colorDrawPieceImage;
4145 return colorDrawPiece;
4149 /* [HR] determine square color depending on chess variant. */
4150 static int SquareColor(row, column)
4155 if (gameInfo.variant == VariantXiangqi) {
4156 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4158 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4160 } else if (row <= 4) {
4166 square_color = ((column + row) % 2) == 1;
4169 /* [hgm] holdings: next line makes all holdings squares light */
4170 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4172 return square_color;
4175 void DrawSquare(row, column, piece, do_flash)
4176 int row, column, do_flash;
4179 int square_color, x, y, direction, font_ascent, font_descent;
4182 XCharStruct overall;
4186 /* Calculate delay in milliseconds (2-delays per complete flash) */
4187 flash_delay = 500 / appData.flashRate;
4190 x = lineGap + ((BOARD_WIDTH-1)-column) *
4191 (squareSize + lineGap);
4192 y = lineGap + row * (squareSize + lineGap);
4194 x = lineGap + column * (squareSize + lineGap);
4195 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4196 (squareSize + lineGap);
4199 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4201 square_color = SquareColor(row, column);
4203 if ( // [HGM] holdings: blank out area between board and holdings
4204 column == BOARD_LEFT-1 || column == BOARD_RGHT
4205 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4206 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4207 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4209 // [HGM] print piece counts next to holdings
4210 string[1] = NULLCHAR;
4211 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4212 string[0] = '0' + piece;
4213 XTextExtents(countFontStruct, string, 1, &direction,
4214 &font_ascent, &font_descent, &overall);
4215 if (appData.monoMode) {
4216 XDrawImageString(xDisplay, xBoardWindow, countGC,
4217 x + squareSize - overall.width - 2,
4218 y + font_ascent + 1, string, 1);
4220 XDrawString(xDisplay, xBoardWindow, countGC,
4221 x + squareSize - overall.width - 2,
4222 y + font_ascent + 1, string, 1);
4225 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4226 string[0] = '0' + piece;
4227 XTextExtents(countFontStruct, string, 1, &direction,
4228 &font_ascent, &font_descent, &overall);
4229 if (appData.monoMode) {
4230 XDrawImageString(xDisplay, xBoardWindow, countGC,
4231 x + 2, y + font_ascent + 1, string, 1);
4233 XDrawString(xDisplay, xBoardWindow, countGC,
4234 x + 2, y + font_ascent + 1, string, 1);
4238 if (piece == EmptySquare || appData.blindfold) {
4239 BlankSquare(x, y, square_color, piece, xBoardWindow);
4241 drawfunc = ChooseDrawFunc();
4242 if (do_flash && appData.flashCount > 0) {
4243 for (i=0; i<appData.flashCount; ++i) {
4245 drawfunc(piece, square_color, x, y, xBoardWindow);
4246 XSync(xDisplay, False);
4247 do_flash_delay(flash_delay);
4249 BlankSquare(x, y, square_color, piece, xBoardWindow);
4250 XSync(xDisplay, False);
4251 do_flash_delay(flash_delay);
4254 drawfunc(piece, square_color, x, y, xBoardWindow);
4258 string[1] = NULLCHAR;
4259 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4260 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4261 string[0] = 'a' + column - BOARD_LEFT;
4262 XTextExtents(coordFontStruct, string, 1, &direction,
4263 &font_ascent, &font_descent, &overall);
4264 if (appData.monoMode) {
4265 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4266 x + squareSize - overall.width - 2,
4267 y + squareSize - font_descent - 1, string, 1);
4269 XDrawString(xDisplay, xBoardWindow, coordGC,
4270 x + squareSize - overall.width - 2,
4271 y + squareSize - font_descent - 1, string, 1);
4274 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4275 string[0] = ONE + row;
4276 XTextExtents(coordFontStruct, string, 1, &direction,
4277 &font_ascent, &font_descent, &overall);
4278 if (appData.monoMode) {
4279 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4280 x + 2, y + font_ascent + 1, string, 1);
4282 XDrawString(xDisplay, xBoardWindow, coordGC,
4283 x + 2, y + font_ascent + 1, string, 1);
4286 if(!partnerUp && marker[row][column]) {
4287 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4288 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4293 /* Why is this needed on some versions of X? */
4294 void EventProc(widget, unused, event)
4299 if (!XtIsRealized(widget))
4302 switch (event->type) {
4304 if (event->xexpose.count > 0) return; /* no clipping is done */
4305 XDrawPosition(widget, True, NULL);
4306 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4307 flipView = !flipView; partnerUp = !partnerUp;
4308 XDrawPosition(widget, True, NULL);
4309 flipView = !flipView; partnerUp = !partnerUp;
4313 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4320 void DrawPosition(fullRedraw, board)
4321 /*Boolean*/int fullRedraw;
4324 XDrawPosition(boardWidget, fullRedraw, board);
4327 /* Returns 1 if there are "too many" differences between b1 and b2
4328 (i.e. more than 1 move was made) */
4329 static int too_many_diffs(b1, b2)
4335 for (i=0; i<BOARD_HEIGHT; ++i) {
4336 for (j=0; j<BOARD_WIDTH; ++j) {
4337 if (b1[i][j] != b2[i][j]) {
4338 if (++c > 4) /* Castling causes 4 diffs */
4347 /* Matrix describing castling maneuvers */
4348 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4349 static int castling_matrix[4][5] = {
4350 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4351 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4352 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4353 { 7, 7, 4, 5, 6 } /* 0-0, black */
4356 /* Checks whether castling occurred. If it did, *rrow and *rcol
4357 are set to the destination (row,col) of the rook that moved.
4359 Returns 1 if castling occurred, 0 if not.
4361 Note: Only handles a max of 1 castling move, so be sure
4362 to call too_many_diffs() first.
4364 static int check_castle_draw(newb, oldb, rrow, rcol)
4371 /* For each type of castling... */
4372 for (i=0; i<4; ++i) {
4373 r = castling_matrix[i];
4375 /* Check the 4 squares involved in the castling move */
4377 for (j=1; j<=4; ++j) {
4378 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4385 /* All 4 changed, so it must be a castling move */
4394 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4395 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4397 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4400 void DrawSeekBackground( int left, int top, int right, int bottom )
4402 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4405 void DrawSeekText(char *buf, int x, int y)
4407 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4410 void DrawSeekDot(int x, int y, int colorNr)
4412 int square = colorNr & 0x80;
4415 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4417 XFillRectangle(xDisplay, xBoardWindow, color,
4418 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4420 XFillArc(xDisplay, xBoardWindow, color,
4421 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4424 static int damage[2][BOARD_RANKS][BOARD_FILES];
4427 * event handler for redrawing the board
4429 void XDrawPosition(w, repaint, board)
4431 /*Boolean*/int repaint;
4435 static int lastFlipView = 0;
4436 static int lastBoardValid[2] = {0, 0};
4437 static Board lastBoard[2];
4440 int nr = twoBoards*partnerUp;
4442 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4444 if (board == NULL) {
4445 if (!lastBoardValid) return;
4446 board = lastBoard[nr];
4448 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4449 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4450 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4455 * It would be simpler to clear the window with XClearWindow()
4456 * but this causes a very distracting flicker.
4459 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4461 /* If too much changes (begin observing new game, etc.), don't
4463 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4465 /* Special check for castling so we don't flash both the king
4466 and the rook (just flash the king). */
4468 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4469 /* Draw rook with NO flashing. King will be drawn flashing later */
4470 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4471 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4475 /* First pass -- Draw (newly) empty squares and repair damage.
4476 This prevents you from having a piece show up twice while it
4477 is flashing on its new square */
4478 for (i = 0; i < BOARD_HEIGHT; i++)
4479 for (j = 0; j < BOARD_WIDTH; j++)
4480 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4481 || damage[nr][i][j]) {
4482 DrawSquare(i, j, board[i][j], 0);
4483 damage[nr][i][j] = False;
4486 /* Second pass -- Draw piece(s) in new position and flash them */
4487 for (i = 0; i < BOARD_HEIGHT; i++)
4488 for (j = 0; j < BOARD_WIDTH; j++)
4489 if (board[i][j] != lastBoard[nr][i][j]) {
4490 DrawSquare(i, j, board[i][j], do_flash);
4494 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4495 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4496 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4498 for (i = 0; i < BOARD_HEIGHT; i++)
4499 for (j = 0; j < BOARD_WIDTH; j++) {
4500 DrawSquare(i, j, board[i][j], 0);
4501 damage[nr][i][j] = False;
4505 CopyBoard(lastBoard[nr], board);
4506 lastBoardValid[nr] = 1;
4507 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4508 lastFlipView = flipView;
4510 /* Draw highlights */
4511 if (pm1X >= 0 && pm1Y >= 0) {
4512 drawHighlight(pm1X, pm1Y, prelineGC);
4514 if (pm2X >= 0 && pm2Y >= 0) {
4515 drawHighlight(pm2X, pm2Y, prelineGC);
4517 if (hi1X >= 0 && hi1Y >= 0) {
4518 drawHighlight(hi1X, hi1Y, highlineGC);
4520 if (hi2X >= 0 && hi2Y >= 0) {
4521 drawHighlight(hi2X, hi2Y, highlineGC);
4524 /* If piece being dragged around board, must redraw that too */
4527 XSync(xDisplay, False);
4532 * event handler for redrawing the board
4534 void DrawPositionProc(w, event, prms, nprms)
4540 XDrawPosition(w, True, NULL);
4545 * event handler for parsing user moves
4547 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4548 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4549 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4550 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4551 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4552 // and at the end FinishMove() to perform the move after optional promotion popups.
4553 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4554 void HandleUserMove(w, event, prms, nprms)
4560 if (w != boardWidget || errorExitStatus != -1) return;
4563 if (event->type == ButtonPress) {
4564 XtPopdown(promotionShell);
4565 XtDestroyWidget(promotionShell);
4566 promotionUp = False;
4574 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4575 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4576 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4579 void AnimateUserMove (Widget w, XEvent * event,
4580 String * params, Cardinal * nParams)
4582 DragPieceMove(event->xmotion.x, event->xmotion.y);
4585 void HandlePV (Widget w, XEvent * event,
4586 String * params, Cardinal * nParams)
4587 { // [HGM] pv: walk PV
4588 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4591 Widget CommentCreate(name, text, mutable, callback, lines)
4593 int /*Boolean*/ mutable;
4594 XtCallbackProc callback;
4598 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4603 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4604 XtGetValues(boardWidget, args, j);
4607 XtSetArg(args[j], XtNresizable, True); j++;
4610 XtCreatePopupShell(name, topLevelShellWidgetClass,
4611 shellWidget, args, j);
4614 XtCreatePopupShell(name, transientShellWidgetClass,
4615 shellWidget, args, j);
4618 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4619 layoutArgs, XtNumber(layoutArgs));
4621 XtCreateManagedWidget("form", formWidgetClass, layout,
4622 formArgs, XtNumber(formArgs));
4626 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4627 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4629 XtSetArg(args[j], XtNstring, text); j++;
4630 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4631 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4632 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4633 XtSetArg(args[j], XtNright, XtChainRight); j++;
4634 XtSetArg(args[j], XtNresizable, True); j++;
4635 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4636 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4637 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4638 XtSetArg(args[j], XtNautoFill, True); j++;
4639 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4641 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4645 XtSetArg(args[j], XtNfromVert, edit); j++;
4646 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4647 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4648 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4649 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4651 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4652 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4655 XtSetArg(args[j], XtNfromVert, edit); j++;
4656 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4657 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4658 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4659 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4660 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4662 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4663 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4666 XtSetArg(args[j], XtNfromVert, edit); j++;
4667 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4668 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4669 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4670 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4671 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4673 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4674 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4677 XtSetArg(args[j], XtNfromVert, edit); j++;
4678 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4679 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4680 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4681 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4683 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4684 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4687 XtSetArg(args[j], XtNfromVert, edit); j++;
4688 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4689 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4690 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4691 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4692 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4694 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4695 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4698 XtRealizeWidget(shell);
4700 if (commentX == -1) {
4703 Dimension pw_height;
4704 Dimension ew_height;
4707 XtSetArg(args[j], XtNheight, &ew_height); j++;
4708 XtGetValues(edit, args, j);
4711 XtSetArg(args[j], XtNheight, &pw_height); j++;
4712 XtGetValues(shell, args, j);
4713 commentH = pw_height + (lines - 1) * ew_height;
4714 commentW = bw_width - 16;
4716 XSync(xDisplay, False);
4718 /* This code seems to tickle an X bug if it is executed too soon
4719 after xboard starts up. The coordinates get transformed as if
4720 the main window was positioned at (0, 0).
4722 XtTranslateCoords(shellWidget,
4723 (bw_width - commentW) / 2, 0 - commentH / 2,
4724 &commentX, &commentY);
4726 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4727 RootWindowOfScreen(XtScreen(shellWidget)),
4728 (bw_width - commentW) / 2, 0 - commentH / 2,
4733 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4736 if(wpComment.width > 0) {
4737 commentX = wpComment.x;
4738 commentY = wpComment.y;
4739 commentW = wpComment.width;
4740 commentH = wpComment.height;
4744 XtSetArg(args[j], XtNheight, commentH); j++;
4745 XtSetArg(args[j], XtNwidth, commentW); j++;
4746 XtSetArg(args[j], XtNx, commentX); j++;
4747 XtSetArg(args[j], XtNy, commentY); j++;
4748 XtSetValues(shell, args, j);
4749 XtSetKeyboardFocus(shell, edit);
4754 /* Used for analysis window and ICS input window */
4755 Widget MiscCreate(name, text, mutable, callback, lines)
4757 int /*Boolean*/ mutable;
4758 XtCallbackProc callback;
4762 Widget shell, layout, form, edit;
4764 Dimension bw_width, pw_height, ew_height, w, h;
4770 XtSetArg(args[j], XtNresizable, True); j++;
4773 XtCreatePopupShell(name, topLevelShellWidgetClass,
4774 shellWidget, args, j);
4777 XtCreatePopupShell(name, transientShellWidgetClass,
4778 shellWidget, args, j);
4781 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4782 layoutArgs, XtNumber(layoutArgs));
4784 XtCreateManagedWidget("form", formWidgetClass, layout,
4785 formArgs, XtNumber(formArgs));
4789 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4790 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4792 XtSetArg(args[j], XtNstring, text); j++;
4793 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4794 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4795 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4796 XtSetArg(args[j], XtNright, XtChainRight); j++;
4797 XtSetArg(args[j], XtNresizable, True); j++;
4798 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4799 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4800 XtSetArg(args[j], XtNautoFill, True); j++;
4801 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4803 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4805 XtRealizeWidget(shell);
4808 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4809 XtGetValues(boardWidget, args, j);
4812 XtSetArg(args[j], XtNheight, &ew_height); j++;
4813 XtGetValues(edit, args, j);
4816 XtSetArg(args[j], XtNheight, &pw_height); j++;
4817 XtGetValues(shell, args, j);
4818 h = pw_height + (lines - 1) * ew_height;
4821 XSync(xDisplay, False);
4823 /* This code seems to tickle an X bug if it is executed too soon
4824 after xboard starts up. The coordinates get transformed as if
4825 the main window was positioned at (0, 0).
4827 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4829 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4830 RootWindowOfScreen(XtScreen(shellWidget)),
4831 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4835 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4838 XtSetArg(args[j], XtNheight, h); j++;
4839 XtSetArg(args[j], XtNwidth, w); j++;
4840 XtSetArg(args[j], XtNx, x); j++;
4841 XtSetArg(args[j], XtNy, y); j++;
4842 XtSetValues(shell, args, j);
4848 static int savedIndex; /* gross that this is global */
4850 void EditCommentPopUp(index, title, text)
4859 if (text == NULL) text = "";
4861 if (editShell == NULL) {
4863 CommentCreate(title, text, True, EditCommentCallback, 4);
4864 XtRealizeWidget(editShell);
4865 CatchDeleteWindow(editShell, "EditCommentPopDown");
4867 edit = XtNameToWidget(editShell, "*form.text");
4869 XtSetArg(args[j], XtNstring, text); j++;
4870 XtSetValues(edit, args, j);
4872 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4873 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4874 XtSetValues(editShell, args, j);
4877 XtPopup(editShell, XtGrabNone);
4881 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4882 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4886 void EditCommentCallback(w, client_data, call_data)
4888 XtPointer client_data, call_data;
4896 XtSetArg(args[j], XtNlabel, &name); j++;
4897 XtGetValues(w, args, j);
4899 if (strcmp(name, _("ok")) == 0) {
4900 edit = XtNameToWidget(editShell, "*form.text");
4902 XtSetArg(args[j], XtNstring, &val); j++;
4903 XtGetValues(edit, args, j);
4904 ReplaceComment(savedIndex, val);
4905 EditCommentPopDown();
4906 } else if (strcmp(name, _("cancel")) == 0) {
4907 EditCommentPopDown();
4908 } else if (strcmp(name, _("clear")) == 0) {
4909 edit = XtNameToWidget(editShell, "*form.text");
4910 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4911 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4915 void EditCommentPopDown()
4920 if (!editUp) return;
4922 XtSetArg(args[j], XtNx, &commentX); j++;
4923 XtSetArg(args[j], XtNy, &commentY); j++;
4924 XtSetArg(args[j], XtNheight, &commentH); j++;
4925 XtSetArg(args[j], XtNwidth, &commentW); j++;
4926 XtGetValues(editShell, args, j);
4927 XtPopdown(editShell);
4930 XtSetArg(args[j], XtNleftBitmap, None); j++;
4931 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4935 void ICSInputBoxPopUp()
4940 char *title = _("ICS Input");
4943 if (ICSInputShell == NULL) {
4944 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4945 tr = XtParseTranslationTable(ICSInputTranslations);
4946 edit = XtNameToWidget(ICSInputShell, "*form.text");
4947 XtOverrideTranslations(edit, tr);
4948 XtRealizeWidget(ICSInputShell);
4949 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4952 edit = XtNameToWidget(ICSInputShell, "*form.text");
4954 XtSetArg(args[j], XtNstring, ""); j++;
4955 XtSetValues(edit, args, j);
4957 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4958 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4959 XtSetValues(ICSInputShell, args, j);
4962 XtPopup(ICSInputShell, XtGrabNone);
4963 XtSetKeyboardFocus(ICSInputShell, edit);
4965 ICSInputBoxUp = True;
4967 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4968 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4972 void ICSInputSendText()
4979 edit = XtNameToWidget(ICSInputShell, "*form.text");
4981 XtSetArg(args[j], XtNstring, &val); j++;
4982 XtGetValues(edit, args, j);
4984 SendMultiLineToICS(val);
4985 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4986 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4989 void ICSInputBoxPopDown()
4994 if (!ICSInputBoxUp) return;
4996 XtPopdown(ICSInputShell);
4997 ICSInputBoxUp = False;
4999 XtSetArg(args[j], XtNleftBitmap, None); j++;
5000 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5004 void CommentPopUp(title, text)
5011 if (commentShell == NULL) {
5013 CommentCreate(title, text, False, CommentCallback, 4);
5014 XtRealizeWidget(commentShell);
5015 CatchDeleteWindow(commentShell, "CommentPopDown");
5017 edit = XtNameToWidget(commentShell, "*form.text");
5019 XtSetArg(args[j], XtNstring, text); j++;
5020 XtSetValues(edit, args, j);
5022 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5023 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5024 XtSetValues(commentShell, args, j);
5027 XtPopup(commentShell, XtGrabNone);
5028 XSync(xDisplay, False);
5033 void CommentCallback(w, client_data, call_data)
5035 XtPointer client_data, call_data;
5042 XtSetArg(args[j], XtNlabel, &name); j++;
5043 XtGetValues(w, args, j);
5045 if (strcmp(name, _("close")) == 0) {
5047 } else if (strcmp(name, _("edit")) == 0) {
5054 void CommentPopDown()
5059 if (!commentUp) return;
5061 XtSetArg(args[j], XtNx, &commentX); j++;
5062 XtSetArg(args[j], XtNy, &commentY); j++;
5063 XtSetArg(args[j], XtNwidth, &commentW); j++;
5064 XtSetArg(args[j], XtNheight, &commentH); j++;
5065 XtGetValues(commentShell, args, j);
5066 XtPopdown(commentShell);
5067 XSync(xDisplay, False);
5071 void FileNamePopUp(label, def, proc, openMode)
5078 Widget popup, layout, dialog, edit;
5084 fileProc = proc; /* I can't see a way not */
5085 fileOpenMode = openMode; /* to use globals here */
5086 { // [HGM] use file-selector dialog stolen from Ghostview
5088 int index; // this is not supported yet
5090 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5091 NULL, openMode, NULL, &name))
5092 (void) (*fileProc)(f, index=0, name);
5096 void FileNamePopDown()
5098 if (!filenameUp) return;
5099 XtPopdown(fileNameShell);
5100 XtDestroyWidget(fileNameShell);
5105 void FileNameCallback(w, client_data, call_data)
5107 XtPointer client_data, call_data;
5112 XtSetArg(args[0], XtNlabel, &name);
5113 XtGetValues(w, args, 1);
5115 if (strcmp(name, _("cancel")) == 0) {
5120 FileNameAction(w, NULL, NULL, NULL);
5123 void FileNameAction(w, event, prms, nprms)
5135 name = XawDialogGetValueString(w = XtParent(w));
5137 if ((name != NULL) && (*name != NULLCHAR)) {
5139 XtPopdown(w = XtParent(XtParent(w)));
5143 p = strrchr(buf, ' ');
5150 fullname = ExpandPathName(buf);
5152 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5155 f = fopen(fullname, fileOpenMode);
5157 DisplayError(_("Failed to open file"), errno);
5159 (void) (*fileProc)(f, index, buf);
5166 XtPopdown(w = XtParent(XtParent(w)));
5172 void PromotionPopUp()
5175 Widget dialog, layout;
5177 Dimension bw_width, pw_width;
5181 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5182 XtGetValues(boardWidget, args, j);
5185 XtSetArg(args[j], XtNresizable, True); j++;
5186 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5188 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5189 shellWidget, args, j);
5191 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5192 layoutArgs, XtNumber(layoutArgs));
5195 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5196 XtSetArg(args[j], XtNborderWidth, 0); j++;
5197 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5200 if(gameInfo.variant != VariantShogi) {
5201 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5202 (XtPointer) dialog);
5203 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5204 (XtPointer) dialog);
5205 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5206 (XtPointer) dialog);
5207 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5208 (XtPointer) dialog);
5209 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5210 gameInfo.variant == VariantGiveaway) {
5211 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5212 (XtPointer) dialog);
5214 if(gameInfo.variant == VariantCapablanca ||
5215 gameInfo.variant == VariantGothic ||
5216 gameInfo.variant == VariantCapaRandom) {
5217 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5218 (XtPointer) dialog);
5219 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5220 (XtPointer) dialog);
5222 } else // [HGM] shogi
5224 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5225 (XtPointer) dialog);
5226 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5227 (XtPointer) dialog);
5229 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5230 (XtPointer) dialog);
5232 XtRealizeWidget(promotionShell);
5233 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5236 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5237 XtGetValues(promotionShell, args, j);
5239 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5240 lineGap + squareSize/3 +
5241 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5242 0 : 6*(squareSize + lineGap)), &x, &y);
5245 XtSetArg(args[j], XtNx, x); j++;
5246 XtSetArg(args[j], XtNy, y); j++;
5247 XtSetValues(promotionShell, args, j);
5249 XtPopup(promotionShell, XtGrabNone);
5254 void PromotionPopDown()
5256 if (!promotionUp) return;
5257 XtPopdown(promotionShell);
5258 XtDestroyWidget(promotionShell);
5259 promotionUp = False;
5262 void PromotionCallback(w, client_data, call_data)
5264 XtPointer client_data, call_data;
5270 XtSetArg(args[0], XtNlabel, &name);
5271 XtGetValues(w, args, 1);
5275 if (fromX == -1) return;
5277 if (strcmp(name, _("cancel")) == 0) {
5281 } else if (strcmp(name, _("Knight")) == 0) {
5283 } else if (strcmp(name, _("Promote")) == 0) {
5285 } else if (strcmp(name, _("Defer")) == 0) {
5288 promoChar = ToLower(name[0]);
5291 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5293 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5294 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5299 void ErrorCallback(w, client_data, call_data)
5301 XtPointer client_data, call_data;
5304 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5306 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5312 if (!errorUp) return;
5314 XtPopdown(errorShell);
5315 XtDestroyWidget(errorShell);
5316 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5319 void ErrorPopUp(title, label, modal)
5320 char *title, *label;
5324 Widget dialog, layout;
5328 Dimension bw_width, pw_width;
5329 Dimension pw_height;
5333 XtSetArg(args[i], XtNresizable, True); i++;
5334 XtSetArg(args[i], XtNtitle, title); i++;
5336 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5337 shellWidget, args, i);
5339 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5340 layoutArgs, XtNumber(layoutArgs));
5343 XtSetArg(args[i], XtNlabel, label); i++;
5344 XtSetArg(args[i], XtNborderWidth, 0); i++;
5345 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5348 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5350 XtRealizeWidget(errorShell);
5351 CatchDeleteWindow(errorShell, "ErrorPopDown");
5354 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5355 XtGetValues(boardWidget, args, i);
5357 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5358 XtSetArg(args[i], XtNheight, &pw_height); i++;
5359 XtGetValues(errorShell, args, i);
5362 /* This code seems to tickle an X bug if it is executed too soon
5363 after xboard starts up. The coordinates get transformed as if
5364 the main window was positioned at (0, 0).
5366 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5367 0 - pw_height + squareSize / 3, &x, &y);
5369 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5370 RootWindowOfScreen(XtScreen(boardWidget)),
5371 (bw_width - pw_width) / 2,
5372 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5376 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5379 XtSetArg(args[i], XtNx, x); i++;
5380 XtSetArg(args[i], XtNy, y); i++;
5381 XtSetValues(errorShell, args, i);
5384 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5387 /* Disable all user input other than deleting the window */
5388 static int frozen = 0;
5392 /* Grab by a widget that doesn't accept input */
5393 XtAddGrab(messageWidget, TRUE, FALSE);
5397 /* Undo a FreezeUI */
5400 if (!frozen) return;
5401 XtRemoveGrab(messageWidget);
5405 char *ModeToWidgetName(mode)
5409 case BeginningOfGame:
5410 if (appData.icsActive)
5411 return "menuMode.ICS Client";
5412 else if (appData.noChessProgram ||
5413 *appData.cmailGameName != NULLCHAR)
5414 return "menuMode.Edit Game";
5416 return "menuMode.Machine Black";
5417 case MachinePlaysBlack:
5418 return "menuMode.Machine Black";
5419 case MachinePlaysWhite:
5420 return "menuMode.Machine White";
5422 return "menuMode.Analysis Mode";
5424 return "menuMode.Analyze File";
5425 case TwoMachinesPlay:
5426 return "menuMode.Two Machines";
5428 return "menuMode.Edit Game";
5429 case PlayFromGameFile:
5430 return "menuFile.Load Game";
5432 return "menuMode.Edit Position";
5434 return "menuMode.Training";
5435 case IcsPlayingWhite:
5436 case IcsPlayingBlack:
5440 return "menuMode.ICS Client";
5447 void ModeHighlight()
5450 static int oldPausing = FALSE;
5451 static GameMode oldmode = (GameMode) -1;
5454 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5456 if (pausing != oldPausing) {
5457 oldPausing = pausing;
5459 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5461 XtSetArg(args[0], XtNleftBitmap, None);
5463 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5466 if (appData.showButtonBar) {
5467 /* Always toggle, don't set. Previous code messes up when
5468 invoked while the button is pressed, as releasing it
5469 toggles the state again. */
5472 XtSetArg(args[0], XtNbackground, &oldbg);
5473 XtSetArg(args[1], XtNforeground, &oldfg);
5474 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5476 XtSetArg(args[0], XtNbackground, oldfg);
5477 XtSetArg(args[1], XtNforeground, oldbg);
5479 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5483 wname = ModeToWidgetName(oldmode);
5484 if (wname != NULL) {
5485 XtSetArg(args[0], XtNleftBitmap, None);
5486 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5488 wname = ModeToWidgetName(gameMode);
5489 if (wname != NULL) {
5490 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5491 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5495 /* Maybe all the enables should be handled here, not just this one */
5496 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5497 gameMode == Training || gameMode == PlayFromGameFile);
5502 * Button/menu procedures
5504 void ResetProc(w, event, prms, nprms)
5513 int LoadGamePopUp(f, gameNumber, title)
5518 cmailMsgLoaded = FALSE;
5519 if (gameNumber == 0) {
5520 int error = GameListBuild(f);
5522 DisplayError(_("Cannot build game list"), error);
5523 } else if (!ListEmpty(&gameList) &&
5524 ((ListGame *) gameList.tailPred)->number > 1) {
5525 GameListPopUp(f, title);
5531 return LoadGame(f, gameNumber, title, FALSE);
5534 void LoadGameProc(w, event, prms, nprms)
5540 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5543 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5546 void LoadNextGameProc(w, event, prms, nprms)
5555 void LoadPrevGameProc(w, event, prms, nprms)
5564 void ReloadGameProc(w, event, prms, nprms)
5573 void LoadNextPositionProc(w, event, prms, nprms)
5582 void LoadPrevPositionProc(w, event, prms, nprms)
5591 void ReloadPositionProc(w, event, prms, nprms)
5600 void LoadPositionProc(w, event, prms, nprms)
5606 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5609 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5612 void SaveGameProc(w, event, prms, nprms)
5618 FileNamePopUp(_("Save game file name?"),
5619 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5623 void SavePositionProc(w, event, prms, nprms)
5629 FileNamePopUp(_("Save position file name?"),
5630 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5634 void ReloadCmailMsgProc(w, event, prms, nprms)
5640 ReloadCmailMsgEvent(FALSE);
5643 void MailMoveProc(w, event, prms, nprms)
5652 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5653 char *selected_fen_position=NULL;
5656 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5657 Atom *type_return, XtPointer *value_return,
5658 unsigned long *length_return, int *format_return)
5660 char *selection_tmp;
5662 if (!selected_fen_position) return False; /* should never happen */
5663 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5664 /* note: since no XtSelectionDoneProc was registered, Xt will
5665 * automatically call XtFree on the value returned. So have to
5666 * make a copy of it allocated with XtMalloc */
5667 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5668 strcpy(selection_tmp, selected_fen_position);
5670 *value_return=selection_tmp;
5671 *length_return=strlen(selection_tmp);
5672 *type_return=*target;
5673 *format_return = 8; /* bits per byte */
5675 } else if (*target == XA_TARGETS(xDisplay)) {
5676 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5677 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5678 targets_tmp[1] = XA_STRING;
5679 *value_return = targets_tmp;
5680 *type_return = XA_ATOM;
5682 *format_return = 8 * sizeof(Atom);
5683 if (*format_return > 32) {
5684 *length_return *= *format_return / 32;
5685 *format_return = 32;
5693 /* note: when called from menu all parameters are NULL, so no clue what the
5694 * Widget which was clicked on was, or what the click event was
5696 void CopyPositionProc(w, event, prms, nprms)
5703 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5704 * have a notion of a position that is selected but not copied.
5705 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5707 if(gameMode == EditPosition) EditPositionDone(TRUE);
5708 if (selected_fen_position) free(selected_fen_position);
5709 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5710 if (!selected_fen_position) return;
5711 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5713 SendPositionSelection,
5714 NULL/* lose_ownership_proc */ ,
5715 NULL/* transfer_done_proc */);
5716 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5718 SendPositionSelection,
5719 NULL/* lose_ownership_proc */ ,
5720 NULL/* transfer_done_proc */);
5723 /* function called when the data to Paste is ready */
5725 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5726 Atom *type, XtPointer value, unsigned long *len, int *format)
5729 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5730 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5731 EditPositionPasteFEN(fenstr);
5735 /* called when Paste Position button is pressed,
5736 * all parameters will be NULL */
5737 void PastePositionProc(w, event, prms, nprms)
5743 XtGetSelectionValue(menuBarWidget,
5744 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5745 /* (XtSelectionCallbackProc) */ PastePositionCB,
5746 NULL, /* client_data passed to PastePositionCB */
5748 /* better to use the time field from the event that triggered the
5749 * call to this function, but that isn't trivial to get
5757 SendGameSelection(Widget w, Atom *selection, Atom *target,
5758 Atom *type_return, XtPointer *value_return,
5759 unsigned long *length_return, int *format_return)
5761 char *selection_tmp;
5763 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5764 FILE* f = fopen(gameCopyFilename, "r");
5767 if (f == NULL) return False;
5771 selection_tmp = XtMalloc(len + 1);
5772 count = fread(selection_tmp, 1, len, f);
5774 XtFree(selection_tmp);
5777 selection_tmp[len] = NULLCHAR;
5778 *value_return = selection_tmp;
5779 *length_return = len;
5780 *type_return = *target;
5781 *format_return = 8; /* bits per byte */
5783 } else if (*target == XA_TARGETS(xDisplay)) {
5784 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5785 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5786 targets_tmp[1] = XA_STRING;
5787 *value_return = targets_tmp;
5788 *type_return = XA_ATOM;
5790 *format_return = 8 * sizeof(Atom);
5791 if (*format_return > 32) {
5792 *length_return *= *format_return / 32;
5793 *format_return = 32;
5801 /* note: when called from menu all parameters are NULL, so no clue what the
5802 * Widget which was clicked on was, or what the click event was
5804 void CopyGameProc(w, event, prms, nprms)
5812 ret = SaveGameToFile(gameCopyFilename, FALSE);
5816 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5817 * have a notion of a game that is selected but not copied.
5818 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5820 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5823 NULL/* lose_ownership_proc */ ,
5824 NULL/* transfer_done_proc */);
5825 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5828 NULL/* lose_ownership_proc */ ,
5829 NULL/* transfer_done_proc */);
5832 /* function called when the data to Paste is ready */
5834 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5835 Atom *type, XtPointer value, unsigned long *len, int *format)
5838 if (value == NULL || *len == 0) {
5839 return; /* nothing had been selected to copy */
5841 f = fopen(gamePasteFilename, "w");
5843 DisplayError(_("Can't open temp file"), errno);
5846 fwrite(value, 1, *len, f);
5849 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5852 /* called when Paste Game button is pressed,
5853 * all parameters will be NULL */
5854 void PasteGameProc(w, event, prms, nprms)
5860 XtGetSelectionValue(menuBarWidget,
5861 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5862 /* (XtSelectionCallbackProc) */ PasteGameCB,
5863 NULL, /* client_data passed to PasteGameCB */
5865 /* better to use the time field from the event that triggered the
5866 * call to this function, but that isn't trivial to get
5876 SaveGameProc(NULL, NULL, NULL, NULL);
5880 void QuitProc(w, event, prms, nprms)
5889 void PauseProc(w, event, prms, nprms)
5899 void MachineBlackProc(w, event, prms, nprms)
5905 MachineBlackEvent();
5908 void MachineWhiteProc(w, event, prms, nprms)
5914 MachineWhiteEvent();
5917 void AnalyzeModeProc(w, event, prms, nprms)
5925 if (!first.analysisSupport) {
5926 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5927 DisplayError(buf, 0);
5930 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5931 if (appData.icsActive) {
5932 if (gameMode != IcsObserving) {
5933 sprintf(buf,_("You are not observing a game"));
5934 DisplayError(buf, 0);
5936 if (appData.icsEngineAnalyze) {
5937 if (appData.debugMode)
5938 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5944 /* if enable, use want disable icsEngineAnalyze */
5945 if (appData.icsEngineAnalyze) {
5950 appData.icsEngineAnalyze = TRUE;
5951 if (appData.debugMode)
5952 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5954 if (!appData.showThinking)
5955 ShowThinkingProc(w,event,prms,nprms);
5960 void AnalyzeFileProc(w, event, prms, nprms)
5966 if (!first.analysisSupport) {
5968 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5969 DisplayError(buf, 0);
5974 if (!appData.showThinking)
5975 ShowThinkingProc(w,event,prms,nprms);
5978 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5979 AnalysisPeriodicEvent(1);
5982 void TwoMachinesProc(w, event, prms, nprms)
5991 void IcsClientProc(w, event, prms, nprms)
6000 void EditGameProc(w, event, prms, nprms)
6009 void EditPositionProc(w, event, prms, nprms)
6015 EditPositionEvent();
6018 void TrainingProc(w, event, prms, nprms)
6027 void EditCommentProc(w, event, prms, nprms)
6034 EditCommentPopDown();
6040 void IcsInputBoxProc(w, event, prms, nprms)
6046 if (ICSInputBoxUp) {
6047 ICSInputBoxPopDown();
6053 void AcceptProc(w, event, prms, nprms)
6062 void DeclineProc(w, event, prms, nprms)
6071 void RematchProc(w, event, prms, nprms)
6080 void CallFlagProc(w, event, prms, nprms)
6089 void DrawProc(w, event, prms, nprms)
6098 void AbortProc(w, event, prms, nprms)
6107 void AdjournProc(w, event, prms, nprms)
6116 void ResignProc(w, event, prms, nprms)
6125 void AdjuWhiteProc(w, event, prms, nprms)
6131 UserAdjudicationEvent(+1);
6134 void AdjuBlackProc(w, event, prms, nprms)
6140 UserAdjudicationEvent(-1);
6143 void AdjuDrawProc(w, event, prms, nprms)
6149 UserAdjudicationEvent(0);
6152 void EnterKeyProc(w, event, prms, nprms)
6158 if (ICSInputBoxUp == True)
6162 void UpKeyProc(w, event, prms, nprms)
6167 { // [HGM] input: let up-arrow recall previous line from history
6174 if (!ICSInputBoxUp) return;
6175 edit = XtNameToWidget(ICSInputShell, "*form.text");
6177 XtSetArg(args[j], XtNstring, &val); j++;
6178 XtGetValues(edit, args, j);
6179 val = PrevInHistory(val);
6180 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6181 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6183 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6184 XawTextReplace(edit, 0, 0, &t);
6185 XawTextSetInsertionPoint(edit, 9999);
6189 void DownKeyProc(w, event, prms, nprms)
6194 { // [HGM] input: let down-arrow recall next line from history
6199 if (!ICSInputBoxUp) return;
6200 edit = XtNameToWidget(ICSInputShell, "*form.text");
6201 val = NextInHistory();
6202 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6203 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6205 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6206 XawTextReplace(edit, 0, 0, &t);
6207 XawTextSetInsertionPoint(edit, 9999);
6211 void StopObservingProc(w, event, prms, nprms)
6217 StopObservingEvent();
6220 void StopExaminingProc(w, event, prms, nprms)
6226 StopExaminingEvent();
6229 void UploadProc(w, event, prms, nprms)
6239 void ForwardProc(w, event, prms, nprms)
6249 void BackwardProc(w, event, prms, nprms)
6258 void ToStartProc(w, event, prms, nprms)
6267 void ToEndProc(w, event, prms, nprms)
6276 void RevertProc(w, event, prms, nprms)
6285 void AnnotateProc(w, event, prms, nprms)
6294 void TruncateGameProc(w, event, prms, nprms)
6300 TruncateGameEvent();
6302 void RetractMoveProc(w, event, prms, nprms)
6311 void MoveNowProc(w, event, prms, nprms)
6321 void AlwaysQueenProc(w, event, prms, nprms)
6329 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6331 if (appData.alwaysPromoteToQueen) {
6332 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6334 XtSetArg(args[0], XtNleftBitmap, None);
6336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6340 void AnimateDraggingProc(w, event, prms, nprms)
6348 appData.animateDragging = !appData.animateDragging;
6350 if (appData.animateDragging) {
6351 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6354 XtSetArg(args[0], XtNleftBitmap, None);
6356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6360 void AnimateMovingProc(w, event, prms, nprms)
6368 appData.animate = !appData.animate;
6370 if (appData.animate) {
6371 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6374 XtSetArg(args[0], XtNleftBitmap, None);
6376 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6380 void AutocommProc(w, event, prms, nprms)
6388 appData.autoComment = !appData.autoComment;
6390 if (appData.autoComment) {
6391 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6393 XtSetArg(args[0], XtNleftBitmap, None);
6395 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6400 void AutoflagProc(w, event, prms, nprms)
6408 appData.autoCallFlag = !appData.autoCallFlag;
6410 if (appData.autoCallFlag) {
6411 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6413 XtSetArg(args[0], XtNleftBitmap, None);
6415 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6419 void AutoflipProc(w, event, prms, nprms)
6427 appData.autoFlipView = !appData.autoFlipView;
6429 if (appData.autoFlipView) {
6430 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6432 XtSetArg(args[0], XtNleftBitmap, None);
6434 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6438 void AutobsProc(w, event, prms, nprms)
6446 appData.autoObserve = !appData.autoObserve;
6448 if (appData.autoObserve) {
6449 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6451 XtSetArg(args[0], XtNleftBitmap, None);
6453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6457 void AutoraiseProc(w, event, prms, nprms)
6465 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6467 if (appData.autoRaiseBoard) {
6468 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6470 XtSetArg(args[0], XtNleftBitmap, None);
6472 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6476 void AutosaveProc(w, event, prms, nprms)
6484 appData.autoSaveGames = !appData.autoSaveGames;
6486 if (appData.autoSaveGames) {
6487 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6489 XtSetArg(args[0], XtNleftBitmap, None);
6491 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6495 void BlindfoldProc(w, event, prms, nprms)
6503 appData.blindfold = !appData.blindfold;
6505 if (appData.blindfold) {
6506 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6508 XtSetArg(args[0], XtNleftBitmap, None);
6510 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6513 DrawPosition(True, NULL);
6516 void TestLegalityProc(w, event, prms, nprms)
6524 appData.testLegality = !appData.testLegality;
6526 if (appData.testLegality) {
6527 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6529 XtSetArg(args[0], XtNleftBitmap, None);
6531 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6536 void FlashMovesProc(w, event, prms, nprms)
6544 if (appData.flashCount == 0) {
6545 appData.flashCount = 3;
6547 appData.flashCount = -appData.flashCount;
6550 if (appData.flashCount > 0) {
6551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6553 XtSetArg(args[0], XtNleftBitmap, None);
6555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6559 void FlipViewProc(w, event, prms, nprms)
6565 flipView = !flipView;
6566 DrawPosition(True, NULL);
6569 void GetMoveListProc(w, event, prms, nprms)
6577 appData.getMoveList = !appData.getMoveList;
6579 if (appData.getMoveList) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6583 XtSetArg(args[0], XtNleftBitmap, None);
6585 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6590 void HighlightDraggingProc(w, event, prms, nprms)
6598 appData.highlightDragging = !appData.highlightDragging;
6600 if (appData.highlightDragging) {
6601 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6603 XtSetArg(args[0], XtNleftBitmap, None);
6605 XtSetValues(XtNameToWidget(menuBarWidget,
6606 "menuOptions.Highlight Dragging"), args, 1);
6610 void HighlightLastMoveProc(w, event, prms, nprms)
6618 appData.highlightLastMove = !appData.highlightLastMove;
6620 if (appData.highlightLastMove) {
6621 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6623 XtSetArg(args[0], XtNleftBitmap, None);
6625 XtSetValues(XtNameToWidget(menuBarWidget,
6626 "menuOptions.Highlight Last Move"), args, 1);
6629 void IcsAlarmProc(w, event, prms, nprms)
6637 appData.icsAlarm = !appData.icsAlarm;
6639 if (appData.icsAlarm) {
6640 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6642 XtSetArg(args[0], XtNleftBitmap, None);
6644 XtSetValues(XtNameToWidget(menuBarWidget,
6645 "menuOptions.ICS Alarm"), args, 1);
6648 void MoveSoundProc(w, event, prms, nprms)
6656 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6658 if (appData.ringBellAfterMoves) {
6659 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6661 XtSetArg(args[0], XtNleftBitmap, None);
6663 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6668 void OldSaveStyleProc(w, event, prms, nprms)
6676 appData.oldSaveStyle = !appData.oldSaveStyle;
6678 if (appData.oldSaveStyle) {
6679 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6681 XtSetArg(args[0], XtNleftBitmap, None);
6683 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6687 void PeriodicUpdatesProc(w, event, prms, nprms)
6695 PeriodicUpdatesEvent(!appData.periodicUpdates);
6697 if (appData.periodicUpdates) {
6698 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6700 XtSetArg(args[0], XtNleftBitmap, None);
6702 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6706 void PonderNextMoveProc(w, event, prms, nprms)
6714 PonderNextMoveEvent(!appData.ponderNextMove);
6716 if (appData.ponderNextMove) {
6717 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6719 XtSetArg(args[0], XtNleftBitmap, None);
6721 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6725 void PopupExitMessageProc(w, event, prms, nprms)
6733 appData.popupExitMessage = !appData.popupExitMessage;
6735 if (appData.popupExitMessage) {
6736 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6738 XtSetArg(args[0], XtNleftBitmap, None);
6740 XtSetValues(XtNameToWidget(menuBarWidget,
6741 "menuOptions.Popup Exit Message"), args, 1);
6744 void PopupMoveErrorsProc(w, event, prms, nprms)
6752 appData.popupMoveErrors = !appData.popupMoveErrors;
6754 if (appData.popupMoveErrors) {
6755 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6757 XtSetArg(args[0], XtNleftBitmap, None);
6759 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6763 void PremoveProc(w, event, prms, nprms)
6771 appData.premove = !appData.premove;
6773 if (appData.premove) {
6774 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6776 XtSetArg(args[0], XtNleftBitmap, None);
6778 XtSetValues(XtNameToWidget(menuBarWidget,
6779 "menuOptions.Premove"), args, 1);
6782 void QuietPlayProc(w, event, prms, nprms)
6790 appData.quietPlay = !appData.quietPlay;
6792 if (appData.quietPlay) {
6793 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6795 XtSetArg(args[0], XtNleftBitmap, None);
6797 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6801 void ShowCoordsProc(w, event, prms, nprms)
6809 appData.showCoords = !appData.showCoords;
6811 if (appData.showCoords) {
6812 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6814 XtSetArg(args[0], XtNleftBitmap, None);
6816 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6819 DrawPosition(True, NULL);
6822 void ShowThinkingProc(w, event, prms, nprms)
6828 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6829 ShowThinkingEvent();
6832 void HideThinkingProc(w, event, prms, nprms)
6840 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6841 ShowThinkingEvent();
6843 if (appData.hideThinkingFromHuman) {
6844 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6846 XtSetArg(args[0], XtNleftBitmap, None);
6848 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6852 void SaveOnExitProc(w, event, prms, nprms)
6860 saveSettingsOnExit = !saveSettingsOnExit;
6862 if (saveSettingsOnExit) {
6863 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6865 XtSetArg(args[0], XtNleftBitmap, None);
6867 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6871 void SaveSettingsProc(w, event, prms, nprms)
6877 SaveSettings(settingsFileName);
6880 void InfoProc(w, event, prms, nprms)
6887 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6892 void ManProc(w, event, prms, nprms)
6900 if (nprms && *nprms > 0)
6904 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6908 void HintProc(w, event, prms, nprms)
6917 void BookProc(w, event, prms, nprms)
6926 void AboutProc(w, event, prms, nprms)
6934 char *zippy = " (with Zippy code)";
6938 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6939 programVersion, zippy,
6940 "Copyright 1991 Digital Equipment Corporation",
6941 "Enhancements Copyright 1992-2009 Free Software Foundation",
6942 "Enhancements Copyright 2005 Alessandro Scotti",
6943 PACKAGE, " is free software and carries NO WARRANTY;",
6944 "see the file COPYING for more information.");
6945 ErrorPopUp(_("About XBoard"), buf, FALSE);
6948 void DebugProc(w, event, prms, nprms)
6954 appData.debugMode = !appData.debugMode;
6957 void AboutGameProc(w, event, prms, nprms)
6966 void NothingProc(w, event, prms, nprms)
6975 void Iconify(w, event, prms, nprms)
6984 XtSetArg(args[0], XtNiconic, True);
6985 XtSetValues(shellWidget, args, 1);
6988 void DisplayMessage(message, extMessage)
6989 char *message, *extMessage;
6991 /* display a message in the message widget */
7000 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7005 message = extMessage;
7009 /* need to test if messageWidget already exists, since this function
7010 can also be called during the startup, if for example a Xresource
7011 is not set up correctly */
7014 XtSetArg(arg, XtNlabel, message);
7015 XtSetValues(messageWidget, &arg, 1);
7021 void DisplayTitle(text)
7026 char title[MSG_SIZ];
7029 if (text == NULL) text = "";
7031 if (appData.titleInWindow) {
7033 XtSetArg(args[i], XtNlabel, text); i++;
7034 XtSetValues(titleWidget, args, i);
7037 if (*text != NULLCHAR) {
7039 strcpy(title, text);
7040 } else if (appData.icsActive) {
7041 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7042 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7043 } else if (appData.cmailGameName[0] != NULLCHAR) {
7044 snprintf(icon, sizeof(icon), "%s", "CMail");
7045 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7047 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7048 } else if (gameInfo.variant == VariantGothic) {
7049 strcpy(icon, programName);
7050 strcpy(title, GOTHIC);
7053 } else if (gameInfo.variant == VariantFalcon) {
7054 strcpy(icon, programName);
7055 strcpy(title, FALCON);
7057 } else if (appData.noChessProgram) {
7058 strcpy(icon, programName);
7059 strcpy(title, programName);
7061 strcpy(icon, first.tidy);
7062 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7065 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7066 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7067 XtSetValues(shellWidget, args, i);
7071 void DisplayError(message, error)
7078 if (appData.debugMode || appData.matchMode) {
7079 fprintf(stderr, "%s: %s\n", programName, message);
7082 if (appData.debugMode || appData.matchMode) {
7083 fprintf(stderr, "%s: %s: %s\n",
7084 programName, message, strerror(error));
7086 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7089 ErrorPopUp(_("Error"), message, FALSE);
7093 void DisplayMoveError(message)
7098 DrawPosition(FALSE, NULL);
7099 if (appData.debugMode || appData.matchMode) {
7100 fprintf(stderr, "%s: %s\n", programName, message);
7102 if (appData.popupMoveErrors) {
7103 ErrorPopUp(_("Error"), message, FALSE);
7105 DisplayMessage(message, "");
7110 void DisplayFatalError(message, error, status)
7116 errorExitStatus = status;
7118 fprintf(stderr, "%s: %s\n", programName, message);
7120 fprintf(stderr, "%s: %s: %s\n",
7121 programName, message, strerror(error));
7122 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7125 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7126 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7132 void DisplayInformation(message)
7136 ErrorPopUp(_("Information"), message, TRUE);
7139 void DisplayNote(message)
7143 ErrorPopUp(_("Note"), message, FALSE);
7147 NullXErrorCheck(dpy, error_event)
7149 XErrorEvent *error_event;
7154 void DisplayIcsInteractionTitle(message)
7157 if (oldICSInteractionTitle == NULL) {
7158 /* Magic to find the old window title, adapted from vim */
7159 char *wina = getenv("WINDOWID");
7161 Window win = (Window) atoi(wina);
7162 Window root, parent, *children;
7163 unsigned int nchildren;
7164 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7166 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7167 if (!XQueryTree(xDisplay, win, &root, &parent,
7168 &children, &nchildren)) break;
7169 if (children) XFree((void *)children);
7170 if (parent == root || parent == 0) break;
7173 XSetErrorHandler(oldHandler);
7175 if (oldICSInteractionTitle == NULL) {
7176 oldICSInteractionTitle = "xterm";
7179 printf("\033]0;%s\007", message);
7183 char pendingReplyPrefix[MSG_SIZ];
7184 ProcRef pendingReplyPR;
7186 void AskQuestionProc(w, event, prms, nprms)
7193 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7197 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7200 void AskQuestionPopDown()
7202 if (!askQuestionUp) return;
7203 XtPopdown(askQuestionShell);
7204 XtDestroyWidget(askQuestionShell);
7205 askQuestionUp = False;
7208 void AskQuestionReplyAction(w, event, prms, nprms)
7218 reply = XawDialogGetValueString(w = XtParent(w));
7219 strcpy(buf, pendingReplyPrefix);
7220 if (*buf) strcat(buf, " ");
7223 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7224 AskQuestionPopDown();
7226 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7229 void AskQuestionCallback(w, client_data, call_data)
7231 XtPointer client_data, call_data;
7236 XtSetArg(args[0], XtNlabel, &name);
7237 XtGetValues(w, args, 1);
7239 if (strcmp(name, _("cancel")) == 0) {
7240 AskQuestionPopDown();
7242 AskQuestionReplyAction(w, NULL, NULL, NULL);
7246 void AskQuestion(title, question, replyPrefix, pr)
7247 char *title, *question, *replyPrefix;
7251 Widget popup, layout, dialog, edit;
7257 strcpy(pendingReplyPrefix, replyPrefix);
7258 pendingReplyPR = pr;
7261 XtSetArg(args[i], XtNresizable, True); i++;
7262 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7263 askQuestionShell = popup =
7264 XtCreatePopupShell(title, transientShellWidgetClass,
7265 shellWidget, args, i);
7268 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7269 layoutArgs, XtNumber(layoutArgs));
7272 XtSetArg(args[i], XtNlabel, question); i++;
7273 XtSetArg(args[i], XtNvalue, ""); i++;
7274 XtSetArg(args[i], XtNborderWidth, 0); i++;
7275 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7278 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7279 (XtPointer) dialog);
7280 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7281 (XtPointer) dialog);
7283 XtRealizeWidget(popup);
7284 CatchDeleteWindow(popup, "AskQuestionPopDown");
7286 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7287 &x, &y, &win_x, &win_y, &mask);
7289 XtSetArg(args[0], XtNx, x - 10);
7290 XtSetArg(args[1], XtNy, y - 30);
7291 XtSetValues(popup, args, 2);
7293 XtPopup(popup, XtGrabExclusive);
7294 askQuestionUp = True;
7296 edit = XtNameToWidget(dialog, "*value");
7297 XtSetKeyboardFocus(popup, edit);
7305 if (*name == NULLCHAR) {
7307 } else if (strcmp(name, "$") == 0) {
7308 putc(BELLCHAR, stderr);
7311 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7319 PlaySound(appData.soundMove);
7325 PlaySound(appData.soundIcsWin);
7331 PlaySound(appData.soundIcsLoss);
7337 PlaySound(appData.soundIcsDraw);
7341 PlayIcsUnfinishedSound()
7343 PlaySound(appData.soundIcsUnfinished);
7349 PlaySound(appData.soundIcsAlarm);
7355 system("stty echo");
7361 system("stty -echo");
7365 Colorize(cc, continuation)
7370 int count, outCount, error;
7372 if (textColors[(int)cc].bg > 0) {
7373 if (textColors[(int)cc].fg > 0) {
7374 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7375 textColors[(int)cc].fg, textColors[(int)cc].bg);
7377 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7378 textColors[(int)cc].bg);
7381 if (textColors[(int)cc].fg > 0) {
7382 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7383 textColors[(int)cc].fg);
7385 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7388 count = strlen(buf);
7389 outCount = OutputToProcess(NoProc, buf, count, &error);
7390 if (outCount < count) {
7391 DisplayFatalError(_("Error writing to display"), error, 1);
7394 if (continuation) return;
7397 PlaySound(appData.soundShout);
7400 PlaySound(appData.soundSShout);
7403 PlaySound(appData.soundChannel1);
7406 PlaySound(appData.soundChannel);
7409 PlaySound(appData.soundKibitz);
7412 PlaySound(appData.soundTell);
7414 case ColorChallenge:
7415 PlaySound(appData.soundChallenge);
7418 PlaySound(appData.soundRequest);
7421 PlaySound(appData.soundSeek);
7432 return getpwuid(getuid())->pw_name;
7435 static char *ExpandPathName(path)
7438 static char static_buf[2000];
7439 char *d, *s, buf[2000];
7445 while (*s && isspace(*s))
7454 if (*(s+1) == '/') {
7455 strcpy(d, getpwuid(getuid())->pw_dir);
7460 *strchr(buf, '/') = 0;
7461 pwd = getpwnam(buf);
7464 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7468 strcpy(d, pwd->pw_dir);
7469 strcat(d, strchr(s+1, '/'));
7480 static char host_name[MSG_SIZ];
7482 #if HAVE_GETHOSTNAME
7483 gethostname(host_name, MSG_SIZ);
7485 #else /* not HAVE_GETHOSTNAME */
7486 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7487 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7489 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7491 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7492 #endif /* not HAVE_GETHOSTNAME */
7495 XtIntervalId delayedEventTimerXID = 0;
7496 DelayedEventCallback delayedEventCallback = 0;
7501 delayedEventTimerXID = 0;
7502 delayedEventCallback();
7506 ScheduleDelayedEvent(cb, millisec)
7507 DelayedEventCallback cb; long millisec;
7509 if(delayedEventTimerXID && delayedEventCallback == cb)
7510 // [HGM] alive: replace, rather than add or flush identical event
7511 XtRemoveTimeOut(delayedEventTimerXID);
7512 delayedEventCallback = cb;
7513 delayedEventTimerXID =
7514 XtAppAddTimeOut(appContext, millisec,
7515 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7518 DelayedEventCallback
7521 if (delayedEventTimerXID) {
7522 return delayedEventCallback;
7529 CancelDelayedEvent()
7531 if (delayedEventTimerXID) {
7532 XtRemoveTimeOut(delayedEventTimerXID);
7533 delayedEventTimerXID = 0;
7537 XtIntervalId loadGameTimerXID = 0;
7539 int LoadGameTimerRunning()
7541 return loadGameTimerXID != 0;
7544 int StopLoadGameTimer()
7546 if (loadGameTimerXID != 0) {
7547 XtRemoveTimeOut(loadGameTimerXID);
7548 loadGameTimerXID = 0;
7556 LoadGameTimerCallback(arg, id)
7560 loadGameTimerXID = 0;
7565 StartLoadGameTimer(millisec)
7569 XtAppAddTimeOut(appContext, millisec,
7570 (XtTimerCallbackProc) LoadGameTimerCallback,
7574 XtIntervalId analysisClockXID = 0;
7577 AnalysisClockCallback(arg, id)
7581 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7582 || appData.icsEngineAnalyze) { // [DM]
7583 AnalysisPeriodicEvent(0);
7584 StartAnalysisClock();
7589 StartAnalysisClock()
7592 XtAppAddTimeOut(appContext, 2000,
7593 (XtTimerCallbackProc) AnalysisClockCallback,
7597 XtIntervalId clockTimerXID = 0;
7599 int ClockTimerRunning()
7601 return clockTimerXID != 0;
7604 int StopClockTimer()
7606 if (clockTimerXID != 0) {
7607 XtRemoveTimeOut(clockTimerXID);
7616 ClockTimerCallback(arg, id)
7625 StartClockTimer(millisec)
7629 XtAppAddTimeOut(appContext, millisec,
7630 (XtTimerCallbackProc) ClockTimerCallback,
7635 DisplayTimerLabel(w, color, timer, highlight)
7644 /* check for low time warning */
7645 Pixel foregroundOrWarningColor = timerForegroundPixel;
7648 appData.lowTimeWarning &&
7649 (timer / 1000) < appData.icsAlarmTime)
7650 foregroundOrWarningColor = lowTimeWarningColor;
7652 if (appData.clockMode) {
7653 sprintf(buf, "%s: %s", color, TimeString(timer));
7654 XtSetArg(args[0], XtNlabel, buf);
7656 sprintf(buf, "%s ", color);
7657 XtSetArg(args[0], XtNlabel, buf);
7662 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7663 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7665 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7666 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7669 XtSetValues(w, args, 3);
7673 DisplayWhiteClock(timeRemaining, highlight)
7679 if(appData.noGUI) return;
7680 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7681 if (highlight && iconPixmap == bIconPixmap) {
7682 iconPixmap = wIconPixmap;
7683 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7684 XtSetValues(shellWidget, args, 1);
7689 DisplayBlackClock(timeRemaining, highlight)
7695 if(appData.noGUI) return;
7696 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7697 if (highlight && iconPixmap == wIconPixmap) {
7698 iconPixmap = bIconPixmap;
7699 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7700 XtSetValues(shellWidget, args, 1);
7718 int StartChildProcess(cmdLine, dir, pr)
7725 int to_prog[2], from_prog[2];
7729 if (appData.debugMode) {
7730 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7733 /* We do NOT feed the cmdLine to the shell; we just
7734 parse it into blank-separated arguments in the
7735 most simple-minded way possible.
7738 strcpy(buf, cmdLine);
7741 while(*p == ' ') p++;
7743 if(*p == '"' || *p == '\'')
7744 p = strchr(++argv[i-1], *p);
7745 else p = strchr(p, ' ');
7746 if (p == NULL) break;
7751 SetUpChildIO(to_prog, from_prog);
7753 if ((pid = fork()) == 0) {
7755 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7756 close(to_prog[1]); // first close the unused pipe ends
7757 close(from_prog[0]);
7758 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7759 dup2(from_prog[1], 1);
7760 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7761 close(from_prog[1]); // and closing again loses one of the pipes!
7762 if(fileno(stderr) >= 2) // better safe than sorry...
7763 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7765 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7770 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7772 execvp(argv[0], argv);
7774 /* If we get here, exec failed */
7779 /* Parent process */
7781 close(from_prog[1]);
7783 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7786 cp->fdFrom = from_prog[0];
7787 cp->fdTo = to_prog[1];
7792 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7793 static RETSIGTYPE AlarmCallBack(int n)
7799 DestroyChildProcess(pr, signalType)
7803 ChildProc *cp = (ChildProc *) pr;
7805 if (cp->kind != CPReal) return;
7807 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7808 signal(SIGALRM, AlarmCallBack);
7810 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7811 kill(cp->pid, SIGKILL); // kill it forcefully
7812 wait((int *) 0); // and wait again
7816 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7818 /* Process is exiting either because of the kill or because of
7819 a quit command sent by the backend; either way, wait for it to die.
7828 InterruptChildProcess(pr)
7831 ChildProc *cp = (ChildProc *) pr;
7833 if (cp->kind != CPReal) return;
7834 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7837 int OpenTelnet(host, port, pr)
7842 char cmdLine[MSG_SIZ];
7844 if (port[0] == NULLCHAR) {
7845 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7847 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7849 return StartChildProcess(cmdLine, "", pr);
7852 int OpenTCP(host, port, pr)
7858 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7859 #else /* !OMIT_SOCKETS */
7861 struct sockaddr_in sa;
7863 unsigned short uport;
7866 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7870 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7871 sa.sin_family = AF_INET;
7872 sa.sin_addr.s_addr = INADDR_ANY;
7873 uport = (unsigned short) 0;
7874 sa.sin_port = htons(uport);
7875 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7879 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7880 if (!(hp = gethostbyname(host))) {
7882 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7883 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7884 hp->h_addrtype = AF_INET;
7886 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7887 hp->h_addr_list[0] = (char *) malloc(4);
7888 hp->h_addr_list[0][0] = b0;
7889 hp->h_addr_list[0][1] = b1;
7890 hp->h_addr_list[0][2] = b2;
7891 hp->h_addr_list[0][3] = b3;
7896 sa.sin_family = hp->h_addrtype;
7897 uport = (unsigned short) atoi(port);
7898 sa.sin_port = htons(uport);
7899 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7901 if (connect(s, (struct sockaddr *) &sa,
7902 sizeof(struct sockaddr_in)) < 0) {
7906 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7913 #endif /* !OMIT_SOCKETS */
7918 int OpenCommPort(name, pr)
7925 fd = open(name, 2, 0);
7926 if (fd < 0) return errno;
7928 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7938 int OpenLoopback(pr)
7944 SetUpChildIO(to, from);
7946 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7949 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7956 int OpenRcmd(host, user, cmd, pr)
7957 char *host, *user, *cmd;
7960 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7964 #define INPUT_SOURCE_BUF_SIZE 8192
7973 char buf[INPUT_SOURCE_BUF_SIZE];
7978 DoInputCallback(closure, source, xid)
7983 InputSource *is = (InputSource *) closure;
7988 if (is->lineByLine) {
7989 count = read(is->fd, is->unused,
7990 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7992 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7995 is->unused += count;
7997 while (p < is->unused) {
7998 q = memchr(p, '\n', is->unused - p);
7999 if (q == NULL) break;
8001 (is->func)(is, is->closure, p, q - p, 0);
8005 while (p < is->unused) {
8010 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8015 (is->func)(is, is->closure, is->buf, count, error);
8019 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8026 ChildProc *cp = (ChildProc *) pr;
8028 is = (InputSource *) calloc(1, sizeof(InputSource));
8029 is->lineByLine = lineByLine;
8033 is->fd = fileno(stdin);
8035 is->kind = cp->kind;
8036 is->fd = cp->fdFrom;
8039 is->unused = is->buf;
8042 is->xid = XtAppAddInput(appContext, is->fd,
8043 (XtPointer) (XtInputReadMask),
8044 (XtInputCallbackProc) DoInputCallback,
8046 is->closure = closure;
8047 return (InputSourceRef) is;
8051 RemoveInputSource(isr)
8054 InputSource *is = (InputSource *) isr;
8056 if (is->xid == 0) return;
8057 XtRemoveInput(is->xid);
8061 int OutputToProcess(pr, message, count, outError)
8067 static int line = 0;
8068 ChildProc *cp = (ChildProc *) pr;
8073 if (appData.noJoin || !appData.useInternalWrap)
8074 outCount = fwrite(message, 1, count, stdout);
8077 int width = get_term_width();
8078 int len = wrap(NULL, message, count, width, &line);
8079 char *msg = malloc(len);
8083 outCount = fwrite(message, 1, count, stdout);
8086 dbgchk = wrap(msg, message, count, width, &line);
8087 if (dbgchk != len && appData.debugMode)
8088 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8089 outCount = fwrite(msg, 1, dbgchk, stdout);
8095 outCount = write(cp->fdTo, message, count);
8105 /* Output message to process, with "ms" milliseconds of delay
8106 between each character. This is needed when sending the logon
8107 script to ICC, which for some reason doesn't like the
8108 instantaneous send. */
8109 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8116 ChildProc *cp = (ChildProc *) pr;
8121 r = write(cp->fdTo, message++, 1);
8134 /**** Animation code by Hugh Fisher, DCS, ANU.
8136 Known problem: if a window overlapping the board is
8137 moved away while a piece is being animated underneath,
8138 the newly exposed area won't be updated properly.
8139 I can live with this.
8141 Known problem: if you look carefully at the animation
8142 of pieces in mono mode, they are being drawn as solid
8143 shapes without interior detail while moving. Fixing
8144 this would be a major complication for minimal return.
8147 /* Masks for XPM pieces. Black and white pieces can have
8148 different shapes, but in the interest of retaining my
8149 sanity pieces must have the same outline on both light
8150 and dark squares, and all pieces must use the same
8151 background square colors/images. */
8153 static int xpmDone = 0;
8156 CreateAnimMasks (pieceDepth)
8163 unsigned long plane;
8166 /* Need a bitmap just to get a GC with right depth */
8167 buf = XCreatePixmap(xDisplay, xBoardWindow,
8169 values.foreground = 1;
8170 values.background = 0;
8171 /* Don't use XtGetGC, not read only */
8172 maskGC = XCreateGC(xDisplay, buf,
8173 GCForeground | GCBackground, &values);
8174 XFreePixmap(xDisplay, buf);
8176 buf = XCreatePixmap(xDisplay, xBoardWindow,
8177 squareSize, squareSize, pieceDepth);
8178 values.foreground = XBlackPixel(xDisplay, xScreen);
8179 values.background = XWhitePixel(xDisplay, xScreen);
8180 bufGC = XCreateGC(xDisplay, buf,
8181 GCForeground | GCBackground, &values);
8183 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8184 /* Begin with empty mask */
8185 if(!xpmDone) // [HGM] pieces: keep using existing
8186 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8187 squareSize, squareSize, 1);
8188 XSetFunction(xDisplay, maskGC, GXclear);
8189 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8190 0, 0, squareSize, squareSize);
8192 /* Take a copy of the piece */
8197 XSetFunction(xDisplay, bufGC, GXcopy);
8198 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8200 0, 0, squareSize, squareSize, 0, 0);
8202 /* XOR the background (light) over the piece */
8203 XSetFunction(xDisplay, bufGC, GXxor);
8205 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8206 0, 0, squareSize, squareSize, 0, 0);
8208 XSetForeground(xDisplay, bufGC, lightSquareColor);
8209 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8212 /* We now have an inverted piece image with the background
8213 erased. Construct mask by just selecting all the non-zero
8214 pixels - no need to reconstruct the original image. */
8215 XSetFunction(xDisplay, maskGC, GXor);
8217 /* Might be quicker to download an XImage and create bitmap
8218 data from it rather than this N copies per piece, but it
8219 only takes a fraction of a second and there is a much
8220 longer delay for loading the pieces. */
8221 for (n = 0; n < pieceDepth; n ++) {
8222 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8223 0, 0, squareSize, squareSize,
8229 XFreePixmap(xDisplay, buf);
8230 XFreeGC(xDisplay, bufGC);
8231 XFreeGC(xDisplay, maskGC);
8235 InitAnimState (anim, info)
8237 XWindowAttributes * info;
8242 /* Each buffer is square size, same depth as window */
8243 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8244 squareSize, squareSize, info->depth);
8245 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8246 squareSize, squareSize, info->depth);
8248 /* Create a plain GC for blitting */
8249 mask = GCForeground | GCBackground | GCFunction |
8250 GCPlaneMask | GCGraphicsExposures;
8251 values.foreground = XBlackPixel(xDisplay, xScreen);
8252 values.background = XWhitePixel(xDisplay, xScreen);
8253 values.function = GXcopy;
8254 values.plane_mask = AllPlanes;
8255 values.graphics_exposures = False;
8256 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8258 /* Piece will be copied from an existing context at
8259 the start of each new animation/drag. */
8260 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8262 /* Outline will be a read-only copy of an existing */
8263 anim->outlineGC = None;
8269 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8270 XWindowAttributes info;
8272 if (xpmDone && gameInfo.variant == old) return;
8273 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8274 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8276 InitAnimState(&game, &info);
8277 InitAnimState(&player, &info);
8279 /* For XPM pieces, we need bitmaps to use as masks. */
8281 CreateAnimMasks(info.depth);
8287 static Boolean frameWaiting;
8289 static RETSIGTYPE FrameAlarm (sig)
8292 frameWaiting = False;
8293 /* In case System-V style signals. Needed?? */
8294 signal(SIGALRM, FrameAlarm);
8301 struct itimerval delay;
8303 XSync(xDisplay, False);
8306 frameWaiting = True;
8307 signal(SIGALRM, FrameAlarm);
8308 delay.it_interval.tv_sec =
8309 delay.it_value.tv_sec = time / 1000;
8310 delay.it_interval.tv_usec =
8311 delay.it_value.tv_usec = (time % 1000) * 1000;
8312 setitimer(ITIMER_REAL, &delay, NULL);
8313 while (frameWaiting) pause();
8314 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8315 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8316 setitimer(ITIMER_REAL, &delay, NULL);
8326 XSync(xDisplay, False);
8328 usleep(time * 1000);
8333 /* Convert board position to corner of screen rect and color */
8336 ScreenSquare(column, row, pt, color)
8337 int column; int row; XPoint * pt; int * color;
8340 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8341 pt->y = lineGap + row * (squareSize + lineGap);
8343 pt->x = lineGap + column * (squareSize + lineGap);
8344 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8346 *color = SquareColor(row, column);
8349 /* Convert window coords to square */
8352 BoardSquare(x, y, column, row)
8353 int x; int y; int * column; int * row;
8355 *column = EventToSquare(x, BOARD_WIDTH);
8356 if (flipView && *column >= 0)
8357 *column = BOARD_WIDTH - 1 - *column;
8358 *row = EventToSquare(y, BOARD_HEIGHT);
8359 if (!flipView && *row >= 0)
8360 *row = BOARD_HEIGHT - 1 - *row;
8365 #undef Max /* just in case */
8367 #define Max(a, b) ((a) > (b) ? (a) : (b))
8368 #define Min(a, b) ((a) < (b) ? (a) : (b))
8371 SetRect(rect, x, y, width, height)
8372 XRectangle * rect; int x; int y; int width; int height;
8376 rect->width = width;
8377 rect->height = height;
8380 /* Test if two frames overlap. If they do, return
8381 intersection rect within old and location of
8382 that rect within new. */
8385 Intersect(old, new, size, area, pt)
8386 XPoint * old; XPoint * new;
8387 int size; XRectangle * area; XPoint * pt;
8389 if (old->x > new->x + size || new->x > old->x + size ||
8390 old->y > new->y + size || new->y > old->y + size) {
8393 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8394 size - abs(old->x - new->x), size - abs(old->y - new->y));
8395 pt->x = Max(old->x - new->x, 0);
8396 pt->y = Max(old->y - new->y, 0);
8401 /* For two overlapping frames, return the rect(s)
8402 in the old that do not intersect with the new. */
8405 CalcUpdateRects(old, new, size, update, nUpdates)
8406 XPoint * old; XPoint * new; int size;
8407 XRectangle update[]; int * nUpdates;
8411 /* If old = new (shouldn't happen) then nothing to draw */
8412 if (old->x == new->x && old->y == new->y) {
8416 /* Work out what bits overlap. Since we know the rects
8417 are the same size we don't need a full intersect calc. */
8419 /* Top or bottom edge? */
8420 if (new->y > old->y) {
8421 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8423 } else if (old->y > new->y) {
8424 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8425 size, old->y - new->y);
8428 /* Left or right edge - don't overlap any update calculated above. */
8429 if (new->x > old->x) {
8430 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8431 new->x - old->x, size - abs(new->y - old->y));
8433 } else if (old->x > new->x) {
8434 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8435 old->x - new->x, size - abs(new->y - old->y));
8442 /* Generate a series of frame coords from start->mid->finish.
8443 The movement rate doubles until the half way point is
8444 reached, then halves back down to the final destination,
8445 which gives a nice slow in/out effect. The algorithmn
8446 may seem to generate too many intermediates for short
8447 moves, but remember that the purpose is to attract the
8448 viewers attention to the piece about to be moved and
8449 then to where it ends up. Too few frames would be less
8453 Tween(start, mid, finish, factor, frames, nFrames)
8454 XPoint * start; XPoint * mid;
8455 XPoint * finish; int factor;
8456 XPoint frames[]; int * nFrames;
8458 int fraction, n, count;
8462 /* Slow in, stepping 1/16th, then 1/8th, ... */
8464 for (n = 0; n < factor; n++)
8466 for (n = 0; n < factor; n++) {
8467 frames[count].x = start->x + (mid->x - start->x) / fraction;
8468 frames[count].y = start->y + (mid->y - start->y) / fraction;
8470 fraction = fraction / 2;
8474 frames[count] = *mid;
8477 /* Slow out, stepping 1/2, then 1/4, ... */
8479 for (n = 0; n < factor; n++) {
8480 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8481 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8483 fraction = fraction * 2;
8488 /* Draw a piece on the screen without disturbing what's there */
8491 SelectGCMask(piece, clip, outline, mask)
8492 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8496 /* Bitmap for piece being moved. */
8497 if (appData.monoMode) {
8498 *mask = *pieceToSolid(piece);
8499 } else if (useImages) {
8501 *mask = xpmMask[piece];
8503 *mask = ximMaskPm[piece];
8506 *mask = *pieceToSolid(piece);
8509 /* GC for piece being moved. Square color doesn't matter, but
8510 since it gets modified we make a copy of the original. */
8512 if (appData.monoMode)
8517 if (appData.monoMode)
8522 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8524 /* Outline only used in mono mode and is not modified */
8526 *outline = bwPieceGC;
8528 *outline = wbPieceGC;
8532 OverlayPiece(piece, clip, outline, dest)
8533 ChessSquare piece; GC clip; GC outline; Drawable dest;
8538 /* Draw solid rectangle which will be clipped to shape of piece */
8539 XFillRectangle(xDisplay, dest, clip,
8540 0, 0, squareSize, squareSize);
8541 if (appData.monoMode)
8542 /* Also draw outline in contrasting color for black
8543 on black / white on white cases */
8544 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8545 0, 0, squareSize, squareSize, 0, 0, 1);
8547 /* Copy the piece */
8552 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8554 0, 0, squareSize, squareSize,
8559 /* Animate the movement of a single piece */
8562 BeginAnimation(anim, piece, startColor, start)
8570 /* The old buffer is initialised with the start square (empty) */
8571 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8572 anim->prevFrame = *start;
8574 /* The piece will be drawn using its own bitmap as a matte */
8575 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8576 XSetClipMask(xDisplay, anim->pieceGC, mask);
8580 AnimationFrame(anim, frame, piece)
8585 XRectangle updates[4];
8590 /* Save what we are about to draw into the new buffer */
8591 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8592 frame->x, frame->y, squareSize, squareSize,
8595 /* Erase bits of the previous frame */
8596 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8597 /* Where the new frame overlapped the previous,
8598 the contents in newBuf are wrong. */
8599 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8600 overlap.x, overlap.y,
8601 overlap.width, overlap.height,
8603 /* Repaint the areas in the old that don't overlap new */
8604 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8605 for (i = 0; i < count; i++)
8606 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8607 updates[i].x - anim->prevFrame.x,
8608 updates[i].y - anim->prevFrame.y,
8609 updates[i].width, updates[i].height,
8610 updates[i].x, updates[i].y);
8612 /* Easy when no overlap */
8613 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8614 0, 0, squareSize, squareSize,
8615 anim->prevFrame.x, anim->prevFrame.y);
8618 /* Save this frame for next time round */
8619 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8620 0, 0, squareSize, squareSize,
8622 anim->prevFrame = *frame;
8624 /* Draw piece over original screen contents, not current,
8625 and copy entire rect. Wipes out overlapping piece images. */
8626 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8627 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8628 0, 0, squareSize, squareSize,
8629 frame->x, frame->y);
8633 EndAnimation (anim, finish)
8637 XRectangle updates[4];
8642 /* The main code will redraw the final square, so we
8643 only need to erase the bits that don't overlap. */
8644 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8645 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8646 for (i = 0; i < count; i++)
8647 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8648 updates[i].x - anim->prevFrame.x,
8649 updates[i].y - anim->prevFrame.y,
8650 updates[i].width, updates[i].height,
8651 updates[i].x, updates[i].y);
8653 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8654 0, 0, squareSize, squareSize,
8655 anim->prevFrame.x, anim->prevFrame.y);
8660 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8662 ChessSquare piece; int startColor;
8663 XPoint * start; XPoint * finish;
8664 XPoint frames[]; int nFrames;
8668 BeginAnimation(anim, piece, startColor, start);
8669 for (n = 0; n < nFrames; n++) {
8670 AnimationFrame(anim, &(frames[n]), piece);
8671 FrameDelay(appData.animSpeed);
8673 EndAnimation(anim, finish);
8676 /* Main control logic for deciding what to animate and how */
8679 AnimateMove(board, fromX, fromY, toX, toY)
8688 XPoint start, finish, mid;
8689 XPoint frames[kFactor * 2 + 1];
8690 int nFrames, startColor, endColor;
8692 /* Are we animating? */
8693 if (!appData.animate || appData.blindfold)
8696 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8697 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8698 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8700 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8701 piece = board[fromY][fromX];
8702 if (piece >= EmptySquare) return;
8707 hop = (piece == WhiteKnight || piece == BlackKnight);
8710 if (appData.debugMode) {
8711 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8712 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8713 piece, fromX, fromY, toX, toY); }
8715 ScreenSquare(fromX, fromY, &start, &startColor);
8716 ScreenSquare(toX, toY, &finish, &endColor);
8719 /* Knight: make diagonal movement then straight */
8720 if (abs(toY - fromY) < abs(toX - fromX)) {
8721 mid.x = start.x + (finish.x - start.x) / 2;
8725 mid.y = start.y + (finish.y - start.y) / 2;
8728 mid.x = start.x + (finish.x - start.x) / 2;
8729 mid.y = start.y + (finish.y - start.y) / 2;
8732 /* Don't use as many frames for very short moves */
8733 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8734 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8736 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8737 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8739 /* Be sure end square is redrawn */
8740 damage[0][toY][toX] = True;
8744 DragPieceBegin(x, y)
8747 int boardX, boardY, color;
8750 /* Are we animating? */
8751 if (!appData.animateDragging || appData.blindfold)
8754 /* Figure out which square we start in and the
8755 mouse position relative to top left corner. */
8756 BoardSquare(x, y, &boardX, &boardY);
8757 player.startBoardX = boardX;
8758 player.startBoardY = boardY;
8759 ScreenSquare(boardX, boardY, &corner, &color);
8760 player.startSquare = corner;
8761 player.startColor = color;
8762 /* As soon as we start dragging, the piece will jump slightly to
8763 be centered over the mouse pointer. */
8764 player.mouseDelta.x = squareSize/2;
8765 player.mouseDelta.y = squareSize/2;
8766 /* Initialise animation */
8767 player.dragPiece = PieceForSquare(boardX, boardY);
8769 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8770 player.dragActive = True;
8771 BeginAnimation(&player, player.dragPiece, color, &corner);
8772 /* Mark this square as needing to be redrawn. Note that
8773 we don't remove the piece though, since logically (ie
8774 as seen by opponent) the move hasn't been made yet. */
8775 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8776 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8777 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8778 corner.x, corner.y, squareSize, squareSize,
8779 0, 0); // [HGM] zh: unstack in stead of grab
8780 damage[0][boardY][boardX] = True;
8782 player.dragActive = False;
8792 /* Are we animating? */
8793 if (!appData.animateDragging || appData.blindfold)
8797 if (! player.dragActive)
8799 /* Move piece, maintaining same relative position
8800 of mouse within square */
8801 corner.x = x - player.mouseDelta.x;
8802 corner.y = y - player.mouseDelta.y;
8803 AnimationFrame(&player, &corner, player.dragPiece);
8805 if (appData.highlightDragging) {
8807 BoardSquare(x, y, &boardX, &boardY);
8808 SetHighlights(fromX, fromY, boardX, boardY);
8817 int boardX, boardY, color;
8820 /* Are we animating? */
8821 if (!appData.animateDragging || appData.blindfold)
8825 if (! player.dragActive)
8827 /* Last frame in sequence is square piece is
8828 placed on, which may not match mouse exactly. */
8829 BoardSquare(x, y, &boardX, &boardY);
8830 ScreenSquare(boardX, boardY, &corner, &color);
8831 EndAnimation(&player, &corner);
8833 /* Be sure end square is redrawn */
8834 damage[0][boardY][boardX] = True;
8836 /* This prevents weird things happening with fast successive
8837 clicks which on my Sun at least can cause motion events
8838 without corresponding press/release. */
8839 player.dragActive = False;
8842 /* Handle expose event while piece being dragged */
8847 if (!player.dragActive || appData.blindfold)
8850 /* What we're doing: logically, the move hasn't been made yet,
8851 so the piece is still in it's original square. But visually
8852 it's being dragged around the board. So we erase the square
8853 that the piece is on and draw it at the last known drag point. */
8854 BlankSquare(player.startSquare.x, player.startSquare.y,
8855 player.startColor, EmptySquare, xBoardWindow);
8856 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8857 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8860 #include <sys/ioctl.h>
8861 int get_term_width()
8863 int fd, default_width;
8866 default_width = 79; // this is FICS default anyway...
8868 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8870 if (!ioctl(fd, TIOCGSIZE, &win))
8871 default_width = win.ts_cols;
8872 #elif defined(TIOCGWINSZ)
8874 if (!ioctl(fd, TIOCGWINSZ, &win))
8875 default_width = win.ws_col;
8877 return default_width;
8880 void update_ics_width()
8882 static int old_width = 0;
8883 int new_width = get_term_width();
8885 if (old_width != new_width)
8886 ics_printf("set width %d\n", new_width);
8887 old_width = new_width;
8890 void NotifyFrontendLogin()