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 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
486 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
487 Font clockFontID, coordFontID, countFontID;
488 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
489 XtAppContext appContext;
491 char *oldICSInteractionTitle;
495 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
497 Position commentX = -1, commentY = -1;
498 Dimension commentW, commentH;
499 typedef unsigned int BoardSize;
501 Boolean chessProgram;
503 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
504 int squareSize, smallLayout = 0, tinyLayout = 0,
505 marginW, marginH, // [HGM] for run-time resizing
506 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
507 ICSInputBoxUp = False, askQuestionUp = False,
508 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
509 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
510 Pixel timerForegroundPixel, timerBackgroundPixel;
511 Pixel buttonForegroundPixel, buttonBackgroundPixel;
512 char *chessDir, *programName, *programVersion,
513 *gameCopyFilename, *gamePasteFilename;
514 Boolean alwaysOnTop = False;
515 Boolean saveSettingsOnExit;
516 char *settingsFileName;
517 char *icsTextMenuString;
519 char *firstChessProgramNames;
520 char *secondChessProgramNames;
522 WindowPlacement wpMain;
523 WindowPlacement wpConsole;
524 WindowPlacement wpComment;
525 WindowPlacement wpMoveHistory;
526 WindowPlacement wpEvalGraph;
527 WindowPlacement wpEngineOutput;
528 WindowPlacement wpGameList;
529 WindowPlacement wpTags;
533 Pixmap pieceBitmap[2][(int)BlackPawn];
534 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
535 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
536 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
537 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
538 int useImages, useImageSqs;
539 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
540 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
541 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
542 XImage *ximLightSquare, *ximDarkSquare;
545 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
546 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
548 #define White(piece) ((int)(piece) < (int)BlackPawn)
550 /* Variables for doing smooth animation. This whole thing
551 would be much easier if the board was double-buffered,
552 but that would require a fairly major rewrite. */
557 GC blitGC, pieceGC, outlineGC;
558 XPoint startSquare, prevFrame, mouseDelta;
562 int startBoardX, startBoardY;
565 /* There can be two pieces being animated at once: a player
566 can begin dragging a piece before the remote opponent has moved. */
568 static AnimState game, player;
570 /* Bitmaps for use as masks when drawing XPM pieces.
571 Need one for each black and white piece. */
572 static Pixmap xpmMask[BlackKing + 1];
574 /* This magic number is the number of intermediate frames used
575 in each half of the animation. For short moves it's reduced
576 by 1. The total number of frames will be factor * 2 + 1. */
579 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
581 MenuItem fileMenu[] = {
582 {N_("New Game"), ResetProc},
583 {N_("New Shuffle Game ..."), ShuffleMenuProc},
584 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
585 {"----", NothingProc},
586 {N_("Load Game"), LoadGameProc},
587 {N_("Load Next Game"), LoadNextGameProc},
588 {N_("Load Previous Game"), LoadPrevGameProc},
589 {N_("Reload Same Game"), ReloadGameProc},
590 {N_("Save Game"), SaveGameProc},
591 {"----", NothingProc},
592 {N_("Copy Game"), CopyGameProc},
593 {N_("Paste Game"), PasteGameProc},
594 {"----", NothingProc},
595 {N_("Load Position"), LoadPositionProc},
596 {N_("Load Next Position"), LoadNextPositionProc},
597 {N_("Load Previous Position"), LoadPrevPositionProc},
598 {N_("Reload Same Position"), ReloadPositionProc},
599 {N_("Save Position"), SavePositionProc},
600 {"----", NothingProc},
601 {N_("Copy Position"), CopyPositionProc},
602 {N_("Paste Position"), PastePositionProc},
603 {"----", NothingProc},
604 {N_("Mail Move"), MailMoveProc},
605 {N_("Reload CMail Message"), ReloadCmailMsgProc},
606 {"----", NothingProc},
607 {N_("Exit"), QuitProc},
611 MenuItem modeMenu[] = {
612 {N_("Machine White"), MachineWhiteProc},
613 {N_("Machine Black"), MachineBlackProc},
614 {N_("Two Machines"), TwoMachinesProc},
615 {N_("Analysis Mode"), AnalyzeModeProc},
616 {N_("Analyze File"), AnalyzeFileProc },
617 {N_("ICS Client"), IcsClientProc},
618 {N_("Edit Game"), EditGameProc},
619 {N_("Edit Position"), EditPositionProc},
620 {N_("Training"), TrainingProc},
621 {"----", NothingProc},
622 {N_("Show Engine Output"), EngineOutputProc},
623 {N_("Show Evaluation Graph"), EvalGraphProc},
624 {N_("Show Game List"), ShowGameListProc},
625 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
626 {"----", NothingProc},
627 {N_("Edit Tags"), EditTagsProc},
628 {N_("Edit Comment"), EditCommentProc},
629 {N_("ICS Input Box"), IcsInputBoxProc},
630 {N_("Pause"), PauseProc},
634 MenuItem actionMenu[] = {
635 {N_("Accept"), AcceptProc},
636 {N_("Decline"), DeclineProc},
637 {N_("Rematch"), RematchProc},
638 {"----", NothingProc},
639 {N_("Call Flag"), CallFlagProc},
640 {N_("Draw"), DrawProc},
641 {N_("Adjourn"), AdjournProc},
642 {N_("Abort"), AbortProc},
643 {N_("Resign"), ResignProc},
644 {"----", NothingProc},
645 {N_("Stop Observing"), StopObservingProc},
646 {N_("Stop Examining"), StopExaminingProc},
647 {N_("Upload to Examine"), UploadProc},
648 {"----", NothingProc},
649 {N_("Adjudicate to White"), AdjuWhiteProc},
650 {N_("Adjudicate to Black"), AdjuBlackProc},
651 {N_("Adjudicate Draw"), AdjuDrawProc},
655 MenuItem stepMenu[] = {
656 {N_("Backward"), BackwardProc},
657 {N_("Forward"), ForwardProc},
658 {N_("Back to Start"), ToStartProc},
659 {N_("Forward to End"), ToEndProc},
660 {N_("Revert"), RevertProc},
661 {N_("Annotate"), AnnotateProc},
662 {N_("Truncate Game"), TruncateGameProc},
663 {"----", NothingProc},
664 {N_("Move Now"), MoveNowProc},
665 {N_("Retract Move"), RetractMoveProc},
669 MenuItem optionsMenu[] = {
670 {N_("Flip View"), FlipViewProc},
671 {"----", NothingProc},
672 {N_("Adjudications ..."), EngineMenuProc},
673 {N_("General Settings ..."), UciMenuProc},
674 {N_("Engine #1 Settings ..."), FirstSettingsProc},
675 {N_("Engine #2 Settings ..."), SecondSettingsProc},
676 {N_("Time Control ..."), TimeControlProc},
677 {N_("Game List ..."), GameListOptionsPopUp},
678 {"----", NothingProc},
679 {N_("Always Queen"), AlwaysQueenProc},
680 {N_("Animate Dragging"), AnimateDraggingProc},
681 {N_("Animate Moving"), AnimateMovingProc},
682 {N_("Auto Comment"), AutocommProc},
683 {N_("Auto Flag"), AutoflagProc},
684 {N_("Auto Flip View"), AutoflipProc},
685 {N_("Auto Observe"), AutobsProc},
686 {N_("Auto Raise Board"), AutoraiseProc},
687 {N_("Auto Save"), AutosaveProc},
688 {N_("Blindfold"), BlindfoldProc},
689 {N_("Flash Moves"), FlashMovesProc},
690 {N_("Get Move List"), GetMoveListProc},
692 {N_("Highlight Dragging"), HighlightDraggingProc},
694 {N_("Highlight Last Move"), HighlightLastMoveProc},
695 {N_("Move Sound"), MoveSoundProc},
696 {N_("ICS Alarm"), IcsAlarmProc},
697 {N_("Old Save Style"), OldSaveStyleProc},
698 {N_("Periodic Updates"), PeriodicUpdatesProc},
699 {N_("Ponder Next Move"), PonderNextMoveProc},
700 {N_("Popup Exit Message"), PopupExitMessageProc},
701 {N_("Popup Move Errors"), PopupMoveErrorsProc},
702 {N_("Premove"), PremoveProc},
703 {N_("Quiet Play"), QuietPlayProc},
704 {N_("Show Coords"), ShowCoordsProc},
705 {N_("Hide Thinking"), HideThinkingProc},
706 {N_("Test Legality"), TestLegalityProc},
707 {"----", NothingProc},
708 {N_("Save Settings Now"), SaveSettingsProc},
709 {N_("Save Settings on Exit"), SaveOnExitProc},
713 MenuItem helpMenu[] = {
714 {N_("Info XBoard"), InfoProc},
715 {N_("Man XBoard"), ManProc},
716 {"----", NothingProc},
717 {N_("Hint"), HintProc},
718 {N_("Book"), BookProc},
719 {"----", NothingProc},
720 {N_("About XBoard"), AboutProc},
725 {N_("File"), fileMenu},
726 {N_("Mode"), modeMenu},
727 {N_("Action"), actionMenu},
728 {N_("Step"), stepMenu},
729 {N_("Options"), optionsMenu},
730 {N_("Help"), helpMenu},
734 #define PAUSE_BUTTON N_("P")
735 MenuItem buttonBar[] = {
738 {PAUSE_BUTTON, PauseProc},
744 #define PIECE_MENU_SIZE 18
745 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
746 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
747 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
748 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
749 N_("Empty square"), N_("Clear board") },
750 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
751 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
752 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
753 N_("Empty square"), N_("Clear board") }
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
757 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
759 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
760 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
761 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
762 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
763 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
764 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
767 #define DROP_MENU_SIZE 6
768 String dropMenuStrings[DROP_MENU_SIZE] = {
769 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
771 /* must be in same order as PieceMenuStrings! */
772 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
773 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
774 WhiteRook, WhiteQueen
782 DropMenuEnables dmEnables[] = {
800 { XtNborderWidth, 0 },
801 { XtNdefaultDistance, 0 },
805 { XtNborderWidth, 0 },
806 { XtNresizable, (XtArgVal) True },
810 { XtNborderWidth, 0 },
816 { XtNjustify, (XtArgVal) XtJustifyRight },
817 { XtNlabel, (XtArgVal) "..." },
818 { XtNresizable, (XtArgVal) True },
819 { XtNresize, (XtArgVal) False }
822 Arg messageArgs[] = {
823 { XtNjustify, (XtArgVal) XtJustifyLeft },
824 { XtNlabel, (XtArgVal) "..." },
825 { XtNresizable, (XtArgVal) True },
826 { XtNresize, (XtArgVal) False }
830 { XtNborderWidth, 0 },
831 { XtNjustify, (XtArgVal) XtJustifyLeft }
834 XtResource clientResources[] = {
835 { "flashCount", "flashCount", XtRInt, sizeof(int),
836 XtOffset(AppDataPtr, flashCount), XtRImmediate,
837 (XtPointer) FLASH_COUNT },
840 XrmOptionDescRec shellOptions[] = {
841 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
842 { "-flash", "flashCount", XrmoptionNoArg, "3" },
843 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
846 XtActionsRec boardActions[] = {
847 { "DrawPosition", DrawPositionProc },
848 { "HandleUserMove", HandleUserMove },
849 { "AnimateUserMove", AnimateUserMove },
850 { "HandlePV", HandlePV },
851 { "UnLoadPV", UnLoadPV },
852 { "FileNameAction", FileNameAction },
853 { "AskQuestionProc", AskQuestionProc },
854 { "AskQuestionReplyAction", AskQuestionReplyAction },
855 { "PieceMenuPopup", PieceMenuPopup },
856 { "WhiteClock", WhiteClock },
857 { "BlackClock", BlackClock },
858 { "Iconify", Iconify },
859 { "ResetProc", ResetProc },
860 { "LoadGameProc", LoadGameProc },
861 { "LoadNextGameProc", LoadNextGameProc },
862 { "LoadPrevGameProc", LoadPrevGameProc },
863 { "LoadSelectedProc", LoadSelectedProc },
864 { "SetFilterProc", SetFilterProc },
865 { "ReloadGameProc", ReloadGameProc },
866 { "LoadPositionProc", LoadPositionProc },
867 { "LoadNextPositionProc", LoadNextPositionProc },
868 { "LoadPrevPositionProc", LoadPrevPositionProc },
869 { "ReloadPositionProc", ReloadPositionProc },
870 { "CopyPositionProc", CopyPositionProc },
871 { "PastePositionProc", PastePositionProc },
872 { "CopyGameProc", CopyGameProc },
873 { "PasteGameProc", PasteGameProc },
874 { "SaveGameProc", SaveGameProc },
875 { "SavePositionProc", SavePositionProc },
876 { "MailMoveProc", MailMoveProc },
877 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
878 { "QuitProc", QuitProc },
879 { "MachineWhiteProc", MachineWhiteProc },
880 { "MachineBlackProc", MachineBlackProc },
881 { "AnalysisModeProc", AnalyzeModeProc },
882 { "AnalyzeFileProc", AnalyzeFileProc },
883 { "TwoMachinesProc", TwoMachinesProc },
884 { "IcsClientProc", IcsClientProc },
885 { "EditGameProc", EditGameProc },
886 { "EditPositionProc", EditPositionProc },
887 { "TrainingProc", EditPositionProc },
888 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
889 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
890 { "ShowGameListProc", ShowGameListProc },
891 { "ShowMoveListProc", HistoryShowProc},
892 { "EditTagsProc", EditCommentProc },
893 { "EditCommentProc", EditCommentProc },
894 { "IcsAlarmProc", IcsAlarmProc },
895 { "IcsInputBoxProc", IcsInputBoxProc },
896 { "PauseProc", PauseProc },
897 { "AcceptProc", AcceptProc },
898 { "DeclineProc", DeclineProc },
899 { "RematchProc", RematchProc },
900 { "CallFlagProc", CallFlagProc },
901 { "DrawProc", DrawProc },
902 { "AdjournProc", AdjournProc },
903 { "AbortProc", AbortProc },
904 { "ResignProc", ResignProc },
905 { "AdjuWhiteProc", AdjuWhiteProc },
906 { "AdjuBlackProc", AdjuBlackProc },
907 { "AdjuDrawProc", AdjuDrawProc },
908 { "EnterKeyProc", EnterKeyProc },
909 { "UpKeyProc", UpKeyProc },
910 { "DownKeyProc", DownKeyProc },
911 { "StopObservingProc", StopObservingProc },
912 { "StopExaminingProc", StopExaminingProc },
913 { "UploadProc", UploadProc },
914 { "BackwardProc", BackwardProc },
915 { "ForwardProc", ForwardProc },
916 { "ToStartProc", ToStartProc },
917 { "ToEndProc", ToEndProc },
918 { "RevertProc", RevertProc },
919 { "AnnotateProc", AnnotateProc },
920 { "TruncateGameProc", TruncateGameProc },
921 { "MoveNowProc", MoveNowProc },
922 { "RetractMoveProc", RetractMoveProc },
923 { "AlwaysQueenProc", AlwaysQueenProc },
924 { "AnimateDraggingProc", AnimateDraggingProc },
925 { "AnimateMovingProc", AnimateMovingProc },
926 { "AutoflagProc", AutoflagProc },
927 { "AutoflipProc", AutoflipProc },
928 { "AutobsProc", AutobsProc },
929 { "AutoraiseProc", AutoraiseProc },
930 { "AutosaveProc", AutosaveProc },
931 { "BlindfoldProc", BlindfoldProc },
932 { "FlashMovesProc", FlashMovesProc },
933 { "FlipViewProc", FlipViewProc },
934 { "GetMoveListProc", GetMoveListProc },
936 { "HighlightDraggingProc", HighlightDraggingProc },
938 { "HighlightLastMoveProc", HighlightLastMoveProc },
939 { "IcsAlarmProc", IcsAlarmProc },
940 { "MoveSoundProc", MoveSoundProc },
941 { "OldSaveStyleProc", OldSaveStyleProc },
942 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
943 { "PonderNextMoveProc", PonderNextMoveProc },
944 { "PopupExitMessageProc", PopupExitMessageProc },
945 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
946 { "PremoveProc", PremoveProc },
947 { "QuietPlayProc", QuietPlayProc },
948 { "ShowCoordsProc", ShowCoordsProc },
949 { "ShowThinkingProc", ShowThinkingProc },
950 { "HideThinkingProc", HideThinkingProc },
951 { "TestLegalityProc", TestLegalityProc },
952 { "SaveSettingsProc", SaveSettingsProc },
953 { "SaveOnExitProc", SaveOnExitProc },
954 { "InfoProc", InfoProc },
955 { "ManProc", ManProc },
956 { "HintProc", HintProc },
957 { "BookProc", BookProc },
958 { "AboutGameProc", AboutGameProc },
959 { "AboutProc", AboutProc },
960 { "DebugProc", DebugProc },
961 { "NothingProc", NothingProc },
962 { "CommentPopDown", (XtActionProc) CommentPopDown },
963 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
964 { "TagsPopDown", (XtActionProc) TagsPopDown },
965 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
966 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
967 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
968 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
969 { "GameListPopDown", (XtActionProc) GameListPopDown },
970 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
971 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
972 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
973 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
974 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
975 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
976 { "EnginePopDown", (XtActionProc) EnginePopDown },
977 { "UciPopDown", (XtActionProc) UciPopDown },
978 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
979 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
980 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
981 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
984 char globalTranslations[] =
985 ":<Key>R: ResignProc() \n \
986 :<Key>r: ResetProc() \n \
987 :<Key>g: LoadGameProc() \n \
988 :<Key>N: LoadNextGameProc() \n \
989 :<Key>P: LoadPrevGameProc() \n \
990 :<Key>Q: QuitProc() \n \
991 :<Key>F: ToEndProc() \n \
992 :<Key>f: ForwardProc() \n \
993 :<Key>B: ToStartProc() \n \
994 :<Key>b: BackwardProc() \n \
995 :<Key>p: PauseProc() \n \
996 :<Key>d: DrawProc() \n \
997 :<Key>t: CallFlagProc() \n \
998 :<Key>i: Iconify() \n \
999 :<Key>c: Iconify() \n \
1000 :<Key>v: FlipViewProc() \n \
1001 <KeyDown>Control_L: BackwardProc() \n \
1002 <KeyUp>Control_L: ForwardProc() \n \
1003 <KeyDown>Control_R: BackwardProc() \n \
1004 <KeyUp>Control_R: ForwardProc() \n \
1005 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1006 \"Send to chess program:\",,1) \n \
1007 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1008 \"Send to second chess program:\",,2) \n";
1010 char boardTranslations[] =
1011 "<Btn1Down>: HandleUserMove() \n \
1012 <Btn1Up>: HandleUserMove() \n \
1013 <Btn1Motion>: AnimateUserMove() \n \
1014 <Btn3Motion>: HandlePV() \n \
1015 <Btn3Up>: PieceMenuPopup(menuB) \n \
1016 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1017 PieceMenuPopup(menuB) \n \
1018 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1019 PieceMenuPopup(menuW) \n \
1020 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1021 PieceMenuPopup(menuW) \n \
1022 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1023 PieceMenuPopup(menuB) \n";
1025 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1026 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1028 char ICSInputTranslations[] =
1029 "<Key>Up: UpKeyProc() \n "
1030 "<Key>Down: DownKeyProc() \n "
1031 "<Key>Return: EnterKeyProc() \n";
1033 String xboardResources[] = {
1034 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1035 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1036 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1041 /* Max possible square size */
1042 #define MAXSQSIZE 256
1044 static int xpm_avail[MAXSQSIZE];
1046 #ifdef HAVE_DIR_STRUCT
1048 /* Extract piece size from filename */
1050 xpm_getsize(name, len, ext)
1061 if ((p=strchr(name, '.')) == NULL ||
1062 StrCaseCmp(p+1, ext) != 0)
1068 while (*p && isdigit(*p))
1075 /* Setup xpm_avail */
1077 xpm_getavail(dirname, ext)
1085 for (i=0; i<MAXSQSIZE; ++i)
1088 if (appData.debugMode)
1089 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1091 dir = opendir(dirname);
1094 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1095 programName, dirname);
1099 while ((ent=readdir(dir)) != NULL) {
1100 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1101 if (i > 0 && i < MAXSQSIZE)
1111 xpm_print_avail(fp, ext)
1117 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1118 for (i=1; i<MAXSQSIZE; ++i) {
1124 /* Return XPM piecesize closest to size */
1126 xpm_closest_to(dirname, size, ext)
1132 int sm_diff = MAXSQSIZE;
1136 xpm_getavail(dirname, ext);
1138 if (appData.debugMode)
1139 xpm_print_avail(stderr, ext);
1141 for (i=1; i<MAXSQSIZE; ++i) {
1144 diff = (diff<0) ? -diff : diff;
1145 if (diff < sm_diff) {
1153 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1159 #else /* !HAVE_DIR_STRUCT */
1160 /* If we are on a system without a DIR struct, we can't
1161 read the directory, so we can't collect a list of
1162 filenames, etc., so we can't do any size-fitting. */
1164 xpm_closest_to(dirname, size, ext)
1169 fprintf(stderr, _("\
1170 Warning: No DIR structure found on this system --\n\
1171 Unable to autosize for XPM/XIM pieces.\n\
1172 Please report this error to frankm@hiwaay.net.\n\
1173 Include system type & operating system in message.\n"));
1176 #endif /* HAVE_DIR_STRUCT */
1178 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1179 "magenta", "cyan", "white" };
1183 TextColors textColors[(int)NColorClasses];
1185 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1187 parse_color(str, which)
1191 char *p, buf[100], *d;
1194 if (strlen(str) > 99) /* watch bounds on buf */
1199 for (i=0; i<which; ++i) {
1206 /* Could be looking at something like:
1208 .. in which case we want to stop on a comma also */
1209 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1213 return -1; /* Use default for empty field */
1216 if (which == 2 || isdigit(*p))
1219 while (*p && isalpha(*p))
1224 for (i=0; i<8; ++i) {
1225 if (!StrCaseCmp(buf, cnames[i]))
1226 return which? (i+40) : (i+30);
1228 if (!StrCaseCmp(buf, "default")) return -1;
1230 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1235 parse_cpair(cc, str)
1239 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1240 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1245 /* bg and attr are optional */
1246 textColors[(int)cc].bg = parse_color(str, 1);
1247 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1248 textColors[(int)cc].attr = 0;
1254 /* Arrange to catch delete-window events */
1255 Atom wm_delete_window;
1257 CatchDeleteWindow(Widget w, String procname)
1260 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1261 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1262 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1269 XtSetArg(args[0], XtNiconic, False);
1270 XtSetValues(shellWidget, args, 1);
1272 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1275 //---------------------------------------------------------------------------------------------------------
1276 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1279 #define CW_USEDEFAULT (1<<31)
1280 #define ICS_TEXT_MENU_SIZE 90
1281 #define DEBUG_FILE "xboard.debug"
1282 #define SetCurrentDirectory chdir
1283 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1287 // these two must some day move to frontend.h, when they are implemented
1288 Boolean GameListIsUp();
1290 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1293 // front-end part of option handling
1295 // [HGM] This platform-dependent table provides the location for storing the color info
1296 extern char *crWhite, * crBlack;
1300 &appData.whitePieceColor,
1301 &appData.blackPieceColor,
1302 &appData.lightSquareColor,
1303 &appData.darkSquareColor,
1304 &appData.highlightSquareColor,
1305 &appData.premoveHighlightColor,
1306 &appData.lowTimeWarningColor,
1317 // [HGM] font: keep a font for each square size, even non-stndard ones
1318 #define NUM_SIZES 18
1319 #define MAX_SIZE 130
1320 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1321 char *fontTable[NUM_FONTS][MAX_SIZE];
1324 ParseFont(char *name, int number)
1325 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1327 if(sscanf(name, "size%d:", &size)) {
1328 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1329 // defer processing it until we know if it matches our board size
1330 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1331 fontTable[number][size] = strdup(strchr(name, ':')+1);
1332 fontValid[number][size] = True;
1337 case 0: // CLOCK_FONT
1338 appData.clockFont = strdup(name);
1340 case 1: // MESSAGE_FONT
1341 appData.font = strdup(name);
1343 case 2: // COORD_FONT
1344 appData.coordFont = strdup(name);
1349 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1354 { // only 2 fonts currently
1355 appData.clockFont = CLOCK_FONT_NAME;
1356 appData.coordFont = COORD_FONT_NAME;
1357 appData.font = DEFAULT_FONT_NAME;
1362 { // no-op, until we identify the code for this already in XBoard and move it here
1366 ParseColor(int n, char *name)
1367 { // in XBoard, just copy the color-name string
1368 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1372 ParseTextAttribs(ColorClass cc, char *s)
1374 (&appData.colorShout)[cc] = strdup(s);
1378 ParseBoardSize(void *addr, char *name)
1380 appData.boardSize = strdup(name);
1385 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1389 SetCommPortDefaults()
1390 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1393 // [HGM] args: these three cases taken out to stay in front-end
1395 SaveFontArg(FILE *f, ArgDescriptor *ad)
1397 char *name, buf[MSG_SIZ];
1398 int i, n = (int)ad->argLoc;
1400 case 0: // CLOCK_FONT
1401 name = appData.clockFont;
1403 case 1: // MESSAGE_FONT
1404 name = appData.font;
1406 case 2: // COORD_FONT
1407 name = appData.coordFont;
1412 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1413 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1414 fontTable[n][squareSize] = strdup(name);
1415 fontValid[n][squareSize] = True;
1418 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1419 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1424 { // nothing to do, as the sounds are at all times represented by their text-string names already
1428 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1429 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1430 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1434 SaveColor(FILE *f, ArgDescriptor *ad)
1435 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1436 if(colorVariable[(int)ad->argLoc])
1437 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1441 SaveBoardSize(FILE *f, char *name, void *addr)
1442 { // wrapper to shield back-end from BoardSize & sizeInfo
1443 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1447 ParseCommPortSettings(char *s)
1448 { // no such option in XBoard (yet)
1451 extern Widget engineOutputShell;
1452 extern Widget tagsShell, editTagsShell;
1454 GetActualPlacement(Widget wg, WindowPlacement *wp)
1464 XtSetArg(args[i], XtNx, &x); i++;
1465 XtSetArg(args[i], XtNy, &y); i++;
1466 XtSetArg(args[i], XtNwidth, &w); i++;
1467 XtSetArg(args[i], XtNheight, &h); i++;
1468 XtGetValues(wg, args, i);
1477 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1478 // In XBoard this will have to wait until awareness of window parameters is implemented
1479 GetActualPlacement(shellWidget, &wpMain);
1480 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1481 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1482 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1483 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1484 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1485 else GetActualPlacement(editShell, &wpComment);
1486 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1487 else GetActualPlacement(editTagsShell, &wpTags);
1491 PrintCommPortSettings(FILE *f, char *name)
1492 { // This option does not exist in XBoard
1496 MySearchPath(char *installDir, char *name, char *fullname)
1497 { // just append installDir and name. Perhaps ExpandPath should be used here?
1498 name = ExpandPathName(name);
1499 if(name && name[0] == '/') strcpy(fullname, name); else {
1500 sprintf(fullname, "%s%c%s", installDir, '/', name);
1506 MyGetFullPathName(char *name, char *fullname)
1507 { // should use ExpandPath?
1508 name = ExpandPathName(name);
1509 strcpy(fullname, name);
1514 EnsureOnScreen(int *x, int *y, int minX, int minY)
1521 { // [HGM] args: allows testing if main window is realized from back-end
1522 return xBoardWindow != 0;
1526 PopUpStartupDialog()
1527 { // start menu not implemented in XBoard
1530 ConvertToLine(int argc, char **argv)
1532 static char line[128*1024], buf[1024];
1536 for(i=1; i<argc; i++) {
1537 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1538 && argv[i][0] != '{' )
1539 sprintf(buf, "{%s} ", argv[i]);
1540 else sprintf(buf, "%s ", argv[i]);
1543 line[strlen(line)-1] = NULLCHAR;
1547 //--------------------------------------------------------------------------------------------
1550 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1552 #define BoardSize int
1553 void InitDrawingSizes(BoardSize boardSize, int flags)
1554 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1555 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1557 XtGeometryResult gres;
1560 if(!formWidget) return;
1563 * Enable shell resizing.
1565 shellArgs[0].value = (XtArgVal) &w;
1566 shellArgs[1].value = (XtArgVal) &h;
1567 XtGetValues(shellWidget, shellArgs, 2);
1569 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1570 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1571 XtSetValues(shellWidget, &shellArgs[2], 4);
1573 XtSetArg(args[0], XtNdefaultDistance, &sep);
1574 XtGetValues(formWidget, args, 1);
1576 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1577 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1580 XtSetArg(args[0], XtNwidth, boardWidth);
1581 XtSetArg(args[1], XtNheight, boardHeight);
1582 XtSetValues(boardWidget, args, 2);
1584 timerWidth = (boardWidth - sep) / 2;
1585 XtSetArg(args[0], XtNwidth, timerWidth);
1586 XtSetValues(whiteTimerWidget, args, 1);
1587 XtSetValues(blackTimerWidget, args, 1);
1589 XawFormDoLayout(formWidget, False);
1591 if (appData.titleInWindow) {
1593 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1594 XtSetArg(args[i], XtNheight, &h); i++;
1595 XtGetValues(titleWidget, args, i);
1597 w = boardWidth - 2*bor;
1599 XtSetArg(args[0], XtNwidth, &w);
1600 XtGetValues(menuBarWidget, args, 1);
1601 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1604 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1605 if (gres != XtGeometryYes && appData.debugMode) {
1607 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1608 programName, gres, w, h, wr, hr);
1612 XawFormDoLayout(formWidget, True);
1615 * Inhibit shell resizing.
1617 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1618 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1619 shellArgs[4].value = shellArgs[2].value = w;
1620 shellArgs[5].value = shellArgs[3].value = h;
1621 XtSetValues(shellWidget, &shellArgs[0], 6);
1623 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1626 for(i=0; i<4; i++) {
1628 for(p=0; p<=(int)WhiteKing; p++)
1629 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1630 if(gameInfo.variant == VariantShogi) {
1631 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1632 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1633 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1634 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1635 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1638 if(gameInfo.variant == VariantGothic) {
1639 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1643 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1644 for(p=0; p<=(int)WhiteKing; p++)
1645 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1646 if(gameInfo.variant == VariantShogi) {
1647 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1648 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1649 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1650 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1651 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1654 if(gameInfo.variant == VariantGothic) {
1655 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1661 for(i=0; i<2; i++) {
1663 for(p=0; p<=(int)WhiteKing; p++)
1664 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1665 if(gameInfo.variant == VariantShogi) {
1666 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1667 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1668 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1669 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1670 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1673 if(gameInfo.variant == VariantGothic) {
1674 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1685 void EscapeExpand(char *p, char *q)
1686 { // [HGM] initstring: routine to shape up string arguments
1687 while(*p++ = *q++) if(p[-1] == '\\')
1689 case 'n': p[-1] = '\n'; break;
1690 case 'r': p[-1] = '\r'; break;
1691 case 't': p[-1] = '\t'; break;
1692 case '\\': p[-1] = '\\'; break;
1693 case 0: *p = 0; return;
1694 default: p[-1] = q[-1]; break;
1703 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1704 XSetWindowAttributes window_attributes;
1706 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1707 XrmValue vFrom, vTo;
1708 XtGeometryResult gres;
1711 int forceMono = False;
1713 srandom(time(0)); // [HGM] book: make random truly random
1715 setbuf(stdout, NULL);
1716 setbuf(stderr, NULL);
1719 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1720 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1724 programName = strrchr(argv[0], '/');
1725 if (programName == NULL)
1726 programName = argv[0];
1731 XtSetLanguageProc(NULL, NULL, NULL);
1732 bindtextdomain(PACKAGE, LOCALEDIR);
1733 textdomain(PACKAGE);
1737 XtAppInitialize(&appContext, "XBoard", shellOptions,
1738 XtNumber(shellOptions),
1739 &argc, argv, xboardResources, NULL, 0);
1740 appData.boardSize = "";
1741 InitAppData(ConvertToLine(argc, argv));
1743 if (p == NULL) p = "/tmp";
1744 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1745 gameCopyFilename = (char*) malloc(i);
1746 gamePasteFilename = (char*) malloc(i);
1747 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1748 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1750 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1751 clientResources, XtNumber(clientResources),
1754 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1755 static char buf[MSG_SIZ];
1756 EscapeExpand(buf, appData.initString);
1757 appData.initString = strdup(buf);
1758 EscapeExpand(buf, appData.secondInitString);
1759 appData.secondInitString = strdup(buf);
1760 EscapeExpand(buf, appData.firstComputerString);
1761 appData.firstComputerString = strdup(buf);
1762 EscapeExpand(buf, appData.secondComputerString);
1763 appData.secondComputerString = strdup(buf);
1766 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1769 if (chdir(chessDir) != 0) {
1770 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1776 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1777 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1778 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1779 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1782 setbuf(debugFP, NULL);
1785 /* [HGM,HR] make sure board size is acceptable */
1786 if(appData.NrFiles > BOARD_FILES ||
1787 appData.NrRanks > BOARD_RANKS )
1788 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1791 /* This feature does not work; animation needs a rewrite */
1792 appData.highlightDragging = FALSE;
1796 xDisplay = XtDisplay(shellWidget);
1797 xScreen = DefaultScreen(xDisplay);
1798 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1800 gameInfo.variant = StringToVariant(appData.variant);
1801 InitPosition(FALSE);
1804 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1806 if (isdigit(appData.boardSize[0])) {
1807 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1808 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1809 &fontPxlSize, &smallLayout, &tinyLayout);
1811 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1812 programName, appData.boardSize);
1816 /* Find some defaults; use the nearest known size */
1817 SizeDefaults *szd, *nearest;
1818 int distance = 99999;
1819 nearest = szd = sizeDefaults;
1820 while (szd->name != NULL) {
1821 if (abs(szd->squareSize - squareSize) < distance) {
1823 distance = abs(szd->squareSize - squareSize);
1824 if (distance == 0) break;
1828 if (i < 2) lineGap = nearest->lineGap;
1829 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1830 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1831 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1832 if (i < 6) smallLayout = nearest->smallLayout;
1833 if (i < 7) tinyLayout = nearest->tinyLayout;
1836 SizeDefaults *szd = sizeDefaults;
1837 if (*appData.boardSize == NULLCHAR) {
1838 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1839 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1842 if (szd->name == NULL) szd--;
1843 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1845 while (szd->name != NULL &&
1846 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1847 if (szd->name == NULL) {
1848 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1849 programName, appData.boardSize);
1853 squareSize = szd->squareSize;
1854 lineGap = szd->lineGap;
1855 clockFontPxlSize = szd->clockFontPxlSize;
1856 coordFontPxlSize = szd->coordFontPxlSize;
1857 fontPxlSize = szd->fontPxlSize;
1858 smallLayout = szd->smallLayout;
1859 tinyLayout = szd->tinyLayout;
1860 // [HGM] font: use defaults from settings file if available and not overruled
1862 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1863 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1864 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1865 appData.font = fontTable[MESSAGE_FONT][squareSize];
1866 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1867 appData.coordFont = fontTable[COORD_FONT][squareSize];
1869 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1870 if (strlen(appData.pixmapDirectory) > 0) {
1871 p = ExpandPathName(appData.pixmapDirectory);
1873 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1874 appData.pixmapDirectory);
1877 if (appData.debugMode) {
1878 fprintf(stderr, _("\
1879 XBoard square size (hint): %d\n\
1880 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1882 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1883 if (appData.debugMode) {
1884 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1888 /* [HR] height treated separately (hacked) */
1889 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1890 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1891 if (appData.showJail == 1) {
1892 /* Jail on top and bottom */
1893 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1894 XtSetArg(boardArgs[2], XtNheight,
1895 boardHeight + 2*(lineGap + squareSize));
1896 } else if (appData.showJail == 2) {
1898 XtSetArg(boardArgs[1], XtNwidth,
1899 boardWidth + 2*(lineGap + squareSize));
1900 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1903 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1904 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1908 * Determine what fonts to use.
1910 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1911 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1912 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1913 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1914 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1915 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1916 appData.font = FindFont(appData.font, fontPxlSize);
1917 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1918 countFontStruct = XQueryFont(xDisplay, countFontID);
1919 // appData.font = FindFont(appData.font, fontPxlSize);
1921 xdb = XtDatabase(xDisplay);
1922 XrmPutStringResource(&xdb, "*font", appData.font);
1925 * Detect if there are not enough colors available and adapt.
1927 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1928 appData.monoMode = True;
1931 if (!appData.monoMode) {
1932 vFrom.addr = (caddr_t) appData.lightSquareColor;
1933 vFrom.size = strlen(appData.lightSquareColor);
1934 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1935 if (vTo.addr == NULL) {
1936 appData.monoMode = True;
1939 lightSquareColor = *(Pixel *) vTo.addr;
1942 if (!appData.monoMode) {
1943 vFrom.addr = (caddr_t) appData.darkSquareColor;
1944 vFrom.size = strlen(appData.darkSquareColor);
1945 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1946 if (vTo.addr == NULL) {
1947 appData.monoMode = True;
1950 darkSquareColor = *(Pixel *) vTo.addr;
1953 if (!appData.monoMode) {
1954 vFrom.addr = (caddr_t) appData.whitePieceColor;
1955 vFrom.size = strlen(appData.whitePieceColor);
1956 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1957 if (vTo.addr == NULL) {
1958 appData.monoMode = True;
1961 whitePieceColor = *(Pixel *) vTo.addr;
1964 if (!appData.monoMode) {
1965 vFrom.addr = (caddr_t) appData.blackPieceColor;
1966 vFrom.size = strlen(appData.blackPieceColor);
1967 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1968 if (vTo.addr == NULL) {
1969 appData.monoMode = True;
1972 blackPieceColor = *(Pixel *) vTo.addr;
1976 if (!appData.monoMode) {
1977 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1978 vFrom.size = strlen(appData.highlightSquareColor);
1979 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1980 if (vTo.addr == NULL) {
1981 appData.monoMode = True;
1984 highlightSquareColor = *(Pixel *) vTo.addr;
1988 if (!appData.monoMode) {
1989 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1990 vFrom.size = strlen(appData.premoveHighlightColor);
1991 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1992 if (vTo.addr == NULL) {
1993 appData.monoMode = True;
1996 premoveHighlightColor = *(Pixel *) vTo.addr;
2001 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2004 if (appData.bitmapDirectory == NULL ||
2005 appData.bitmapDirectory[0] == NULLCHAR)
2006 appData.bitmapDirectory = DEF_BITMAP_DIR;
2009 if (appData.lowTimeWarning && !appData.monoMode) {
2010 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2011 vFrom.size = strlen(appData.lowTimeWarningColor);
2012 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2013 if (vTo.addr == NULL)
2014 appData.monoMode = True;
2016 lowTimeWarningColor = *(Pixel *) vTo.addr;
2019 if (appData.monoMode && appData.debugMode) {
2020 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2021 (unsigned long) XWhitePixel(xDisplay, xScreen),
2022 (unsigned long) XBlackPixel(xDisplay, xScreen));
2025 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2026 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2027 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2028 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2029 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2030 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2031 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2032 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2033 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2034 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2036 if (appData.colorize) {
2038 _("%s: can't parse color names; disabling colorization\n"),
2041 appData.colorize = FALSE;
2043 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2044 textColors[ColorNone].attr = 0;
2046 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2052 layoutName = "tinyLayout";
2053 } else if (smallLayout) {
2054 layoutName = "smallLayout";
2056 layoutName = "normalLayout";
2058 /* Outer layoutWidget is there only to provide a name for use in
2059 resources that depend on the layout style */
2061 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2062 layoutArgs, XtNumber(layoutArgs));
2064 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2065 formArgs, XtNumber(formArgs));
2066 XtSetArg(args[0], XtNdefaultDistance, &sep);
2067 XtGetValues(formWidget, args, 1);
2070 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2071 XtSetArg(args[0], XtNtop, XtChainTop);
2072 XtSetArg(args[1], XtNbottom, XtChainTop);
2073 XtSetArg(args[2], XtNright, XtChainLeft);
2074 XtSetValues(menuBarWidget, args, 3);
2076 widgetList[j++] = whiteTimerWidget =
2077 XtCreateWidget("whiteTime", labelWidgetClass,
2078 formWidget, timerArgs, XtNumber(timerArgs));
2079 XtSetArg(args[0], XtNfont, clockFontStruct);
2080 XtSetArg(args[1], XtNtop, XtChainTop);
2081 XtSetArg(args[2], XtNbottom, XtChainTop);
2082 XtSetValues(whiteTimerWidget, args, 3);
2084 widgetList[j++] = blackTimerWidget =
2085 XtCreateWidget("blackTime", labelWidgetClass,
2086 formWidget, timerArgs, XtNumber(timerArgs));
2087 XtSetArg(args[0], XtNfont, clockFontStruct);
2088 XtSetArg(args[1], XtNtop, XtChainTop);
2089 XtSetArg(args[2], XtNbottom, XtChainTop);
2090 XtSetValues(blackTimerWidget, args, 3);
2092 if (appData.titleInWindow) {
2093 widgetList[j++] = titleWidget =
2094 XtCreateWidget("title", labelWidgetClass, formWidget,
2095 titleArgs, XtNumber(titleArgs));
2096 XtSetArg(args[0], XtNtop, XtChainTop);
2097 XtSetArg(args[1], XtNbottom, XtChainTop);
2098 XtSetValues(titleWidget, args, 2);
2101 if (appData.showButtonBar) {
2102 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2103 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2104 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2105 XtSetArg(args[2], XtNtop, XtChainTop);
2106 XtSetArg(args[3], XtNbottom, XtChainTop);
2107 XtSetValues(buttonBarWidget, args, 4);
2110 widgetList[j++] = messageWidget =
2111 XtCreateWidget("message", labelWidgetClass, formWidget,
2112 messageArgs, XtNumber(messageArgs));
2113 XtSetArg(args[0], XtNtop, XtChainTop);
2114 XtSetArg(args[1], XtNbottom, XtChainTop);
2115 XtSetValues(messageWidget, args, 2);
2117 widgetList[j++] = boardWidget =
2118 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2119 XtNumber(boardArgs));
2121 XtManageChildren(widgetList, j);
2123 timerWidth = (boardWidth - sep) / 2;
2124 XtSetArg(args[0], XtNwidth, timerWidth);
2125 XtSetValues(whiteTimerWidget, args, 1);
2126 XtSetValues(blackTimerWidget, args, 1);
2128 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2129 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2130 XtGetValues(whiteTimerWidget, args, 2);
2132 if (appData.showButtonBar) {
2133 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2134 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2135 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2139 * formWidget uses these constraints but they are stored
2143 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2144 XtSetValues(menuBarWidget, args, i);
2145 if (appData.titleInWindow) {
2148 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2149 XtSetValues(whiteTimerWidget, args, i);
2151 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2152 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2153 XtSetValues(blackTimerWidget, args, i);
2155 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2156 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2157 XtSetValues(titleWidget, args, i);
2159 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2160 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2161 XtSetValues(messageWidget, args, i);
2162 if (appData.showButtonBar) {
2164 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2165 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2166 XtSetValues(buttonBarWidget, args, i);
2170 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2171 XtSetValues(whiteTimerWidget, args, i);
2173 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2174 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2175 XtSetValues(blackTimerWidget, args, i);
2177 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2178 XtSetValues(titleWidget, args, i);
2180 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2181 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2182 XtSetValues(messageWidget, args, i);
2183 if (appData.showButtonBar) {
2185 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2186 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2187 XtSetValues(buttonBarWidget, args, i);
2192 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2193 XtSetValues(whiteTimerWidget, args, i);
2195 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2196 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2197 XtSetValues(blackTimerWidget, args, i);
2199 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2200 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2201 XtSetValues(messageWidget, args, i);
2202 if (appData.showButtonBar) {
2204 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2205 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2206 XtSetValues(buttonBarWidget, args, i);
2210 XtSetArg(args[0], XtNfromVert, messageWidget);
2211 XtSetArg(args[1], XtNtop, XtChainTop);
2212 XtSetArg(args[2], XtNbottom, XtChainBottom);
2213 XtSetArg(args[3], XtNleft, XtChainLeft);
2214 XtSetArg(args[4], XtNright, XtChainRight);
2215 XtSetValues(boardWidget, args, 5);
2217 XtRealizeWidget(shellWidget);
2220 XtSetArg(args[0], XtNx, wpMain.x);
2221 XtSetArg(args[1], XtNy, wpMain.y);
2222 XtSetValues(shellWidget, args, 2);
2226 * Correct the width of the message and title widgets.
2227 * It is not known why some systems need the extra fudge term.
2228 * The value "2" is probably larger than needed.
2230 XawFormDoLayout(formWidget, False);
2232 #define WIDTH_FUDGE 2
2234 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2235 XtSetArg(args[i], XtNheight, &h); i++;
2236 XtGetValues(messageWidget, args, i);
2237 if (appData.showButtonBar) {
2239 XtSetArg(args[i], XtNwidth, &w); i++;
2240 XtGetValues(buttonBarWidget, args, i);
2241 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2243 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2246 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2247 if (gres != XtGeometryYes && appData.debugMode) {
2248 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2249 programName, gres, w, h, wr, hr);
2252 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2253 /* The size used for the child widget in layout lags one resize behind
2254 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
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 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2263 XtSetArg(args[1], XtNright, XtChainRight);
2264 XtSetValues(messageWidget, args, 2);
2266 if (appData.titleInWindow) {
2268 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2269 XtSetArg(args[i], XtNheight, &h); i++;
2270 XtGetValues(titleWidget, args, i);
2272 w = boardWidth - 2*bor;
2274 XtSetArg(args[0], XtNwidth, &w);
2275 XtGetValues(menuBarWidget, args, 1);
2276 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2279 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2280 if (gres != XtGeometryYes && appData.debugMode) {
2282 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2283 programName, gres, w, h, wr, hr);
2286 XawFormDoLayout(formWidget, True);
2288 xBoardWindow = XtWindow(boardWidget);
2290 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2291 // not need to go into InitDrawingSizes().
2295 * Create X checkmark bitmap and initialize option menu checks.
2297 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2298 checkmark_bits, checkmark_width, checkmark_height);
2299 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2300 if (appData.alwaysPromoteToQueen) {
2301 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2304 if (appData.animateDragging) {
2305 XtSetValues(XtNameToWidget(menuBarWidget,
2306 "menuOptions.Animate Dragging"),
2309 if (appData.animate) {
2310 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2313 if (appData.autoComment) {
2314 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2317 if (appData.autoCallFlag) {
2318 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2321 if (appData.autoFlipView) {
2322 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2325 if (appData.autoObserve) {
2326 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2329 if (appData.autoRaiseBoard) {
2330 XtSetValues(XtNameToWidget(menuBarWidget,
2331 "menuOptions.Auto Raise Board"), args, 1);
2333 if (appData.autoSaveGames) {
2334 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2337 if (appData.saveGameFile[0] != NULLCHAR) {
2338 /* Can't turn this off from menu */
2339 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2341 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2345 if (appData.blindfold) {
2346 XtSetValues(XtNameToWidget(menuBarWidget,
2347 "menuOptions.Blindfold"), args, 1);
2349 if (appData.flashCount > 0) {
2350 XtSetValues(XtNameToWidget(menuBarWidget,
2351 "menuOptions.Flash Moves"),
2354 if (appData.getMoveList) {
2355 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2359 if (appData.highlightDragging) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,
2361 "menuOptions.Highlight Dragging"),
2365 if (appData.highlightLastMove) {
2366 XtSetValues(XtNameToWidget(menuBarWidget,
2367 "menuOptions.Highlight Last Move"),
2370 if (appData.icsAlarm) {
2371 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2374 if (appData.ringBellAfterMoves) {
2375 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2378 if (appData.oldSaveStyle) {
2379 XtSetValues(XtNameToWidget(menuBarWidget,
2380 "menuOptions.Old Save Style"), args, 1);
2382 if (appData.periodicUpdates) {
2383 XtSetValues(XtNameToWidget(menuBarWidget,
2384 "menuOptions.Periodic Updates"), args, 1);
2386 if (appData.ponderNextMove) {
2387 XtSetValues(XtNameToWidget(menuBarWidget,
2388 "menuOptions.Ponder Next Move"), args, 1);
2390 if (appData.popupExitMessage) {
2391 XtSetValues(XtNameToWidget(menuBarWidget,
2392 "menuOptions.Popup Exit Message"), args, 1);
2394 if (appData.popupMoveErrors) {
2395 XtSetValues(XtNameToWidget(menuBarWidget,
2396 "menuOptions.Popup Move Errors"), args, 1);
2398 if (appData.premove) {
2399 XtSetValues(XtNameToWidget(menuBarWidget,
2400 "menuOptions.Premove"), args, 1);
2402 if (appData.quietPlay) {
2403 XtSetValues(XtNameToWidget(menuBarWidget,
2404 "menuOptions.Quiet Play"), args, 1);
2406 if (appData.showCoords) {
2407 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2410 if (appData.hideThinkingFromHuman) {
2411 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2414 if (appData.testLegality) {
2415 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2418 if (saveSettingsOnExit) {
2419 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2426 ReadBitmap(&wIconPixmap, "icon_white.bm",
2427 icon_white_bits, icon_white_width, icon_white_height);
2428 ReadBitmap(&bIconPixmap, "icon_black.bm",
2429 icon_black_bits, icon_black_width, icon_black_height);
2430 iconPixmap = wIconPixmap;
2432 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2433 XtSetValues(shellWidget, args, i);
2436 * Create a cursor for the board widget.
2438 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2439 XChangeWindowAttributes(xDisplay, xBoardWindow,
2440 CWCursor, &window_attributes);
2443 * Inhibit shell resizing.
2445 shellArgs[0].value = (XtArgVal) &w;
2446 shellArgs[1].value = (XtArgVal) &h;
2447 XtGetValues(shellWidget, shellArgs, 2);
2448 shellArgs[4].value = shellArgs[2].value = w;
2449 shellArgs[5].value = shellArgs[3].value = h;
2450 XtSetValues(shellWidget, &shellArgs[2], 4);
2451 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2452 marginH = h - boardHeight;
2454 CatchDeleteWindow(shellWidget, "QuitProc");
2459 if (appData.bitmapDirectory[0] != NULLCHAR) {
2466 /* Create regular pieces */
2467 if (!useImages) CreatePieces();
2472 if (appData.animate || appData.animateDragging)
2475 XtAugmentTranslations(formWidget,
2476 XtParseTranslationTable(globalTranslations));
2477 XtAugmentTranslations(boardWidget,
2478 XtParseTranslationTable(boardTranslations));
2479 XtAugmentTranslations(whiteTimerWidget,
2480 XtParseTranslationTable(whiteTranslations));
2481 XtAugmentTranslations(blackTimerWidget,
2482 XtParseTranslationTable(blackTranslations));
2484 /* Why is the following needed on some versions of X instead
2485 * of a translation? */
2486 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2487 (XtEventHandler) EventProc, NULL);
2490 /* [AS] Restore layout */
2491 if( wpMoveHistory.visible ) {
2495 if( wpEvalGraph.visible )
2500 if( wpEngineOutput.visible ) {
2501 EngineOutputPopUp();
2506 if (errorExitStatus == -1) {
2507 if (appData.icsActive) {
2508 /* We now wait until we see "login:" from the ICS before
2509 sending the logon script (problems with timestamp otherwise) */
2510 /*ICSInitScript();*/
2511 if (appData.icsInputBox) ICSInputBoxPopUp();
2515 signal(SIGWINCH, TermSizeSigHandler);
2517 signal(SIGINT, IntSigHandler);
2518 signal(SIGTERM, IntSigHandler);
2519 if (*appData.cmailGameName != NULLCHAR) {
2520 signal(SIGUSR1, CmailSigHandler);
2523 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2526 XtAppMainLoop(appContext);
2527 if (appData.debugMode) fclose(debugFP); // [DM] debug
2534 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2535 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2537 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2538 unlink(gameCopyFilename);
2539 unlink(gamePasteFilename);
2542 RETSIGTYPE TermSizeSigHandler(int sig)
2555 CmailSigHandler(sig)
2561 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2563 /* Activate call-back function CmailSigHandlerCallBack() */
2564 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2566 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2570 CmailSigHandlerCallBack(isr, closure, message, count, error)
2578 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2580 /**** end signal code ****/
2590 f = fopen(appData.icsLogon, "r");
2596 strcat(buf, appData.icsLogon);
2597 f = fopen(buf, "r");
2601 ProcessICSInitScript(f);
2608 EditCommentPopDown();
2623 if (!menuBarWidget) return;
2624 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2626 DisplayError("menuStep.Revert", 0);
2628 XtSetSensitive(w, !grey);
2630 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2632 DisplayError("menuStep.Annotate", 0);
2634 XtSetSensitive(w, !grey);
2639 SetMenuEnables(enab)
2643 if (!menuBarWidget) return;
2644 while (enab->name != NULL) {
2645 w = XtNameToWidget(menuBarWidget, enab->name);
2647 DisplayError(enab->name, 0);
2649 XtSetSensitive(w, enab->value);
2655 Enables icsEnables[] = {
2656 { "menuFile.Mail Move", False },
2657 { "menuFile.Reload CMail Message", False },
2658 { "menuMode.Machine Black", False },
2659 { "menuMode.Machine White", False },
2660 { "menuMode.Analysis Mode", False },
2661 { "menuMode.Analyze File", False },
2662 { "menuMode.Two Machines", False },
2664 { "menuHelp.Hint", False },
2665 { "menuHelp.Book", False },
2666 { "menuStep.Move Now", False },
2667 { "menuOptions.Periodic Updates", False },
2668 { "menuOptions.Hide Thinking", False },
2669 { "menuOptions.Ponder Next Move", False },
2671 { "menuStep.Annotate", False },
2675 Enables ncpEnables[] = {
2676 { "menuFile.Mail Move", False },
2677 { "menuFile.Reload CMail Message", False },
2678 { "menuMode.Machine White", False },
2679 { "menuMode.Machine Black", False },
2680 { "menuMode.Analysis Mode", False },
2681 { "menuMode.Analyze File", False },
2682 { "menuMode.Two Machines", False },
2683 { "menuMode.ICS Client", False },
2684 { "menuMode.ICS Input Box", False },
2685 { "Action", False },
2686 { "menuStep.Revert", False },
2687 { "menuStep.Annotate", False },
2688 { "menuStep.Move Now", False },
2689 { "menuStep.Retract Move", False },
2690 { "menuOptions.Auto Comment", False },
2691 { "menuOptions.Auto Flag", False },
2692 { "menuOptions.Auto Flip View", False },
2693 { "menuOptions.Auto Observe", False },
2694 { "menuOptions.Auto Raise Board", False },
2695 { "menuOptions.Get Move List", False },
2696 { "menuOptions.ICS Alarm", False },
2697 { "menuOptions.Move Sound", False },
2698 { "menuOptions.Quiet Play", False },
2699 { "menuOptions.Hide Thinking", False },
2700 { "menuOptions.Periodic Updates", False },
2701 { "menuOptions.Ponder Next Move", False },
2702 { "menuHelp.Hint", False },
2703 { "menuHelp.Book", False },
2707 Enables gnuEnables[] = {
2708 { "menuMode.ICS Client", False },
2709 { "menuMode.ICS Input Box", False },
2710 { "menuAction.Accept", False },
2711 { "menuAction.Decline", False },
2712 { "menuAction.Rematch", False },
2713 { "menuAction.Adjourn", False },
2714 { "menuAction.Stop Examining", False },
2715 { "menuAction.Stop Observing", False },
2716 { "menuAction.Upload to Examine", False },
2717 { "menuStep.Revert", False },
2718 { "menuStep.Annotate", False },
2719 { "menuOptions.Auto Comment", False },
2720 { "menuOptions.Auto Observe", False },
2721 { "menuOptions.Auto Raise Board", False },
2722 { "menuOptions.Get Move List", False },
2723 { "menuOptions.Premove", False },
2724 { "menuOptions.Quiet Play", False },
2726 /* The next two options rely on SetCmailMode being called *after* */
2727 /* SetGNUMode so that when GNU is being used to give hints these */
2728 /* menu options are still available */
2730 { "menuFile.Mail Move", False },
2731 { "menuFile.Reload CMail Message", False },
2735 Enables cmailEnables[] = {
2737 { "menuAction.Call Flag", False },
2738 { "menuAction.Draw", True },
2739 { "menuAction.Adjourn", False },
2740 { "menuAction.Abort", False },
2741 { "menuAction.Stop Observing", False },
2742 { "menuAction.Stop Examining", False },
2743 { "menuFile.Mail Move", True },
2744 { "menuFile.Reload CMail Message", True },
2748 Enables trainingOnEnables[] = {
2749 { "menuMode.Edit Comment", False },
2750 { "menuMode.Pause", False },
2751 { "menuStep.Forward", False },
2752 { "menuStep.Backward", False },
2753 { "menuStep.Forward to End", False },
2754 { "menuStep.Back to Start", False },
2755 { "menuStep.Move Now", False },
2756 { "menuStep.Truncate Game", False },
2760 Enables trainingOffEnables[] = {
2761 { "menuMode.Edit Comment", True },
2762 { "menuMode.Pause", True },
2763 { "menuStep.Forward", True },
2764 { "menuStep.Backward", True },
2765 { "menuStep.Forward to End", True },
2766 { "menuStep.Back to Start", True },
2767 { "menuStep.Move Now", True },
2768 { "menuStep.Truncate Game", True },
2772 Enables machineThinkingEnables[] = {
2773 { "menuFile.Load Game", False },
2774 { "menuFile.Load Next Game", False },
2775 { "menuFile.Load Previous Game", False },
2776 { "menuFile.Reload Same Game", False },
2777 { "menuFile.Paste Game", False },
2778 { "menuFile.Load Position", False },
2779 { "menuFile.Load Next Position", False },
2780 { "menuFile.Load Previous Position", False },
2781 { "menuFile.Reload Same Position", False },
2782 { "menuFile.Paste Position", False },
2783 { "menuMode.Machine White", False },
2784 { "menuMode.Machine Black", False },
2785 { "menuMode.Two Machines", False },
2786 { "menuStep.Retract Move", False },
2790 Enables userThinkingEnables[] = {
2791 { "menuFile.Load Game", True },
2792 { "menuFile.Load Next Game", True },
2793 { "menuFile.Load Previous Game", True },
2794 { "menuFile.Reload Same Game", True },
2795 { "menuFile.Paste Game", True },
2796 { "menuFile.Load Position", True },
2797 { "menuFile.Load Next Position", True },
2798 { "menuFile.Load Previous Position", True },
2799 { "menuFile.Reload Same Position", True },
2800 { "menuFile.Paste Position", True },
2801 { "menuMode.Machine White", True },
2802 { "menuMode.Machine Black", True },
2803 { "menuMode.Two Machines", True },
2804 { "menuStep.Retract Move", True },
2810 SetMenuEnables(icsEnables);
2813 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2814 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2821 SetMenuEnables(ncpEnables);
2827 SetMenuEnables(gnuEnables);
2833 SetMenuEnables(cmailEnables);
2839 SetMenuEnables(trainingOnEnables);
2840 if (appData.showButtonBar) {
2841 XtSetSensitive(buttonBarWidget, False);
2847 SetTrainingModeOff()
2849 SetMenuEnables(trainingOffEnables);
2850 if (appData.showButtonBar) {
2851 XtSetSensitive(buttonBarWidget, True);
2856 SetUserThinkingEnables()
2858 if (appData.noChessProgram) return;
2859 SetMenuEnables(userThinkingEnables);
2863 SetMachineThinkingEnables()
2865 if (appData.noChessProgram) return;
2866 SetMenuEnables(machineThinkingEnables);
2868 case MachinePlaysBlack:
2869 case MachinePlaysWhite:
2870 case TwoMachinesPlay:
2871 XtSetSensitive(XtNameToWidget(menuBarWidget,
2872 ModeToWidgetName(gameMode)), True);
2879 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2880 #define HISTORY_SIZE 64
\r
2881 static char *history[HISTORY_SIZE];
\r
2882 int histIn = 0, histP = 0;
\r
2885 SaveInHistory(char *cmd)
\r
2887 if (history[histIn] != NULL) {
\r
2888 free(history[histIn]);
\r
2889 history[histIn] = NULL;
\r
2891 if (*cmd == NULLCHAR) return;
\r
2892 history[histIn] = StrSave(cmd);
\r
2893 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2894 if (history[histIn] != NULL) {
\r
2895 free(history[histIn]);
\r
2896 history[histIn] = NULL;
\r
2902 PrevInHistory(char *cmd)
\r
2905 if (histP == histIn) {
\r
2906 if (history[histIn] != NULL) free(history[histIn]);
\r
2907 history[histIn] = StrSave(cmd);
\r
2909 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2910 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2912 return history[histP];
\r
2918 if (histP == histIn) return NULL;
\r
2919 histP = (histP + 1) % HISTORY_SIZE;
\r
2920 return history[histP];
\r
2922 // end of borrowed code
\r
2924 #define Abs(n) ((n)<0 ? -(n) : (n))
2927 * Find a font that matches "pattern" that is as close as
2928 * possible to the targetPxlSize. Prefer fonts that are k
2929 * pixels smaller to fonts that are k pixels larger. The
2930 * pattern must be in the X Consortium standard format,
2931 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2932 * The return value should be freed with XtFree when no
2935 char *FindFont(pattern, targetPxlSize)
2939 char **fonts, *p, *best, *scalable, *scalableTail;
2940 int i, j, nfonts, minerr, err, pxlSize;
2943 char **missing_list;
2945 char *def_string, *base_fnt_lst, strInt[3];
2947 XFontStruct **fnt_list;
2949 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2950 sprintf(strInt, "%d", targetPxlSize);
2951 p = strstr(pattern, "--");
2952 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2953 strcat(base_fnt_lst, strInt);
2954 strcat(base_fnt_lst, strchr(p + 2, '-'));
2956 if ((fntSet = XCreateFontSet(xDisplay,
2960 &def_string)) == NULL) {
2962 fprintf(stderr, _("Unable to create font set.\n"));
2966 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2968 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2970 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2971 programName, pattern);
2979 for (i=0; i<nfonts; i++) {
2982 if (*p != '-') continue;
2984 if (*p == NULLCHAR) break;
2985 if (*p++ == '-') j++;
2987 if (j < 7) continue;
2990 scalable = fonts[i];
2993 err = pxlSize - targetPxlSize;
2994 if (Abs(err) < Abs(minerr) ||
2995 (minerr > 0 && err < 0 && -err == minerr)) {
3001 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3002 /* If the error is too big and there is a scalable font,
3003 use the scalable font. */
3004 int headlen = scalableTail - scalable;
3005 p = (char *) XtMalloc(strlen(scalable) + 10);
3006 while (isdigit(*scalableTail)) scalableTail++;
3007 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3009 p = (char *) XtMalloc(strlen(best) + 1);
3012 if (appData.debugMode) {
3013 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3014 pattern, targetPxlSize, p);
3017 if (missing_count > 0)
3018 XFreeStringList(missing_list);
3019 XFreeFontSet(xDisplay, fntSet);
3021 XFreeFontNames(fonts);
3028 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3029 | GCBackground | GCFunction | GCPlaneMask;
3030 XGCValues gc_values;
3033 gc_values.plane_mask = AllPlanes;
3034 gc_values.line_width = lineGap;
3035 gc_values.line_style = LineSolid;
3036 gc_values.function = GXcopy;
3038 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3039 gc_values.background = XBlackPixel(xDisplay, xScreen);
3040 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3042 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3043 gc_values.background = XWhitePixel(xDisplay, xScreen);
3044 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3045 XSetFont(xDisplay, coordGC, coordFontID);
3047 // [HGM] make font for holdings counts (white on black0
3048 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3049 gc_values.background = XBlackPixel(xDisplay, xScreen);
3050 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3051 XSetFont(xDisplay, countGC, countFontID);
3053 if (appData.monoMode) {
3054 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3055 gc_values.background = XWhitePixel(xDisplay, xScreen);
3056 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3058 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3059 gc_values.background = XBlackPixel(xDisplay, xScreen);
3060 lightSquareGC = wbPieceGC
3061 = XtGetGC(shellWidget, value_mask, &gc_values);
3063 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3064 gc_values.background = XWhitePixel(xDisplay, xScreen);
3065 darkSquareGC = bwPieceGC
3066 = XtGetGC(shellWidget, value_mask, &gc_values);
3068 if (DefaultDepth(xDisplay, xScreen) == 1) {
3069 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3070 gc_values.function = GXcopyInverted;
3071 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3072 gc_values.function = GXcopy;
3073 if (XBlackPixel(xDisplay, xScreen) == 1) {
3074 bwPieceGC = darkSquareGC;
3075 wbPieceGC = copyInvertedGC;
3077 bwPieceGC = copyInvertedGC;
3078 wbPieceGC = lightSquareGC;
3082 gc_values.foreground = highlightSquareColor;
3083 gc_values.background = highlightSquareColor;
3084 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3086 gc_values.foreground = premoveHighlightColor;
3087 gc_values.background = premoveHighlightColor;
3088 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3090 gc_values.foreground = lightSquareColor;
3091 gc_values.background = darkSquareColor;
3092 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3094 gc_values.foreground = darkSquareColor;
3095 gc_values.background = lightSquareColor;
3096 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3098 gc_values.foreground = jailSquareColor;
3099 gc_values.background = jailSquareColor;
3100 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3102 gc_values.foreground = whitePieceColor;
3103 gc_values.background = darkSquareColor;
3104 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 gc_values.foreground = whitePieceColor;
3107 gc_values.background = lightSquareColor;
3108 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3110 gc_values.foreground = whitePieceColor;
3111 gc_values.background = jailSquareColor;
3112 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3114 gc_values.foreground = blackPieceColor;
3115 gc_values.background = darkSquareColor;
3116 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3118 gc_values.foreground = blackPieceColor;
3119 gc_values.background = lightSquareColor;
3120 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3122 gc_values.foreground = blackPieceColor;
3123 gc_values.background = jailSquareColor;
3124 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3128 void loadXIM(xim, xmask, filename, dest, mask)
3141 fp = fopen(filename, "rb");
3143 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3150 for (y=0; y<h; ++y) {
3151 for (x=0; x<h; ++x) {
3156 XPutPixel(xim, x, y, blackPieceColor);
3158 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3161 XPutPixel(xim, x, y, darkSquareColor);
3163 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3166 XPutPixel(xim, x, y, whitePieceColor);
3168 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3171 XPutPixel(xim, x, y, lightSquareColor);
3173 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3179 /* create Pixmap of piece */
3180 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3182 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3185 /* create Pixmap of clipmask
3186 Note: We assume the white/black pieces have the same
3187 outline, so we make only 6 masks. This is okay
3188 since the XPM clipmask routines do the same. */
3190 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3192 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3195 /* now create the 1-bit version */
3196 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3199 values.foreground = 1;
3200 values.background = 0;
3202 /* Don't use XtGetGC, not read only */
3203 maskGC = XCreateGC(xDisplay, *mask,
3204 GCForeground | GCBackground, &values);
3205 XCopyPlane(xDisplay, temp, *mask, maskGC,
3206 0, 0, squareSize, squareSize, 0, 0, 1);
3207 XFreePixmap(xDisplay, temp);
3212 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3214 void CreateXIMPieces()
3219 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3224 /* The XSynchronize calls were copied from CreatePieces.
3225 Not sure if needed, but can't hurt */
3226 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3229 /* temp needed by loadXIM() */
3230 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3231 0, 0, ss, ss, AllPlanes, XYPixmap);
3233 if (strlen(appData.pixmapDirectory) == 0) {
3237 if (appData.monoMode) {
3238 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3242 fprintf(stderr, _("\nLoading XIMs...\n"));
3244 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3245 fprintf(stderr, "%d", piece+1);
3246 for (kind=0; kind<4; kind++) {
3247 fprintf(stderr, ".");
3248 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3249 ExpandPathName(appData.pixmapDirectory),
3250 piece <= (int) WhiteKing ? "" : "w",
3251 pieceBitmapNames[piece],
3253 ximPieceBitmap[kind][piece] =
3254 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3255 0, 0, ss, ss, AllPlanes, XYPixmap);
3256 if (appData.debugMode)
3257 fprintf(stderr, _("(File:%s:) "), buf);
3258 loadXIM(ximPieceBitmap[kind][piece],
3260 &(xpmPieceBitmap2[kind][piece]),
3261 &(ximMaskPm2[piece]));
3262 if(piece <= (int)WhiteKing)
3263 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3265 fprintf(stderr," ");
3267 /* Load light and dark squares */
3268 /* If the LSQ and DSQ pieces don't exist, we will
3269 draw them with solid squares. */
3270 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3271 if (access(buf, 0) != 0) {
3275 fprintf(stderr, _("light square "));
3277 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3278 0, 0, ss, ss, AllPlanes, XYPixmap);
3279 if (appData.debugMode)
3280 fprintf(stderr, _("(File:%s:) "), buf);
3282 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3283 fprintf(stderr, _("dark square "));
3284 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3285 ExpandPathName(appData.pixmapDirectory), ss);
3286 if (appData.debugMode)
3287 fprintf(stderr, _("(File:%s:) "), buf);
3289 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3290 0, 0, ss, ss, AllPlanes, XYPixmap);
3291 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3292 xpmJailSquare = xpmLightSquare;
3294 fprintf(stderr, _("Done.\n"));
3296 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3300 void CreateXPMPieces()
3304 u_int ss = squareSize;
3306 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3307 XpmColorSymbol symbols[4];
3309 /* The XSynchronize calls were copied from CreatePieces.
3310 Not sure if needed, but can't hurt */
3311 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3313 /* Setup translations so piece colors match square colors */
3314 symbols[0].name = "light_piece";
3315 symbols[0].value = appData.whitePieceColor;
3316 symbols[1].name = "dark_piece";
3317 symbols[1].value = appData.blackPieceColor;
3318 symbols[2].name = "light_square";
3319 symbols[2].value = appData.lightSquareColor;
3320 symbols[3].name = "dark_square";
3321 symbols[3].value = appData.darkSquareColor;
3323 attr.valuemask = XpmColorSymbols;
3324 attr.colorsymbols = symbols;
3325 attr.numsymbols = 4;
3327 if (appData.monoMode) {
3328 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3332 if (strlen(appData.pixmapDirectory) == 0) {
3333 XpmPieces* pieces = builtInXpms;
3336 while (pieces->size != squareSize && pieces->size) pieces++;
3337 if (!pieces->size) {
3338 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3341 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3342 for (kind=0; kind<4; kind++) {
3344 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3345 pieces->xpm[piece][kind],
3346 &(xpmPieceBitmap2[kind][piece]),
3347 NULL, &attr)) != 0) {
3348 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3352 if(piece <= (int) WhiteKing)
3353 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3357 xpmJailSquare = xpmLightSquare;
3361 fprintf(stderr, _("\nLoading XPMs...\n"));
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 fprintf(stderr, "%d ", piece+1);
3366 for (kind=0; kind<4; kind++) {
3367 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3368 ExpandPathName(appData.pixmapDirectory),
3369 piece > (int) WhiteKing ? "w" : "",
3370 pieceBitmapNames[piece],
3372 if (appData.debugMode) {
3373 fprintf(stderr, _("(File:%s:) "), buf);
3375 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3376 &(xpmPieceBitmap2[kind][piece]),
3377 NULL, &attr)) != 0) {
3378 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3379 // [HGM] missing: read of unorthodox piece failed; substitute King.
3380 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3381 ExpandPathName(appData.pixmapDirectory),
3383 if (appData.debugMode) {
3384 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3386 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3387 &(xpmPieceBitmap2[kind][piece]),
3391 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3396 if(piece <= (int) WhiteKing)
3397 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3400 /* Load light and dark squares */
3401 /* If the LSQ and DSQ pieces don't exist, we will
3402 draw them with solid squares. */
3403 fprintf(stderr, _("light square "));
3404 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3405 if (access(buf, 0) != 0) {
3409 if (appData.debugMode)
3410 fprintf(stderr, _("(File:%s:) "), buf);
3412 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3413 &xpmLightSquare, NULL, &attr)) != 0) {
3414 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3417 fprintf(stderr, _("dark square "));
3418 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3419 ExpandPathName(appData.pixmapDirectory), ss);
3420 if (appData.debugMode) {
3421 fprintf(stderr, _("(File:%s:) "), buf);
3423 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3424 &xpmDarkSquare, NULL, &attr)) != 0) {
3425 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3429 xpmJailSquare = xpmLightSquare;
3430 fprintf(stderr, _("Done.\n"));
3432 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3435 #endif /* HAVE_LIBXPM */
3438 /* No built-in bitmaps */
3443 u_int ss = squareSize;
3445 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3448 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3449 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3450 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3451 pieceBitmapNames[piece],
3452 ss, kind == SOLID ? 's' : 'o');
3453 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3454 if(piece <= (int)WhiteKing)
3455 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3459 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3463 /* With built-in bitmaps */
3466 BuiltInBits* bib = builtInBits;
3469 u_int ss = squareSize;
3471 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3474 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3476 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3477 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3478 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3479 pieceBitmapNames[piece],
3480 ss, kind == SOLID ? 's' : 'o');
3481 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3482 bib->bits[kind][piece], ss, ss);
3483 if(piece <= (int)WhiteKing)
3484 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3488 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3493 void ReadBitmap(pm, name, bits, wreq, hreq)
3496 unsigned char bits[];
3502 char msg[MSG_SIZ], fullname[MSG_SIZ];
3504 if (*appData.bitmapDirectory != NULLCHAR) {
3505 strcpy(fullname, appData.bitmapDirectory);
3506 strcat(fullname, "/");
3507 strcat(fullname, name);
3508 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3509 &w, &h, pm, &x_hot, &y_hot);
3510 fprintf(stderr, "load %s\n", name);
3511 if (errcode != BitmapSuccess) {
3513 case BitmapOpenFailed:
3514 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3516 case BitmapFileInvalid:
3517 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3519 case BitmapNoMemory:
3520 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3524 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3528 fprintf(stderr, _("%s: %s...using built-in\n"),
3530 } else if (w != wreq || h != hreq) {
3532 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3533 programName, fullname, w, h, wreq, hreq);
3539 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3548 if (lineGap == 0) return;
3550 /* [HR] Split this into 2 loops for non-square boards. */
3552 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3553 gridSegments[i].x1 = 0;
3554 gridSegments[i].x2 =
3555 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3556 gridSegments[i].y1 = gridSegments[i].y2
3557 = lineGap / 2 + (i * (squareSize + lineGap));
3560 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3561 gridSegments[j + i].y1 = 0;
3562 gridSegments[j + i].y2 =
3563 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3564 gridSegments[j + i].x1 = gridSegments[j + i].x2
3565 = lineGap / 2 + (j * (squareSize + lineGap));
3569 static void MenuBarSelect(w, addr, index)
3574 XtActionProc proc = (XtActionProc) addr;
3576 (proc)(NULL, NULL, NULL, NULL);
3579 void CreateMenuBarPopup(parent, name, mb)
3589 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3592 XtSetArg(args[j], XtNleftMargin, 20); j++;
3593 XtSetArg(args[j], XtNrightMargin, 20); j++;
3595 while (mi->string != NULL) {
3596 if (strcmp(mi->string, "----") == 0) {
3597 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3600 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3601 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3603 XtAddCallback(entry, XtNcallback,
3604 (XtCallbackProc) MenuBarSelect,
3605 (caddr_t) mi->proc);
3611 Widget CreateMenuBar(mb)
3615 Widget anchor, menuBar;
3617 char menuName[MSG_SIZ];
3620 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3621 XtSetArg(args[j], XtNvSpace, 0); j++;
3622 XtSetArg(args[j], XtNborderWidth, 0); j++;
3623 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3624 formWidget, args, j);
3626 while (mb->name != NULL) {
3627 strcpy(menuName, "menu");
3628 strcat(menuName, mb->name);
3630 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3633 shortName[0] = _(mb->name)[0];
3634 shortName[1] = NULLCHAR;
3635 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3638 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3641 XtSetArg(args[j], XtNborderWidth, 0); j++;
3642 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3644 CreateMenuBarPopup(menuBar, menuName, mb);
3650 Widget CreateButtonBar(mi)
3654 Widget button, buttonBar;
3658 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3660 XtSetArg(args[j], XtNhSpace, 0); j++;
3662 XtSetArg(args[j], XtNborderWidth, 0); j++;
3663 XtSetArg(args[j], XtNvSpace, 0); j++;
3664 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3665 formWidget, args, j);
3667 while (mi->string != NULL) {
3670 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3671 XtSetArg(args[j], XtNborderWidth, 0); j++;
3673 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3674 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3675 buttonBar, args, j);
3676 XtAddCallback(button, XtNcallback,
3677 (XtCallbackProc) MenuBarSelect,
3678 (caddr_t) mi->proc);
3685 CreatePieceMenu(name, color)
3692 ChessSquare selection;
3694 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3695 boardWidget, args, 0);
3697 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3698 String item = pieceMenuStrings[color][i];
3700 if (strcmp(item, "----") == 0) {
3701 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3704 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3705 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3707 selection = pieceMenuTranslation[color][i];
3708 XtAddCallback(entry, XtNcallback,
3709 (XtCallbackProc) PieceMenuSelect,
3710 (caddr_t) selection);
3711 if (selection == WhitePawn || selection == BlackPawn) {
3712 XtSetArg(args[0], XtNpopupOnEntry, entry);
3713 XtSetValues(menu, args, 1);
3726 ChessSquare selection;
3728 whitePieceMenu = CreatePieceMenu("menuW", 0);
3729 blackPieceMenu = CreatePieceMenu("menuB", 1);
3731 XtRegisterGrabAction(PieceMenuPopup, True,
3732 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3733 GrabModeAsync, GrabModeAsync);
3735 XtSetArg(args[0], XtNlabel, _("Drop"));
3736 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3737 boardWidget, args, 1);
3738 for (i = 0; i < DROP_MENU_SIZE; i++) {
3739 String item = dropMenuStrings[i];
3741 if (strcmp(item, "----") == 0) {
3742 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3745 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3746 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3748 selection = dropMenuTranslation[i];
3749 XtAddCallback(entry, XtNcallback,
3750 (XtCallbackProc) DropMenuSelect,
3751 (caddr_t) selection);
3756 void SetupDropMenu()
3764 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3765 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3766 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3767 dmEnables[i].piece);
3768 XtSetSensitive(entry, p != NULL || !appData.testLegality
3769 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3770 && !appData.icsActive));
3772 while (p && *p++ == dmEnables[i].piece) count++;
3773 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3775 XtSetArg(args[j], XtNlabel, label); j++;
3776 XtSetValues(entry, args, j);
3780 void PieceMenuPopup(w, event, params, num_params)
3784 Cardinal *num_params;
3786 String whichMenu; int menuNr;
3787 if (event->type == ButtonRelease)
3788 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3789 else if (event->type == ButtonPress)
3790 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3792 case 0: whichMenu = params[0]; break;
3793 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3795 case -1: if (errorUp) ErrorPopDown();
3798 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3801 static void PieceMenuSelect(w, piece, junk)
3806 if (pmFromX < 0 || pmFromY < 0) return;
3807 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3810 static void DropMenuSelect(w, piece, junk)
3815 if (pmFromX < 0 || pmFromY < 0) return;
3816 DropMenuEvent(piece, pmFromX, pmFromY);
3819 void WhiteClock(w, event, prms, nprms)
3825 if (gameMode == EditPosition || gameMode == IcsExamining) {
3826 SetWhiteToPlayEvent();
3827 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3832 void BlackClock(w, event, prms, nprms)
3838 if (gameMode == EditPosition || gameMode == IcsExamining) {
3839 SetBlackToPlayEvent();
3840 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3847 * If the user selects on a border boundary, return -1; if off the board,
3848 * return -2. Otherwise map the event coordinate to the square.
3850 int EventToSquare(x, limit)
3858 if ((x % (squareSize + lineGap)) >= squareSize)
3860 x /= (squareSize + lineGap);
3866 static void do_flash_delay(msec)
3872 static void drawHighlight(file, rank, gc)
3878 if (lineGap == 0 || appData.blindfold) return;
3881 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3882 (squareSize + lineGap);
3883 y = lineGap/2 + rank * (squareSize + lineGap);
3885 x = lineGap/2 + file * (squareSize + lineGap);
3886 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3887 (squareSize + lineGap);
3890 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3891 squareSize+lineGap, squareSize+lineGap);
3894 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3895 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3898 SetHighlights(fromX, fromY, toX, toY)
3899 int fromX, fromY, toX, toY;
3901 if (hi1X != fromX || hi1Y != fromY) {
3902 if (hi1X >= 0 && hi1Y >= 0) {
3903 drawHighlight(hi1X, hi1Y, lineGC);
3905 } // [HGM] first erase both, then draw new!
3906 if (hi2X != toX || hi2Y != toY) {
3907 if (hi2X >= 0 && hi2Y >= 0) {
3908 drawHighlight(hi2X, hi2Y, lineGC);
3911 if (hi1X != fromX || hi1Y != fromY) {
3912 if (fromX >= 0 && fromY >= 0) {
3913 drawHighlight(fromX, fromY, highlineGC);
3916 if (hi2X != toX || hi2Y != toY) {
3917 if (toX >= 0 && toY >= 0) {
3918 drawHighlight(toX, toY, highlineGC);
3930 SetHighlights(-1, -1, -1, -1);
3935 SetPremoveHighlights(fromX, fromY, toX, toY)
3936 int fromX, fromY, toX, toY;
3938 if (pm1X != fromX || pm1Y != fromY) {
3939 if (pm1X >= 0 && pm1Y >= 0) {
3940 drawHighlight(pm1X, pm1Y, lineGC);
3942 if (fromX >= 0 && fromY >= 0) {
3943 drawHighlight(fromX, fromY, prelineGC);
3946 if (pm2X != toX || pm2Y != toY) {
3947 if (pm2X >= 0 && pm2Y >= 0) {
3948 drawHighlight(pm2X, pm2Y, lineGC);
3950 if (toX >= 0 && toY >= 0) {
3951 drawHighlight(toX, toY, prelineGC);
3961 ClearPremoveHighlights()
3963 SetPremoveHighlights(-1, -1, -1, -1);
3966 static void BlankSquare(x, y, color, piece, dest)
3971 if (useImages && useImageSqs) {
3975 pm = xpmLightSquare;
3980 case 2: /* neutral */
3985 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3986 squareSize, squareSize, x, y);
3996 case 2: /* neutral */
4001 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4006 I split out the routines to draw a piece so that I could
4007 make a generic flash routine.
4009 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4011 int square_color, x, y;
4014 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4015 switch (square_color) {
4017 case 2: /* neutral */
4019 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4020 ? *pieceToOutline(piece)
4021 : *pieceToSolid(piece),
4022 dest, bwPieceGC, 0, 0,
4023 squareSize, squareSize, x, y);
4026 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4027 ? *pieceToSolid(piece)
4028 : *pieceToOutline(piece),
4029 dest, wbPieceGC, 0, 0,
4030 squareSize, squareSize, x, y);
4035 static void monoDrawPiece(piece, square_color, x, y, dest)
4037 int square_color, x, y;
4040 switch (square_color) {
4042 case 2: /* neutral */
4044 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4045 ? *pieceToOutline(piece)
4046 : *pieceToSolid(piece),
4047 dest, bwPieceGC, 0, 0,
4048 squareSize, squareSize, x, y, 1);
4051 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4052 ? *pieceToSolid(piece)
4053 : *pieceToOutline(piece),
4054 dest, wbPieceGC, 0, 0,
4055 squareSize, squareSize, x, y, 1);
4060 static void colorDrawPiece(piece, square_color, x, y, dest)
4062 int square_color, x, y;
4065 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4066 switch (square_color) {
4068 XCopyPlane(xDisplay, *pieceToSolid(piece),
4069 dest, (int) piece < (int) BlackPawn
4070 ? wlPieceGC : blPieceGC, 0, 0,
4071 squareSize, squareSize, x, y, 1);
4074 XCopyPlane(xDisplay, *pieceToSolid(piece),
4075 dest, (int) piece < (int) BlackPawn
4076 ? wdPieceGC : bdPieceGC, 0, 0,
4077 squareSize, squareSize, x, y, 1);
4079 case 2: /* neutral */
4081 XCopyPlane(xDisplay, *pieceToSolid(piece),
4082 dest, (int) piece < (int) BlackPawn
4083 ? wjPieceGC : bjPieceGC, 0, 0,
4084 squareSize, squareSize, x, y, 1);
4089 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4091 int square_color, x, y;
4096 switch (square_color) {
4098 case 2: /* neutral */
4100 if ((int)piece < (int) BlackPawn) {
4108 if ((int)piece < (int) BlackPawn) {
4116 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4117 dest, wlPieceGC, 0, 0,
4118 squareSize, squareSize, x, y);
4121 typedef void (*DrawFunc)();
4123 DrawFunc ChooseDrawFunc()
4125 if (appData.monoMode) {
4126 if (DefaultDepth(xDisplay, xScreen) == 1) {
4127 return monoDrawPiece_1bit;
4129 return monoDrawPiece;
4133 return colorDrawPieceImage;
4135 return colorDrawPiece;
4139 /* [HR] determine square color depending on chess variant. */
4140 static int SquareColor(row, column)
4145 if (gameInfo.variant == VariantXiangqi) {
4146 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4148 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4150 } else if (row <= 4) {
4156 square_color = ((column + row) % 2) == 1;
4159 /* [hgm] holdings: next line makes all holdings squares light */
4160 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4162 return square_color;
4165 void DrawSquare(row, column, piece, do_flash)
4166 int row, column, do_flash;
4169 int square_color, x, y, direction, font_ascent, font_descent;
4172 XCharStruct overall;
4176 /* Calculate delay in milliseconds (2-delays per complete flash) */
4177 flash_delay = 500 / appData.flashRate;
4180 x = lineGap + ((BOARD_WIDTH-1)-column) *
4181 (squareSize + lineGap);
4182 y = lineGap + row * (squareSize + lineGap);
4184 x = lineGap + column * (squareSize + lineGap);
4185 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4186 (squareSize + lineGap);
4189 square_color = SquareColor(row, column);
4191 if ( // [HGM] holdings: blank out area between board and holdings
4192 column == BOARD_LEFT-1 || column == BOARD_RGHT
4193 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4194 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4195 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4197 // [HGM] print piece counts next to holdings
4198 string[1] = NULLCHAR;
4199 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4200 string[0] = '0' + piece;
4201 XTextExtents(countFontStruct, string, 1, &direction,
4202 &font_ascent, &font_descent, &overall);
4203 if (appData.monoMode) {
4204 XDrawImageString(xDisplay, xBoardWindow, countGC,
4205 x + squareSize - overall.width - 2,
4206 y + font_ascent + 1, string, 1);
4208 XDrawString(xDisplay, xBoardWindow, countGC,
4209 x + squareSize - overall.width - 2,
4210 y + font_ascent + 1, string, 1);
4213 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4214 string[0] = '0' + piece;
4215 XTextExtents(countFontStruct, string, 1, &direction,
4216 &font_ascent, &font_descent, &overall);
4217 if (appData.monoMode) {
4218 XDrawImageString(xDisplay, xBoardWindow, countGC,
4219 x + 2, y + font_ascent + 1, string, 1);
4221 XDrawString(xDisplay, xBoardWindow, countGC,
4222 x + 2, y + font_ascent + 1, string, 1);
4226 if (piece == EmptySquare || appData.blindfold) {
4227 BlankSquare(x, y, square_color, piece, xBoardWindow);
4229 drawfunc = ChooseDrawFunc();
4230 if (do_flash && appData.flashCount > 0) {
4231 for (i=0; i<appData.flashCount; ++i) {
4233 drawfunc(piece, square_color, x, y, xBoardWindow);
4234 XSync(xDisplay, False);
4235 do_flash_delay(flash_delay);
4237 BlankSquare(x, y, square_color, piece, xBoardWindow);
4238 XSync(xDisplay, False);
4239 do_flash_delay(flash_delay);
4242 drawfunc(piece, square_color, x, y, xBoardWindow);
4246 string[1] = NULLCHAR;
4247 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4248 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4249 string[0] = 'a' + column - BOARD_LEFT;
4250 XTextExtents(coordFontStruct, string, 1, &direction,
4251 &font_ascent, &font_descent, &overall);
4252 if (appData.monoMode) {
4253 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4254 x + squareSize - overall.width - 2,
4255 y + squareSize - font_descent - 1, string, 1);
4257 XDrawString(xDisplay, xBoardWindow, coordGC,
4258 x + squareSize - overall.width - 2,
4259 y + squareSize - font_descent - 1, string, 1);
4262 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4263 string[0] = ONE + row;
4264 XTextExtents(coordFontStruct, string, 1, &direction,
4265 &font_ascent, &font_descent, &overall);
4266 if (appData.monoMode) {
4267 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4268 x + 2, y + font_ascent + 1, string, 1);
4270 XDrawString(xDisplay, xBoardWindow, coordGC,
4271 x + 2, y + font_ascent + 1, string, 1);
4274 if(marker[row][column]) {
4275 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4276 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4281 /* Why is this needed on some versions of X? */
4282 void EventProc(widget, unused, event)
4287 if (!XtIsRealized(widget))
4290 switch (event->type) {
4292 if (event->xexpose.count > 0) return; /* no clipping is done */
4293 XDrawPosition(widget, True, NULL);
4296 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4303 void DrawPosition(fullRedraw, board)
4304 /*Boolean*/int fullRedraw;
4307 XDrawPosition(boardWidget, fullRedraw, board);
4310 /* Returns 1 if there are "too many" differences between b1 and b2
4311 (i.e. more than 1 move was made) */
4312 static int too_many_diffs(b1, b2)
4318 for (i=0; i<BOARD_HEIGHT; ++i) {
4319 for (j=0; j<BOARD_WIDTH; ++j) {
4320 if (b1[i][j] != b2[i][j]) {
4321 if (++c > 4) /* Castling causes 4 diffs */
4330 /* Matrix describing castling maneuvers */
4331 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4332 static int castling_matrix[4][5] = {
4333 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4334 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4335 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4336 { 7, 7, 4, 5, 6 } /* 0-0, black */
4339 /* Checks whether castling occurred. If it did, *rrow and *rcol
4340 are set to the destination (row,col) of the rook that moved.
4342 Returns 1 if castling occurred, 0 if not.
4344 Note: Only handles a max of 1 castling move, so be sure
4345 to call too_many_diffs() first.
4347 static int check_castle_draw(newb, oldb, rrow, rcol)
4354 /* For each type of castling... */
4355 for (i=0; i<4; ++i) {
4356 r = castling_matrix[i];
4358 /* Check the 4 squares involved in the castling move */
4360 for (j=1; j<=4; ++j) {
4361 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4368 /* All 4 changed, so it must be a castling move */
4377 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4378 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4380 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4383 void DrawSeekBackground( int left, int top, int right, int bottom )
4385 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4388 void DrawSeekText(char *buf, int x, int y)
4390 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4393 void DrawSeekDot(int x, int y, int colorNr)
4395 int square = colorNr & 0x80;
4398 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4400 XFillRectangle(xDisplay, xBoardWindow, color,
4401 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4403 XFillArc(xDisplay, xBoardWindow, color,
4404 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4407 static int damage[BOARD_RANKS][BOARD_FILES];
4410 * event handler for redrawing the board
4412 void XDrawPosition(w, repaint, board)
4414 /*Boolean*/int repaint;
4418 static int lastFlipView = 0;
4419 static int lastBoardValid = 0;
4420 static Board lastBoard;
4424 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4426 if (board == NULL) {
4427 if (!lastBoardValid) return;
4430 if (!lastBoardValid || lastFlipView != flipView) {
4431 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4437 * It would be simpler to clear the window with XClearWindow()
4438 * but this causes a very distracting flicker.
4441 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4443 /* If too much changes (begin observing new game, etc.), don't
4445 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4447 /* Special check for castling so we don't flash both the king
4448 and the rook (just flash the king). */
4450 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4451 /* Draw rook with NO flashing. King will be drawn flashing later */
4452 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4453 lastBoard[rrow][rcol] = board[rrow][rcol];
4457 /* First pass -- Draw (newly) empty squares and repair damage.
4458 This prevents you from having a piece show up twice while it
4459 is flashing on its new square */
4460 for (i = 0; i < BOARD_HEIGHT; i++)
4461 for (j = 0; j < BOARD_WIDTH; j++)
4462 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4464 DrawSquare(i, j, board[i][j], 0);
4465 damage[i][j] = False;
4468 /* Second pass -- Draw piece(s) in new position and flash them */
4469 for (i = 0; i < BOARD_HEIGHT; i++)
4470 for (j = 0; j < BOARD_WIDTH; j++)
4471 if (board[i][j] != lastBoard[i][j]) {
4472 DrawSquare(i, j, board[i][j], do_flash);
4476 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4477 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4479 for (i = 0; i < BOARD_HEIGHT; i++)
4480 for (j = 0; j < BOARD_WIDTH; j++) {
4481 DrawSquare(i, j, board[i][j], 0);
4482 damage[i][j] = False;
4486 CopyBoard(lastBoard, board);
4488 lastFlipView = flipView;
4490 /* Draw highlights */
4491 if (pm1X >= 0 && pm1Y >= 0) {
4492 drawHighlight(pm1X, pm1Y, prelineGC);
4494 if (pm2X >= 0 && pm2Y >= 0) {
4495 drawHighlight(pm2X, pm2Y, prelineGC);
4497 if (hi1X >= 0 && hi1Y >= 0) {
4498 drawHighlight(hi1X, hi1Y, highlineGC);
4500 if (hi2X >= 0 && hi2Y >= 0) {
4501 drawHighlight(hi2X, hi2Y, highlineGC);
4504 /* If piece being dragged around board, must redraw that too */
4507 XSync(xDisplay, False);
4512 * event handler for redrawing the board
4514 void DrawPositionProc(w, event, prms, nprms)
4520 XDrawPosition(w, True, NULL);
4525 * event handler for parsing user moves
4527 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4528 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4529 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4530 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4531 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4532 // and at the end FinishMove() to perform the move after optional promotion popups.
4533 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4534 void HandleUserMove(w, event, prms, nprms)
4540 if (w != boardWidget || errorExitStatus != -1) return;
4543 if (event->type == ButtonPress) {
4544 XtPopdown(promotionShell);
4545 XtDestroyWidget(promotionShell);
4546 promotionUp = False;
4554 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4555 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4556 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4559 void AnimateUserMove (Widget w, XEvent * event,
4560 String * params, Cardinal * nParams)
4562 DragPieceMove(event->xmotion.x, event->xmotion.y);
4565 void HandlePV (Widget w, XEvent * event,
4566 String * params, Cardinal * nParams)
4567 { // [HGM] pv: walk PV
4568 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4571 Widget CommentCreate(name, text, mutable, callback, lines)
4573 int /*Boolean*/ mutable;
4574 XtCallbackProc callback;
4578 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4583 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4584 XtGetValues(boardWidget, args, j);
4587 XtSetArg(args[j], XtNresizable, True); j++;
4590 XtCreatePopupShell(name, topLevelShellWidgetClass,
4591 shellWidget, args, j);
4594 XtCreatePopupShell(name, transientShellWidgetClass,
4595 shellWidget, args, j);
4598 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4599 layoutArgs, XtNumber(layoutArgs));
4601 XtCreateManagedWidget("form", formWidgetClass, layout,
4602 formArgs, XtNumber(formArgs));
4606 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4607 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4609 XtSetArg(args[j], XtNstring, text); j++;
4610 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4611 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4612 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4613 XtSetArg(args[j], XtNright, XtChainRight); j++;
4614 XtSetArg(args[j], XtNresizable, True); j++;
4615 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4616 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4617 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4618 XtSetArg(args[j], XtNautoFill, True); j++;
4619 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4621 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4625 XtSetArg(args[j], XtNfromVert, edit); j++;
4626 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4627 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4628 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4629 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4631 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4632 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4635 XtSetArg(args[j], XtNfromVert, edit); j++;
4636 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4637 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4638 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4639 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4640 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4642 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4643 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4646 XtSetArg(args[j], XtNfromVert, edit); j++;
4647 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4648 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4649 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4650 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4651 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4653 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4654 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4657 XtSetArg(args[j], XtNfromVert, edit); j++;
4658 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4659 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4660 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4661 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4663 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4664 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4667 XtSetArg(args[j], XtNfromVert, edit); j++;
4668 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4669 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4670 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4671 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4672 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4674 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4675 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4678 XtRealizeWidget(shell);
4680 if (commentX == -1) {
4683 Dimension pw_height;
4684 Dimension ew_height;
4687 XtSetArg(args[j], XtNheight, &ew_height); j++;
4688 XtGetValues(edit, args, j);
4691 XtSetArg(args[j], XtNheight, &pw_height); j++;
4692 XtGetValues(shell, args, j);
4693 commentH = pw_height + (lines - 1) * ew_height;
4694 commentW = bw_width - 16;
4696 XSync(xDisplay, False);
4698 /* This code seems to tickle an X bug if it is executed too soon
4699 after xboard starts up. The coordinates get transformed as if
4700 the main window was positioned at (0, 0).
4702 XtTranslateCoords(shellWidget,
4703 (bw_width - commentW) / 2, 0 - commentH / 2,
4704 &commentX, &commentY);
4706 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4707 RootWindowOfScreen(XtScreen(shellWidget)),
4708 (bw_width - commentW) / 2, 0 - commentH / 2,
4713 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4716 if(wpComment.width > 0) {
4717 commentX = wpComment.x;
4718 commentY = wpComment.y;
4719 commentW = wpComment.width;
4720 commentH = wpComment.height;
4724 XtSetArg(args[j], XtNheight, commentH); j++;
4725 XtSetArg(args[j], XtNwidth, commentW); j++;
4726 XtSetArg(args[j], XtNx, commentX); j++;
4727 XtSetArg(args[j], XtNy, commentY); j++;
4728 XtSetValues(shell, args, j);
4729 XtSetKeyboardFocus(shell, edit);
4734 /* Used for analysis window and ICS input window */
4735 Widget MiscCreate(name, text, mutable, callback, lines)
4737 int /*Boolean*/ mutable;
4738 XtCallbackProc callback;
4742 Widget shell, layout, form, edit;
4744 Dimension bw_width, pw_height, ew_height, w, h;
4750 XtSetArg(args[j], XtNresizable, True); j++;
4753 XtCreatePopupShell(name, topLevelShellWidgetClass,
4754 shellWidget, args, j);
4757 XtCreatePopupShell(name, transientShellWidgetClass,
4758 shellWidget, args, j);
4761 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4762 layoutArgs, XtNumber(layoutArgs));
4764 XtCreateManagedWidget("form", formWidgetClass, layout,
4765 formArgs, XtNumber(formArgs));
4769 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4770 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4772 XtSetArg(args[j], XtNstring, text); j++;
4773 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4774 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4775 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4776 XtSetArg(args[j], XtNright, XtChainRight); j++;
4777 XtSetArg(args[j], XtNresizable, True); j++;
4778 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4779 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4780 XtSetArg(args[j], XtNautoFill, True); j++;
4781 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4783 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4785 XtRealizeWidget(shell);
4788 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4789 XtGetValues(boardWidget, args, j);
4792 XtSetArg(args[j], XtNheight, &ew_height); j++;
4793 XtGetValues(edit, args, j);
4796 XtSetArg(args[j], XtNheight, &pw_height); j++;
4797 XtGetValues(shell, args, j);
4798 h = pw_height + (lines - 1) * ew_height;
4801 XSync(xDisplay, False);
4803 /* This code seems to tickle an X bug if it is executed too soon
4804 after xboard starts up. The coordinates get transformed as if
4805 the main window was positioned at (0, 0).
4807 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4809 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4810 RootWindowOfScreen(XtScreen(shellWidget)),
4811 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4815 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4818 XtSetArg(args[j], XtNheight, h); j++;
4819 XtSetArg(args[j], XtNwidth, w); j++;
4820 XtSetArg(args[j], XtNx, x); j++;
4821 XtSetArg(args[j], XtNy, y); j++;
4822 XtSetValues(shell, args, j);
4828 static int savedIndex; /* gross that this is global */
4830 void EditCommentPopUp(index, title, text)
4839 if (text == NULL) text = "";
4841 if (editShell == NULL) {
4843 CommentCreate(title, text, True, EditCommentCallback, 4);
4844 XtRealizeWidget(editShell);
4845 CatchDeleteWindow(editShell, "EditCommentPopDown");
4847 edit = XtNameToWidget(editShell, "*form.text");
4849 XtSetArg(args[j], XtNstring, text); j++;
4850 XtSetValues(edit, args, j);
4852 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4853 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4854 XtSetValues(editShell, args, j);
4857 XtPopup(editShell, XtGrabNone);
4861 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4862 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4866 void EditCommentCallback(w, client_data, call_data)
4868 XtPointer client_data, call_data;
4876 XtSetArg(args[j], XtNlabel, &name); j++;
4877 XtGetValues(w, args, j);
4879 if (strcmp(name, _("ok")) == 0) {
4880 edit = XtNameToWidget(editShell, "*form.text");
4882 XtSetArg(args[j], XtNstring, &val); j++;
4883 XtGetValues(edit, args, j);
4884 ReplaceComment(savedIndex, val);
4885 EditCommentPopDown();
4886 } else if (strcmp(name, _("cancel")) == 0) {
4887 EditCommentPopDown();
4888 } else if (strcmp(name, _("clear")) == 0) {
4889 edit = XtNameToWidget(editShell, "*form.text");
4890 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4891 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4895 void EditCommentPopDown()
4900 if (!editUp) return;
4902 XtSetArg(args[j], XtNx, &commentX); j++;
4903 XtSetArg(args[j], XtNy, &commentY); j++;
4904 XtSetArg(args[j], XtNheight, &commentH); j++;
4905 XtSetArg(args[j], XtNwidth, &commentW); j++;
4906 XtGetValues(editShell, args, j);
4907 XtPopdown(editShell);
4910 XtSetArg(args[j], XtNleftBitmap, None); j++;
4911 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4915 void ICSInputBoxPopUp()
4920 char *title = _("ICS Input");
4923 if (ICSInputShell == NULL) {
4924 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4925 tr = XtParseTranslationTable(ICSInputTranslations);
4926 edit = XtNameToWidget(ICSInputShell, "*form.text");
4927 XtOverrideTranslations(edit, tr);
4928 XtRealizeWidget(ICSInputShell);
4929 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4932 edit = XtNameToWidget(ICSInputShell, "*form.text");
4934 XtSetArg(args[j], XtNstring, ""); j++;
4935 XtSetValues(edit, args, j);
4937 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4938 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4939 XtSetValues(ICSInputShell, args, j);
4942 XtPopup(ICSInputShell, XtGrabNone);
4943 XtSetKeyboardFocus(ICSInputShell, edit);
4945 ICSInputBoxUp = True;
4947 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4948 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4952 void ICSInputSendText()
4959 edit = XtNameToWidget(ICSInputShell, "*form.text");
4961 XtSetArg(args[j], XtNstring, &val); j++;
4962 XtGetValues(edit, args, j);
4964 SendMultiLineToICS(val);
4965 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4966 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4969 void ICSInputBoxPopDown()
4974 if (!ICSInputBoxUp) return;
4976 XtPopdown(ICSInputShell);
4977 ICSInputBoxUp = False;
4979 XtSetArg(args[j], XtNleftBitmap, None); j++;
4980 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4984 void CommentPopUp(title, text)
4991 if (commentShell == NULL) {
4993 CommentCreate(title, text, False, CommentCallback, 4);
4994 XtRealizeWidget(commentShell);
4995 CatchDeleteWindow(commentShell, "CommentPopDown");
4997 edit = XtNameToWidget(commentShell, "*form.text");
4999 XtSetArg(args[j], XtNstring, text); j++;
5000 XtSetValues(edit, args, j);
5002 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5003 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5004 XtSetValues(commentShell, args, j);
5007 XtPopup(commentShell, XtGrabNone);
5008 XSync(xDisplay, False);
5013 void CommentCallback(w, client_data, call_data)
5015 XtPointer client_data, call_data;
5022 XtSetArg(args[j], XtNlabel, &name); j++;
5023 XtGetValues(w, args, j);
5025 if (strcmp(name, _("close")) == 0) {
5027 } else if (strcmp(name, _("edit")) == 0) {
5034 void CommentPopDown()
5039 if (!commentUp) return;
5041 XtSetArg(args[j], XtNx, &commentX); j++;
5042 XtSetArg(args[j], XtNy, &commentY); j++;
5043 XtSetArg(args[j], XtNwidth, &commentW); j++;
5044 XtSetArg(args[j], XtNheight, &commentH); j++;
5045 XtGetValues(commentShell, args, j);
5046 XtPopdown(commentShell);
5047 XSync(xDisplay, False);
5051 void FileNamePopUp(label, def, proc, openMode)
5058 Widget popup, layout, dialog, edit;
5064 fileProc = proc; /* I can't see a way not */
5065 fileOpenMode = openMode; /* to use globals here */
5066 { // [HGM] use file-selector dialog stolen from Ghostview
5068 int index; // this is not supported yet
5070 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5071 NULL, openMode, NULL, &name))
5072 (void) (*fileProc)(f, index=0, name);
5076 void FileNamePopDown()
5078 if (!filenameUp) return;
5079 XtPopdown(fileNameShell);
5080 XtDestroyWidget(fileNameShell);
5085 void FileNameCallback(w, client_data, call_data)
5087 XtPointer client_data, call_data;
5092 XtSetArg(args[0], XtNlabel, &name);
5093 XtGetValues(w, args, 1);
5095 if (strcmp(name, _("cancel")) == 0) {
5100 FileNameAction(w, NULL, NULL, NULL);
5103 void FileNameAction(w, event, prms, nprms)
5115 name = XawDialogGetValueString(w = XtParent(w));
5117 if ((name != NULL) && (*name != NULLCHAR)) {
5119 XtPopdown(w = XtParent(XtParent(w)));
5123 p = strrchr(buf, ' ');
5130 fullname = ExpandPathName(buf);
5132 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5135 f = fopen(fullname, fileOpenMode);
5137 DisplayError(_("Failed to open file"), errno);
5139 (void) (*fileProc)(f, index, buf);
5146 XtPopdown(w = XtParent(XtParent(w)));
5152 void PromotionPopUp()
5155 Widget dialog, layout;
5157 Dimension bw_width, pw_width;
5161 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5162 XtGetValues(boardWidget, args, j);
5165 XtSetArg(args[j], XtNresizable, True); j++;
5166 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5168 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5169 shellWidget, args, j);
5171 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5172 layoutArgs, XtNumber(layoutArgs));
5175 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5176 XtSetArg(args[j], XtNborderWidth, 0); j++;
5177 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5180 if(gameInfo.variant != VariantShogi) {
5181 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5182 (XtPointer) dialog);
5183 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5184 (XtPointer) dialog);
5185 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5186 (XtPointer) dialog);
5187 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5188 (XtPointer) dialog);
5189 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5190 gameInfo.variant == VariantGiveaway) {
5191 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5192 (XtPointer) dialog);
5194 if(gameInfo.variant == VariantCapablanca ||
5195 gameInfo.variant == VariantGothic ||
5196 gameInfo.variant == VariantCapaRandom) {
5197 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5198 (XtPointer) dialog);
5199 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5200 (XtPointer) dialog);
5202 } else // [HGM] shogi
5204 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5205 (XtPointer) dialog);
5206 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5207 (XtPointer) dialog);
5209 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5210 (XtPointer) dialog);
5212 XtRealizeWidget(promotionShell);
5213 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5216 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5217 XtGetValues(promotionShell, args, j);
5219 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5220 lineGap + squareSize/3 +
5221 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5222 0 : 6*(squareSize + lineGap)), &x, &y);
5225 XtSetArg(args[j], XtNx, x); j++;
5226 XtSetArg(args[j], XtNy, y); j++;
5227 XtSetValues(promotionShell, args, j);
5229 XtPopup(promotionShell, XtGrabNone);
5234 void PromotionPopDown()
5236 if (!promotionUp) return;
5237 XtPopdown(promotionShell);
5238 XtDestroyWidget(promotionShell);
5239 promotionUp = False;
5242 void PromotionCallback(w, client_data, call_data)
5244 XtPointer client_data, call_data;
5250 XtSetArg(args[0], XtNlabel, &name);
5251 XtGetValues(w, args, 1);
5255 if (fromX == -1) return;
5257 if (strcmp(name, _("cancel")) == 0) {
5261 } else if (strcmp(name, _("Knight")) == 0) {
5263 } else if (strcmp(name, _("Promote")) == 0) {
5265 } else if (strcmp(name, _("Defer")) == 0) {
5268 promoChar = ToLower(name[0]);
5271 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5273 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5274 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5279 void ErrorCallback(w, client_data, call_data)
5281 XtPointer client_data, call_data;
5284 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5286 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5292 if (!errorUp) return;
5294 XtPopdown(errorShell);
5295 XtDestroyWidget(errorShell);
5296 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5299 void ErrorPopUp(title, label, modal)
5300 char *title, *label;
5304 Widget dialog, layout;
5308 Dimension bw_width, pw_width;
5309 Dimension pw_height;
5313 XtSetArg(args[i], XtNresizable, True); i++;
5314 XtSetArg(args[i], XtNtitle, title); i++;
5316 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5317 shellWidget, args, i);
5319 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5320 layoutArgs, XtNumber(layoutArgs));
5323 XtSetArg(args[i], XtNlabel, label); i++;
5324 XtSetArg(args[i], XtNborderWidth, 0); i++;
5325 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5328 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5330 XtRealizeWidget(errorShell);
5331 CatchDeleteWindow(errorShell, "ErrorPopDown");
5334 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5335 XtGetValues(boardWidget, args, i);
5337 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5338 XtSetArg(args[i], XtNheight, &pw_height); i++;
5339 XtGetValues(errorShell, args, i);
5342 /* This code seems to tickle an X bug if it is executed too soon
5343 after xboard starts up. The coordinates get transformed as if
5344 the main window was positioned at (0, 0).
5346 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5347 0 - pw_height + squareSize / 3, &x, &y);
5349 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5350 RootWindowOfScreen(XtScreen(boardWidget)),
5351 (bw_width - pw_width) / 2,
5352 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5356 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5359 XtSetArg(args[i], XtNx, x); i++;
5360 XtSetArg(args[i], XtNy, y); i++;
5361 XtSetValues(errorShell, args, i);
5364 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5367 /* Disable all user input other than deleting the window */
5368 static int frozen = 0;
5372 /* Grab by a widget that doesn't accept input */
5373 XtAddGrab(messageWidget, TRUE, FALSE);
5377 /* Undo a FreezeUI */
5380 if (!frozen) return;
5381 XtRemoveGrab(messageWidget);
5385 char *ModeToWidgetName(mode)
5389 case BeginningOfGame:
5390 if (appData.icsActive)
5391 return "menuMode.ICS Client";
5392 else if (appData.noChessProgram ||
5393 *appData.cmailGameName != NULLCHAR)
5394 return "menuMode.Edit Game";
5396 return "menuMode.Machine Black";
5397 case MachinePlaysBlack:
5398 return "menuMode.Machine Black";
5399 case MachinePlaysWhite:
5400 return "menuMode.Machine White";
5402 return "menuMode.Analysis Mode";
5404 return "menuMode.Analyze File";
5405 case TwoMachinesPlay:
5406 return "menuMode.Two Machines";
5408 return "menuMode.Edit Game";
5409 case PlayFromGameFile:
5410 return "menuFile.Load Game";
5412 return "menuMode.Edit Position";
5414 return "menuMode.Training";
5415 case IcsPlayingWhite:
5416 case IcsPlayingBlack:
5420 return "menuMode.ICS Client";
5427 void ModeHighlight()
5430 static int oldPausing = FALSE;
5431 static GameMode oldmode = (GameMode) -1;
5434 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5436 if (pausing != oldPausing) {
5437 oldPausing = pausing;
5439 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5441 XtSetArg(args[0], XtNleftBitmap, None);
5443 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5446 if (appData.showButtonBar) {
5447 /* Always toggle, don't set. Previous code messes up when
5448 invoked while the button is pressed, as releasing it
5449 toggles the state again. */
5452 XtSetArg(args[0], XtNbackground, &oldbg);
5453 XtSetArg(args[1], XtNforeground, &oldfg);
5454 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5456 XtSetArg(args[0], XtNbackground, oldfg);
5457 XtSetArg(args[1], XtNforeground, oldbg);
5459 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5463 wname = ModeToWidgetName(oldmode);
5464 if (wname != NULL) {
5465 XtSetArg(args[0], XtNleftBitmap, None);
5466 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5468 wname = ModeToWidgetName(gameMode);
5469 if (wname != NULL) {
5470 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5471 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5475 /* Maybe all the enables should be handled here, not just this one */
5476 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5477 gameMode == Training || gameMode == PlayFromGameFile);
5482 * Button/menu procedures
5484 void ResetProc(w, event, prms, nprms)
5493 int LoadGamePopUp(f, gameNumber, title)
5498 cmailMsgLoaded = FALSE;
5499 if (gameNumber == 0) {
5500 int error = GameListBuild(f);
5502 DisplayError(_("Cannot build game list"), error);
5503 } else if (!ListEmpty(&gameList) &&
5504 ((ListGame *) gameList.tailPred)->number > 1) {
5505 GameListPopUp(f, title);
5511 return LoadGame(f, gameNumber, title, FALSE);
5514 void LoadGameProc(w, event, prms, nprms)
5520 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5523 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5526 void LoadNextGameProc(w, event, prms, nprms)
5535 void LoadPrevGameProc(w, event, prms, nprms)
5544 void ReloadGameProc(w, event, prms, nprms)
5553 void LoadNextPositionProc(w, event, prms, nprms)
5562 void LoadPrevPositionProc(w, event, prms, nprms)
5571 void ReloadPositionProc(w, event, prms, nprms)
5580 void LoadPositionProc(w, event, prms, nprms)
5586 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5589 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5592 void SaveGameProc(w, event, prms, nprms)
5598 FileNamePopUp(_("Save game file name?"),
5599 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5603 void SavePositionProc(w, event, prms, nprms)
5609 FileNamePopUp(_("Save position file name?"),
5610 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5614 void ReloadCmailMsgProc(w, event, prms, nprms)
5620 ReloadCmailMsgEvent(FALSE);
5623 void MailMoveProc(w, event, prms, nprms)
5632 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5633 char *selected_fen_position=NULL;
5636 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5637 Atom *type_return, XtPointer *value_return,
5638 unsigned long *length_return, int *format_return)
5640 char *selection_tmp;
5642 if (!selected_fen_position) return False; /* should never happen */
5643 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5644 /* note: since no XtSelectionDoneProc was registered, Xt will
5645 * automatically call XtFree on the value returned. So have to
5646 * make a copy of it allocated with XtMalloc */
5647 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5648 strcpy(selection_tmp, selected_fen_position);
5650 *value_return=selection_tmp;
5651 *length_return=strlen(selection_tmp);
5652 *type_return=*target;
5653 *format_return = 8; /* bits per byte */
5655 } else if (*target == XA_TARGETS(xDisplay)) {
5656 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5657 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5658 targets_tmp[1] = XA_STRING;
5659 *value_return = targets_tmp;
5660 *type_return = XA_ATOM;
5662 *format_return = 8 * sizeof(Atom);
5663 if (*format_return > 32) {
5664 *length_return *= *format_return / 32;
5665 *format_return = 32;
5673 /* note: when called from menu all parameters are NULL, so no clue what the
5674 * Widget which was clicked on was, or what the click event was
5676 void CopyPositionProc(w, event, prms, nprms)
5683 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5684 * have a notion of a position that is selected but not copied.
5685 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5687 if(gameMode == EditPosition) EditPositionDone(TRUE);
5688 if (selected_fen_position) free(selected_fen_position);
5689 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5690 if (!selected_fen_position) return;
5691 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5693 SendPositionSelection,
5694 NULL/* lose_ownership_proc */ ,
5695 NULL/* transfer_done_proc */);
5696 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5698 SendPositionSelection,
5699 NULL/* lose_ownership_proc */ ,
5700 NULL/* transfer_done_proc */);
5703 /* function called when the data to Paste is ready */
5705 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5706 Atom *type, XtPointer value, unsigned long *len, int *format)
5709 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5710 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5711 EditPositionPasteFEN(fenstr);
5715 /* called when Paste Position button is pressed,
5716 * all parameters will be NULL */
5717 void PastePositionProc(w, event, prms, nprms)
5723 XtGetSelectionValue(menuBarWidget,
5724 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5725 /* (XtSelectionCallbackProc) */ PastePositionCB,
5726 NULL, /* client_data passed to PastePositionCB */
5728 /* better to use the time field from the event that triggered the
5729 * call to this function, but that isn't trivial to get
5737 SendGameSelection(Widget w, Atom *selection, Atom *target,
5738 Atom *type_return, XtPointer *value_return,
5739 unsigned long *length_return, int *format_return)
5741 char *selection_tmp;
5743 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5744 FILE* f = fopen(gameCopyFilename, "r");
5747 if (f == NULL) return False;
5751 selection_tmp = XtMalloc(len + 1);
5752 count = fread(selection_tmp, 1, len, f);
5754 XtFree(selection_tmp);
5757 selection_tmp[len] = NULLCHAR;
5758 *value_return = selection_tmp;
5759 *length_return = len;
5760 *type_return = *target;
5761 *format_return = 8; /* bits per byte */
5763 } else if (*target == XA_TARGETS(xDisplay)) {
5764 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5765 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5766 targets_tmp[1] = XA_STRING;
5767 *value_return = targets_tmp;
5768 *type_return = XA_ATOM;
5770 *format_return = 8 * sizeof(Atom);
5771 if (*format_return > 32) {
5772 *length_return *= *format_return / 32;
5773 *format_return = 32;
5781 /* note: when called from menu all parameters are NULL, so no clue what the
5782 * Widget which was clicked on was, or what the click event was
5784 void CopyGameProc(w, event, prms, nprms)
5792 ret = SaveGameToFile(gameCopyFilename, FALSE);
5796 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5797 * have a notion of a game that is selected but not copied.
5798 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5800 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5803 NULL/* lose_ownership_proc */ ,
5804 NULL/* transfer_done_proc */);
5805 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5808 NULL/* lose_ownership_proc */ ,
5809 NULL/* transfer_done_proc */);
5812 /* function called when the data to Paste is ready */
5814 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5815 Atom *type, XtPointer value, unsigned long *len, int *format)
5818 if (value == NULL || *len == 0) {
5819 return; /* nothing had been selected to copy */
5821 f = fopen(gamePasteFilename, "w");
5823 DisplayError(_("Can't open temp file"), errno);
5826 fwrite(value, 1, *len, f);
5829 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5832 /* called when Paste Game button is pressed,
5833 * all parameters will be NULL */
5834 void PasteGameProc(w, event, prms, nprms)
5840 XtGetSelectionValue(menuBarWidget,
5841 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5842 /* (XtSelectionCallbackProc) */ PasteGameCB,
5843 NULL, /* client_data passed to PasteGameCB */
5845 /* better to use the time field from the event that triggered the
5846 * call to this function, but that isn't trivial to get
5856 SaveGameProc(NULL, NULL, NULL, NULL);
5860 void QuitProc(w, event, prms, nprms)
5869 void PauseProc(w, event, prms, nprms)
5879 void MachineBlackProc(w, event, prms, nprms)
5885 MachineBlackEvent();
5888 void MachineWhiteProc(w, event, prms, nprms)
5894 MachineWhiteEvent();
5897 void AnalyzeModeProc(w, event, prms, nprms)
5905 if (!first.analysisSupport) {
5906 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5907 DisplayError(buf, 0);
5910 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5911 if (appData.icsActive) {
5912 if (gameMode != IcsObserving) {
5913 sprintf(buf,_("You are not observing a game"));
5914 DisplayError(buf, 0);
5916 if (appData.icsEngineAnalyze) {
5917 if (appData.debugMode)
5918 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5924 /* if enable, use want disable icsEngineAnalyze */
5925 if (appData.icsEngineAnalyze) {
5930 appData.icsEngineAnalyze = TRUE;
5931 if (appData.debugMode)
5932 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5934 if (!appData.showThinking)
5935 ShowThinkingProc(w,event,prms,nprms);
5940 void AnalyzeFileProc(w, event, prms, nprms)
5946 if (!first.analysisSupport) {
5948 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5949 DisplayError(buf, 0);
5954 if (!appData.showThinking)
5955 ShowThinkingProc(w,event,prms,nprms);
5958 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5959 AnalysisPeriodicEvent(1);
5962 void TwoMachinesProc(w, event, prms, nprms)
5971 void IcsClientProc(w, event, prms, nprms)
5980 void EditGameProc(w, event, prms, nprms)
5989 void EditPositionProc(w, event, prms, nprms)
5995 EditPositionEvent();
5998 void TrainingProc(w, event, prms, nprms)
6007 void EditCommentProc(w, event, prms, nprms)
6014 EditCommentPopDown();
6020 void IcsInputBoxProc(w, event, prms, nprms)
6026 if (ICSInputBoxUp) {
6027 ICSInputBoxPopDown();
6033 void AcceptProc(w, event, prms, nprms)
6042 void DeclineProc(w, event, prms, nprms)
6051 void RematchProc(w, event, prms, nprms)
6060 void CallFlagProc(w, event, prms, nprms)
6069 void DrawProc(w, event, prms, nprms)
6078 void AbortProc(w, event, prms, nprms)
6087 void AdjournProc(w, event, prms, nprms)
6096 void ResignProc(w, event, prms, nprms)
6105 void AdjuWhiteProc(w, event, prms, nprms)
6111 UserAdjudicationEvent(+1);
6114 void AdjuBlackProc(w, event, prms, nprms)
6120 UserAdjudicationEvent(-1);
6123 void AdjuDrawProc(w, event, prms, nprms)
6129 UserAdjudicationEvent(0);
6132 void EnterKeyProc(w, event, prms, nprms)
6138 if (ICSInputBoxUp == True)
6142 void UpKeyProc(w, event, prms, nprms)
6147 { // [HGM] input: let up-arrow recall previous line from history
6154 if (!ICSInputBoxUp) return;
6155 edit = XtNameToWidget(ICSInputShell, "*form.text");
6157 XtSetArg(args[j], XtNstring, &val); j++;
6158 XtGetValues(edit, args, j);
6159 val = PrevInHistory(val);
6160 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6161 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6163 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6164 XawTextReplace(edit, 0, 0, &t);
6165 XawTextSetInsertionPoint(edit, 9999);
6169 void DownKeyProc(w, event, prms, nprms)
6174 { // [HGM] input: let down-arrow recall next line from history
6179 if (!ICSInputBoxUp) return;
6180 edit = XtNameToWidget(ICSInputShell, "*form.text");
6181 val = NextInHistory();
6182 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6183 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6185 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6186 XawTextReplace(edit, 0, 0, &t);
6187 XawTextSetInsertionPoint(edit, 9999);
6191 void StopObservingProc(w, event, prms, nprms)
6197 StopObservingEvent();
6200 void StopExaminingProc(w, event, prms, nprms)
6206 StopExaminingEvent();
6209 void UploadProc(w, event, prms, nprms)
6219 void ForwardProc(w, event, prms, nprms)
6229 void BackwardProc(w, event, prms, nprms)
6238 void ToStartProc(w, event, prms, nprms)
6247 void ToEndProc(w, event, prms, nprms)
6256 void RevertProc(w, event, prms, nprms)
6265 void AnnotateProc(w, event, prms, nprms)
6274 void TruncateGameProc(w, event, prms, nprms)
6280 TruncateGameEvent();
6282 void RetractMoveProc(w, event, prms, nprms)
6291 void MoveNowProc(w, event, prms, nprms)
6301 void AlwaysQueenProc(w, event, prms, nprms)
6309 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6311 if (appData.alwaysPromoteToQueen) {
6312 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6314 XtSetArg(args[0], XtNleftBitmap, None);
6316 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6320 void AnimateDraggingProc(w, event, prms, nprms)
6328 appData.animateDragging = !appData.animateDragging;
6330 if (appData.animateDragging) {
6331 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6334 XtSetArg(args[0], XtNleftBitmap, None);
6336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6340 void AnimateMovingProc(w, event, prms, nprms)
6348 appData.animate = !appData.animate;
6350 if (appData.animate) {
6351 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6354 XtSetArg(args[0], XtNleftBitmap, None);
6356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6360 void AutocommProc(w, event, prms, nprms)
6368 appData.autoComment = !appData.autoComment;
6370 if (appData.autoComment) {
6371 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6373 XtSetArg(args[0], XtNleftBitmap, None);
6375 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6380 void AutoflagProc(w, event, prms, nprms)
6388 appData.autoCallFlag = !appData.autoCallFlag;
6390 if (appData.autoCallFlag) {
6391 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6393 XtSetArg(args[0], XtNleftBitmap, None);
6395 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6399 void AutoflipProc(w, event, prms, nprms)
6407 appData.autoFlipView = !appData.autoFlipView;
6409 if (appData.autoFlipView) {
6410 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6412 XtSetArg(args[0], XtNleftBitmap, None);
6414 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6418 void AutobsProc(w, event, prms, nprms)
6426 appData.autoObserve = !appData.autoObserve;
6428 if (appData.autoObserve) {
6429 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6431 XtSetArg(args[0], XtNleftBitmap, None);
6433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6437 void AutoraiseProc(w, event, prms, nprms)
6445 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6447 if (appData.autoRaiseBoard) {
6448 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6450 XtSetArg(args[0], XtNleftBitmap, None);
6452 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6456 void AutosaveProc(w, event, prms, nprms)
6464 appData.autoSaveGames = !appData.autoSaveGames;
6466 if (appData.autoSaveGames) {
6467 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6469 XtSetArg(args[0], XtNleftBitmap, None);
6471 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6475 void BlindfoldProc(w, event, prms, nprms)
6483 appData.blindfold = !appData.blindfold;
6485 if (appData.blindfold) {
6486 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6488 XtSetArg(args[0], XtNleftBitmap, None);
6490 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6493 DrawPosition(True, NULL);
6496 void TestLegalityProc(w, event, prms, nprms)
6504 appData.testLegality = !appData.testLegality;
6506 if (appData.testLegality) {
6507 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6509 XtSetArg(args[0], XtNleftBitmap, None);
6511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6516 void FlashMovesProc(w, event, prms, nprms)
6524 if (appData.flashCount == 0) {
6525 appData.flashCount = 3;
6527 appData.flashCount = -appData.flashCount;
6530 if (appData.flashCount > 0) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6539 void FlipViewProc(w, event, prms, nprms)
6545 flipView = !flipView;
6546 DrawPosition(True, NULL);
6549 void GetMoveListProc(w, event, prms, nprms)
6557 appData.getMoveList = !appData.getMoveList;
6559 if (appData.getMoveList) {
6560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6563 XtSetArg(args[0], XtNleftBitmap, None);
6565 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6570 void HighlightDraggingProc(w, event, prms, nprms)
6578 appData.highlightDragging = !appData.highlightDragging;
6580 if (appData.highlightDragging) {
6581 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6583 XtSetArg(args[0], XtNleftBitmap, None);
6585 XtSetValues(XtNameToWidget(menuBarWidget,
6586 "menuOptions.Highlight Dragging"), args, 1);
6590 void HighlightLastMoveProc(w, event, prms, nprms)
6598 appData.highlightLastMove = !appData.highlightLastMove;
6600 if (appData.highlightLastMove) {
6601 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6603 XtSetArg(args[0], XtNleftBitmap, None);
6605 XtSetValues(XtNameToWidget(menuBarWidget,
6606 "menuOptions.Highlight Last Move"), args, 1);
6609 void IcsAlarmProc(w, event, prms, nprms)
6617 appData.icsAlarm = !appData.icsAlarm;
6619 if (appData.icsAlarm) {
6620 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6622 XtSetArg(args[0], XtNleftBitmap, None);
6624 XtSetValues(XtNameToWidget(menuBarWidget,
6625 "menuOptions.ICS Alarm"), args, 1);
6628 void MoveSoundProc(w, event, prms, nprms)
6636 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6638 if (appData.ringBellAfterMoves) {
6639 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6641 XtSetArg(args[0], XtNleftBitmap, None);
6643 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6648 void OldSaveStyleProc(w, event, prms, nprms)
6656 appData.oldSaveStyle = !appData.oldSaveStyle;
6658 if (appData.oldSaveStyle) {
6659 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6661 XtSetArg(args[0], XtNleftBitmap, None);
6663 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6667 void PeriodicUpdatesProc(w, event, prms, nprms)
6675 PeriodicUpdatesEvent(!appData.periodicUpdates);
6677 if (appData.periodicUpdates) {
6678 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6680 XtSetArg(args[0], XtNleftBitmap, None);
6682 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6686 void PonderNextMoveProc(w, event, prms, nprms)
6694 PonderNextMoveEvent(!appData.ponderNextMove);
6696 if (appData.ponderNextMove) {
6697 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6699 XtSetArg(args[0], XtNleftBitmap, None);
6701 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6705 void PopupExitMessageProc(w, event, prms, nprms)
6713 appData.popupExitMessage = !appData.popupExitMessage;
6715 if (appData.popupExitMessage) {
6716 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6718 XtSetArg(args[0], XtNleftBitmap, None);
6720 XtSetValues(XtNameToWidget(menuBarWidget,
6721 "menuOptions.Popup Exit Message"), args, 1);
6724 void PopupMoveErrorsProc(w, event, prms, nprms)
6732 appData.popupMoveErrors = !appData.popupMoveErrors;
6734 if (appData.popupMoveErrors) {
6735 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6737 XtSetArg(args[0], XtNleftBitmap, None);
6739 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6743 void PremoveProc(w, event, prms, nprms)
6751 appData.premove = !appData.premove;
6753 if (appData.premove) {
6754 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6756 XtSetArg(args[0], XtNleftBitmap, None);
6758 XtSetValues(XtNameToWidget(menuBarWidget,
6759 "menuOptions.Premove"), args, 1);
6762 void QuietPlayProc(w, event, prms, nprms)
6770 appData.quietPlay = !appData.quietPlay;
6772 if (appData.quietPlay) {
6773 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6775 XtSetArg(args[0], XtNleftBitmap, None);
6777 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6781 void ShowCoordsProc(w, event, prms, nprms)
6789 appData.showCoords = !appData.showCoords;
6791 if (appData.showCoords) {
6792 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6794 XtSetArg(args[0], XtNleftBitmap, None);
6796 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6799 DrawPosition(True, NULL);
6802 void ShowThinkingProc(w, event, prms, nprms)
6808 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6809 ShowThinkingEvent();
6812 void HideThinkingProc(w, event, prms, nprms)
6820 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6821 ShowThinkingEvent();
6823 if (appData.hideThinkingFromHuman) {
6824 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6826 XtSetArg(args[0], XtNleftBitmap, None);
6828 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6832 void SaveOnExitProc(w, event, prms, nprms)
6840 saveSettingsOnExit = !saveSettingsOnExit;
6842 if (saveSettingsOnExit) {
6843 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6845 XtSetArg(args[0], XtNleftBitmap, None);
6847 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6851 void SaveSettingsProc(w, event, prms, nprms)
6857 SaveSettings(settingsFileName);
6860 void InfoProc(w, event, prms, nprms)
6867 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6872 void ManProc(w, event, prms, nprms)
6880 if (nprms && *nprms > 0)
6884 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6888 void HintProc(w, event, prms, nprms)
6897 void BookProc(w, event, prms, nprms)
6906 void AboutProc(w, event, prms, nprms)
6914 char *zippy = " (with Zippy code)";
6918 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6919 programVersion, zippy,
6920 "Copyright 1991 Digital Equipment Corporation",
6921 "Enhancements Copyright 1992-2009 Free Software Foundation",
6922 "Enhancements Copyright 2005 Alessandro Scotti",
6923 PACKAGE, " is free software and carries NO WARRANTY;",
6924 "see the file COPYING for more information.");
6925 ErrorPopUp(_("About XBoard"), buf, FALSE);
6928 void DebugProc(w, event, prms, nprms)
6934 appData.debugMode = !appData.debugMode;
6937 void AboutGameProc(w, event, prms, nprms)
6946 void NothingProc(w, event, prms, nprms)
6955 void Iconify(w, event, prms, nprms)
6964 XtSetArg(args[0], XtNiconic, True);
6965 XtSetValues(shellWidget, args, 1);
6968 void DisplayMessage(message, extMessage)
6969 char *message, *extMessage;
6971 /* display a message in the message widget */
6980 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6985 message = extMessage;
6989 /* need to test if messageWidget already exists, since this function
6990 can also be called during the startup, if for example a Xresource
6991 is not set up correctly */
6994 XtSetArg(arg, XtNlabel, message);
6995 XtSetValues(messageWidget, &arg, 1);
7001 void DisplayTitle(text)
7006 char title[MSG_SIZ];
7009 if (text == NULL) text = "";
7011 if (appData.titleInWindow) {
7013 XtSetArg(args[i], XtNlabel, text); i++;
7014 XtSetValues(titleWidget, args, i);
7017 if (*text != NULLCHAR) {
7019 strcpy(title, text);
7020 } else if (appData.icsActive) {
7021 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7022 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7023 } else if (appData.cmailGameName[0] != NULLCHAR) {
7024 snprintf(icon, sizeof(icon), "%s", "CMail");
7025 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7027 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7028 } else if (gameInfo.variant == VariantGothic) {
7029 strcpy(icon, programName);
7030 strcpy(title, GOTHIC);
7033 } else if (gameInfo.variant == VariantFalcon) {
7034 strcpy(icon, programName);
7035 strcpy(title, FALCON);
7037 } else if (appData.noChessProgram) {
7038 strcpy(icon, programName);
7039 strcpy(title, programName);
7041 strcpy(icon, first.tidy);
7042 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7045 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7046 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7047 XtSetValues(shellWidget, args, i);
7051 void DisplayError(message, error)
7058 if (appData.debugMode || appData.matchMode) {
7059 fprintf(stderr, "%s: %s\n", programName, message);
7062 if (appData.debugMode || appData.matchMode) {
7063 fprintf(stderr, "%s: %s: %s\n",
7064 programName, message, strerror(error));
7066 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7069 ErrorPopUp(_("Error"), message, FALSE);
7073 void DisplayMoveError(message)
7078 DrawPosition(FALSE, NULL);
7079 if (appData.debugMode || appData.matchMode) {
7080 fprintf(stderr, "%s: %s\n", programName, message);
7082 if (appData.popupMoveErrors) {
7083 ErrorPopUp(_("Error"), message, FALSE);
7085 DisplayMessage(message, "");
7090 void DisplayFatalError(message, error, status)
7096 errorExitStatus = status;
7098 fprintf(stderr, "%s: %s\n", programName, message);
7100 fprintf(stderr, "%s: %s: %s\n",
7101 programName, message, strerror(error));
7102 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7105 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7106 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7112 void DisplayInformation(message)
7116 ErrorPopUp(_("Information"), message, TRUE);
7119 void DisplayNote(message)
7123 ErrorPopUp(_("Note"), message, FALSE);
7127 NullXErrorCheck(dpy, error_event)
7129 XErrorEvent *error_event;
7134 void DisplayIcsInteractionTitle(message)
7137 if (oldICSInteractionTitle == NULL) {
7138 /* Magic to find the old window title, adapted from vim */
7139 char *wina = getenv("WINDOWID");
7141 Window win = (Window) atoi(wina);
7142 Window root, parent, *children;
7143 unsigned int nchildren;
7144 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7146 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7147 if (!XQueryTree(xDisplay, win, &root, &parent,
7148 &children, &nchildren)) break;
7149 if (children) XFree((void *)children);
7150 if (parent == root || parent == 0) break;
7153 XSetErrorHandler(oldHandler);
7155 if (oldICSInteractionTitle == NULL) {
7156 oldICSInteractionTitle = "xterm";
7159 printf("\033]0;%s\007", message);
7163 char pendingReplyPrefix[MSG_SIZ];
7164 ProcRef pendingReplyPR;
7166 void AskQuestionProc(w, event, prms, nprms)
7173 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7177 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7180 void AskQuestionPopDown()
7182 if (!askQuestionUp) return;
7183 XtPopdown(askQuestionShell);
7184 XtDestroyWidget(askQuestionShell);
7185 askQuestionUp = False;
7188 void AskQuestionReplyAction(w, event, prms, nprms)
7198 reply = XawDialogGetValueString(w = XtParent(w));
7199 strcpy(buf, pendingReplyPrefix);
7200 if (*buf) strcat(buf, " ");
7203 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7204 AskQuestionPopDown();
7206 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7209 void AskQuestionCallback(w, client_data, call_data)
7211 XtPointer client_data, call_data;
7216 XtSetArg(args[0], XtNlabel, &name);
7217 XtGetValues(w, args, 1);
7219 if (strcmp(name, _("cancel")) == 0) {
7220 AskQuestionPopDown();
7222 AskQuestionReplyAction(w, NULL, NULL, NULL);
7226 void AskQuestion(title, question, replyPrefix, pr)
7227 char *title, *question, *replyPrefix;
7231 Widget popup, layout, dialog, edit;
7237 strcpy(pendingReplyPrefix, replyPrefix);
7238 pendingReplyPR = pr;
7241 XtSetArg(args[i], XtNresizable, True); i++;
7242 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7243 askQuestionShell = popup =
7244 XtCreatePopupShell(title, transientShellWidgetClass,
7245 shellWidget, args, i);
7248 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7249 layoutArgs, XtNumber(layoutArgs));
7252 XtSetArg(args[i], XtNlabel, question); i++;
7253 XtSetArg(args[i], XtNvalue, ""); i++;
7254 XtSetArg(args[i], XtNborderWidth, 0); i++;
7255 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7258 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7259 (XtPointer) dialog);
7260 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7261 (XtPointer) dialog);
7263 XtRealizeWidget(popup);
7264 CatchDeleteWindow(popup, "AskQuestionPopDown");
7266 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7267 &x, &y, &win_x, &win_y, &mask);
7269 XtSetArg(args[0], XtNx, x - 10);
7270 XtSetArg(args[1], XtNy, y - 30);
7271 XtSetValues(popup, args, 2);
7273 XtPopup(popup, XtGrabExclusive);
7274 askQuestionUp = True;
7276 edit = XtNameToWidget(dialog, "*value");
7277 XtSetKeyboardFocus(popup, edit);
7285 if (*name == NULLCHAR) {
7287 } else if (strcmp(name, "$") == 0) {
7288 putc(BELLCHAR, stderr);
7291 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7299 PlaySound(appData.soundMove);
7305 PlaySound(appData.soundIcsWin);
7311 PlaySound(appData.soundIcsLoss);
7317 PlaySound(appData.soundIcsDraw);
7321 PlayIcsUnfinishedSound()
7323 PlaySound(appData.soundIcsUnfinished);
7329 PlaySound(appData.soundIcsAlarm);
7335 system("stty echo");
7341 system("stty -echo");
7345 Colorize(cc, continuation)
7350 int count, outCount, error;
7352 if (textColors[(int)cc].bg > 0) {
7353 if (textColors[(int)cc].fg > 0) {
7354 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7355 textColors[(int)cc].fg, textColors[(int)cc].bg);
7357 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7358 textColors[(int)cc].bg);
7361 if (textColors[(int)cc].fg > 0) {
7362 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7363 textColors[(int)cc].fg);
7365 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7368 count = strlen(buf);
7369 outCount = OutputToProcess(NoProc, buf, count, &error);
7370 if (outCount < count) {
7371 DisplayFatalError(_("Error writing to display"), error, 1);
7374 if (continuation) return;
7377 PlaySound(appData.soundShout);
7380 PlaySound(appData.soundSShout);
7383 PlaySound(appData.soundChannel1);
7386 PlaySound(appData.soundChannel);
7389 PlaySound(appData.soundKibitz);
7392 PlaySound(appData.soundTell);
7394 case ColorChallenge:
7395 PlaySound(appData.soundChallenge);
7398 PlaySound(appData.soundRequest);
7401 PlaySound(appData.soundSeek);
7412 return getpwuid(getuid())->pw_name;
7415 static char *ExpandPathName(path)
7418 static char static_buf[2000];
7419 char *d, *s, buf[2000];
7425 while (*s && isspace(*s))
7434 if (*(s+1) == '/') {
7435 strcpy(d, getpwuid(getuid())->pw_dir);
7440 *strchr(buf, '/') = 0;
7441 pwd = getpwnam(buf);
7444 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7448 strcpy(d, pwd->pw_dir);
7449 strcat(d, strchr(s+1, '/'));
7460 static char host_name[MSG_SIZ];
7462 #if HAVE_GETHOSTNAME
7463 gethostname(host_name, MSG_SIZ);
7465 #else /* not HAVE_GETHOSTNAME */
7466 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7467 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7469 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7471 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7472 #endif /* not HAVE_GETHOSTNAME */
7475 XtIntervalId delayedEventTimerXID = 0;
7476 DelayedEventCallback delayedEventCallback = 0;
7481 delayedEventTimerXID = 0;
7482 delayedEventCallback();
7486 ScheduleDelayedEvent(cb, millisec)
7487 DelayedEventCallback cb; long millisec;
7489 if(delayedEventTimerXID && delayedEventCallback == cb)
7490 // [HGM] alive: replace, rather than add or flush identical event
7491 XtRemoveTimeOut(delayedEventTimerXID);
7492 delayedEventCallback = cb;
7493 delayedEventTimerXID =
7494 XtAppAddTimeOut(appContext, millisec,
7495 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7498 DelayedEventCallback
7501 if (delayedEventTimerXID) {
7502 return delayedEventCallback;
7509 CancelDelayedEvent()
7511 if (delayedEventTimerXID) {
7512 XtRemoveTimeOut(delayedEventTimerXID);
7513 delayedEventTimerXID = 0;
7517 XtIntervalId loadGameTimerXID = 0;
7519 int LoadGameTimerRunning()
7521 return loadGameTimerXID != 0;
7524 int StopLoadGameTimer()
7526 if (loadGameTimerXID != 0) {
7527 XtRemoveTimeOut(loadGameTimerXID);
7528 loadGameTimerXID = 0;
7536 LoadGameTimerCallback(arg, id)
7540 loadGameTimerXID = 0;
7545 StartLoadGameTimer(millisec)
7549 XtAppAddTimeOut(appContext, millisec,
7550 (XtTimerCallbackProc) LoadGameTimerCallback,
7554 XtIntervalId analysisClockXID = 0;
7557 AnalysisClockCallback(arg, id)
7561 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7562 || appData.icsEngineAnalyze) { // [DM]
7563 AnalysisPeriodicEvent(0);
7564 StartAnalysisClock();
7569 StartAnalysisClock()
7572 XtAppAddTimeOut(appContext, 2000,
7573 (XtTimerCallbackProc) AnalysisClockCallback,
7577 XtIntervalId clockTimerXID = 0;
7579 int ClockTimerRunning()
7581 return clockTimerXID != 0;
7584 int StopClockTimer()
7586 if (clockTimerXID != 0) {
7587 XtRemoveTimeOut(clockTimerXID);
7596 ClockTimerCallback(arg, id)
7605 StartClockTimer(millisec)
7609 XtAppAddTimeOut(appContext, millisec,
7610 (XtTimerCallbackProc) ClockTimerCallback,
7615 DisplayTimerLabel(w, color, timer, highlight)
7624 /* check for low time warning */
7625 Pixel foregroundOrWarningColor = timerForegroundPixel;
7628 appData.lowTimeWarning &&
7629 (timer / 1000) < appData.icsAlarmTime)
7630 foregroundOrWarningColor = lowTimeWarningColor;
7632 if (appData.clockMode) {
7633 sprintf(buf, "%s: %s", color, TimeString(timer));
7634 XtSetArg(args[0], XtNlabel, buf);
7636 sprintf(buf, "%s ", color);
7637 XtSetArg(args[0], XtNlabel, buf);
7642 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7643 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7645 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7646 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7649 XtSetValues(w, args, 3);
7653 DisplayWhiteClock(timeRemaining, highlight)
7659 if(appData.noGUI) return;
7660 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7661 if (highlight && iconPixmap == bIconPixmap) {
7662 iconPixmap = wIconPixmap;
7663 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7664 XtSetValues(shellWidget, args, 1);
7669 DisplayBlackClock(timeRemaining, highlight)
7675 if(appData.noGUI) return;
7676 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7677 if (highlight && iconPixmap == wIconPixmap) {
7678 iconPixmap = bIconPixmap;
7679 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7680 XtSetValues(shellWidget, args, 1);
7698 int StartChildProcess(cmdLine, dir, pr)
7705 int to_prog[2], from_prog[2];
7709 if (appData.debugMode) {
7710 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7713 /* We do NOT feed the cmdLine to the shell; we just
7714 parse it into blank-separated arguments in the
7715 most simple-minded way possible.
7718 strcpy(buf, cmdLine);
7721 while(*p == ' ') p++;
7723 if(*p == '"' || *p == '\'')
7724 p = strchr(++argv[i-1], *p);
7725 else p = strchr(p, ' ');
7726 if (p == NULL) break;
7731 SetUpChildIO(to_prog, from_prog);
7733 if ((pid = fork()) == 0) {
7735 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7736 close(to_prog[1]); // first close the unused pipe ends
7737 close(from_prog[0]);
7738 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7739 dup2(from_prog[1], 1);
7740 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7741 close(from_prog[1]); // and closing again loses one of the pipes!
7742 if(fileno(stderr) >= 2) // better safe than sorry...
7743 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7745 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7750 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7752 execvp(argv[0], argv);
7754 /* If we get here, exec failed */
7759 /* Parent process */
7761 close(from_prog[1]);
7763 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7766 cp->fdFrom = from_prog[0];
7767 cp->fdTo = to_prog[1];
7772 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7773 static RETSIGTYPE AlarmCallBack(int n)
7779 DestroyChildProcess(pr, signalType)
7783 ChildProc *cp = (ChildProc *) pr;
7785 if (cp->kind != CPReal) return;
7787 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7788 signal(SIGALRM, AlarmCallBack);
7790 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7791 kill(cp->pid, SIGKILL); // kill it forcefully
7792 wait((int *) 0); // and wait again
7796 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7798 /* Process is exiting either because of the kill or because of
7799 a quit command sent by the backend; either way, wait for it to die.
7808 InterruptChildProcess(pr)
7811 ChildProc *cp = (ChildProc *) pr;
7813 if (cp->kind != CPReal) return;
7814 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7817 int OpenTelnet(host, port, pr)
7822 char cmdLine[MSG_SIZ];
7824 if (port[0] == NULLCHAR) {
7825 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7827 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7829 return StartChildProcess(cmdLine, "", pr);
7832 int OpenTCP(host, port, pr)
7838 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7839 #else /* !OMIT_SOCKETS */
7841 struct sockaddr_in sa;
7843 unsigned short uport;
7846 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7850 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7851 sa.sin_family = AF_INET;
7852 sa.sin_addr.s_addr = INADDR_ANY;
7853 uport = (unsigned short) 0;
7854 sa.sin_port = htons(uport);
7855 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7859 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7860 if (!(hp = gethostbyname(host))) {
7862 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7863 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7864 hp->h_addrtype = AF_INET;
7866 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7867 hp->h_addr_list[0] = (char *) malloc(4);
7868 hp->h_addr_list[0][0] = b0;
7869 hp->h_addr_list[0][1] = b1;
7870 hp->h_addr_list[0][2] = b2;
7871 hp->h_addr_list[0][3] = b3;
7876 sa.sin_family = hp->h_addrtype;
7877 uport = (unsigned short) atoi(port);
7878 sa.sin_port = htons(uport);
7879 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7881 if (connect(s, (struct sockaddr *) &sa,
7882 sizeof(struct sockaddr_in)) < 0) {
7886 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7893 #endif /* !OMIT_SOCKETS */
7898 int OpenCommPort(name, pr)
7905 fd = open(name, 2, 0);
7906 if (fd < 0) return errno;
7908 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7918 int OpenLoopback(pr)
7924 SetUpChildIO(to, from);
7926 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7929 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7936 int OpenRcmd(host, user, cmd, pr)
7937 char *host, *user, *cmd;
7940 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7944 #define INPUT_SOURCE_BUF_SIZE 8192
7953 char buf[INPUT_SOURCE_BUF_SIZE];
7958 DoInputCallback(closure, source, xid)
7963 InputSource *is = (InputSource *) closure;
7968 if (is->lineByLine) {
7969 count = read(is->fd, is->unused,
7970 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7972 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7975 is->unused += count;
7977 while (p < is->unused) {
7978 q = memchr(p, '\n', is->unused - p);
7979 if (q == NULL) break;
7981 (is->func)(is, is->closure, p, q - p, 0);
7985 while (p < is->unused) {
7990 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7995 (is->func)(is, is->closure, is->buf, count, error);
7999 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8006 ChildProc *cp = (ChildProc *) pr;
8008 is = (InputSource *) calloc(1, sizeof(InputSource));
8009 is->lineByLine = lineByLine;
8013 is->fd = fileno(stdin);
8015 is->kind = cp->kind;
8016 is->fd = cp->fdFrom;
8019 is->unused = is->buf;
8022 is->xid = XtAppAddInput(appContext, is->fd,
8023 (XtPointer) (XtInputReadMask),
8024 (XtInputCallbackProc) DoInputCallback,
8026 is->closure = closure;
8027 return (InputSourceRef) is;
8031 RemoveInputSource(isr)
8034 InputSource *is = (InputSource *) isr;
8036 if (is->xid == 0) return;
8037 XtRemoveInput(is->xid);
8041 int OutputToProcess(pr, message, count, outError)
8047 static int line = 0;
8048 ChildProc *cp = (ChildProc *) pr;
8053 if (appData.noJoin || !appData.useInternalWrap)
8054 outCount = fwrite(message, 1, count, stdout);
8057 int width = get_term_width();
8058 int len = wrap(NULL, message, count, width, &line);
8059 char *msg = malloc(len);
8063 outCount = fwrite(message, 1, count, stdout);
8066 dbgchk = wrap(msg, message, count, width, &line);
8067 if (dbgchk != len && appData.debugMode)
8068 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8069 outCount = fwrite(msg, 1, dbgchk, stdout);
8075 outCount = write(cp->fdTo, message, count);
8085 /* Output message to process, with "ms" milliseconds of delay
8086 between each character. This is needed when sending the logon
8087 script to ICC, which for some reason doesn't like the
8088 instantaneous send. */
8089 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8096 ChildProc *cp = (ChildProc *) pr;
8101 r = write(cp->fdTo, message++, 1);
8114 /**** Animation code by Hugh Fisher, DCS, ANU.
8116 Known problem: if a window overlapping the board is
8117 moved away while a piece is being animated underneath,
8118 the newly exposed area won't be updated properly.
8119 I can live with this.
8121 Known problem: if you look carefully at the animation
8122 of pieces in mono mode, they are being drawn as solid
8123 shapes without interior detail while moving. Fixing
8124 this would be a major complication for minimal return.
8127 /* Masks for XPM pieces. Black and white pieces can have
8128 different shapes, but in the interest of retaining my
8129 sanity pieces must have the same outline on both light
8130 and dark squares, and all pieces must use the same
8131 background square colors/images. */
8133 static int xpmDone = 0;
8136 CreateAnimMasks (pieceDepth)
8143 unsigned long plane;
8146 /* Need a bitmap just to get a GC with right depth */
8147 buf = XCreatePixmap(xDisplay, xBoardWindow,
8149 values.foreground = 1;
8150 values.background = 0;
8151 /* Don't use XtGetGC, not read only */
8152 maskGC = XCreateGC(xDisplay, buf,
8153 GCForeground | GCBackground, &values);
8154 XFreePixmap(xDisplay, buf);
8156 buf = XCreatePixmap(xDisplay, xBoardWindow,
8157 squareSize, squareSize, pieceDepth);
8158 values.foreground = XBlackPixel(xDisplay, xScreen);
8159 values.background = XWhitePixel(xDisplay, xScreen);
8160 bufGC = XCreateGC(xDisplay, buf,
8161 GCForeground | GCBackground, &values);
8163 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8164 /* Begin with empty mask */
8165 if(!xpmDone) // [HGM] pieces: keep using existing
8166 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8167 squareSize, squareSize, 1);
8168 XSetFunction(xDisplay, maskGC, GXclear);
8169 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8170 0, 0, squareSize, squareSize);
8172 /* Take a copy of the piece */
8177 XSetFunction(xDisplay, bufGC, GXcopy);
8178 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8180 0, 0, squareSize, squareSize, 0, 0);
8182 /* XOR the background (light) over the piece */
8183 XSetFunction(xDisplay, bufGC, GXxor);
8185 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8186 0, 0, squareSize, squareSize, 0, 0);
8188 XSetForeground(xDisplay, bufGC, lightSquareColor);
8189 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8192 /* We now have an inverted piece image with the background
8193 erased. Construct mask by just selecting all the non-zero
8194 pixels - no need to reconstruct the original image. */
8195 XSetFunction(xDisplay, maskGC, GXor);
8197 /* Might be quicker to download an XImage and create bitmap
8198 data from it rather than this N copies per piece, but it
8199 only takes a fraction of a second and there is a much
8200 longer delay for loading the pieces. */
8201 for (n = 0; n < pieceDepth; n ++) {
8202 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8203 0, 0, squareSize, squareSize,
8209 XFreePixmap(xDisplay, buf);
8210 XFreeGC(xDisplay, bufGC);
8211 XFreeGC(xDisplay, maskGC);
8215 InitAnimState (anim, info)
8217 XWindowAttributes * info;
8222 /* Each buffer is square size, same depth as window */
8223 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8224 squareSize, squareSize, info->depth);
8225 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8226 squareSize, squareSize, info->depth);
8228 /* Create a plain GC for blitting */
8229 mask = GCForeground | GCBackground | GCFunction |
8230 GCPlaneMask | GCGraphicsExposures;
8231 values.foreground = XBlackPixel(xDisplay, xScreen);
8232 values.background = XWhitePixel(xDisplay, xScreen);
8233 values.function = GXcopy;
8234 values.plane_mask = AllPlanes;
8235 values.graphics_exposures = False;
8236 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8238 /* Piece will be copied from an existing context at
8239 the start of each new animation/drag. */
8240 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8242 /* Outline will be a read-only copy of an existing */
8243 anim->outlineGC = None;
8249 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8250 XWindowAttributes info;
8252 if (xpmDone && gameInfo.variant == old) return;
8253 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8254 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8256 InitAnimState(&game, &info);
8257 InitAnimState(&player, &info);
8259 /* For XPM pieces, we need bitmaps to use as masks. */
8261 CreateAnimMasks(info.depth);
8267 static Boolean frameWaiting;
8269 static RETSIGTYPE FrameAlarm (sig)
8272 frameWaiting = False;
8273 /* In case System-V style signals. Needed?? */
8274 signal(SIGALRM, FrameAlarm);
8281 struct itimerval delay;
8283 XSync(xDisplay, False);
8286 frameWaiting = True;
8287 signal(SIGALRM, FrameAlarm);
8288 delay.it_interval.tv_sec =
8289 delay.it_value.tv_sec = time / 1000;
8290 delay.it_interval.tv_usec =
8291 delay.it_value.tv_usec = (time % 1000) * 1000;
8292 setitimer(ITIMER_REAL, &delay, NULL);
8293 while (frameWaiting) pause();
8294 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8295 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8296 setitimer(ITIMER_REAL, &delay, NULL);
8306 XSync(xDisplay, False);
8308 usleep(time * 1000);
8313 /* Convert board position to corner of screen rect and color */
8316 ScreenSquare(column, row, pt, color)
8317 int column; int row; XPoint * pt; int * color;
8320 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8321 pt->y = lineGap + row * (squareSize + lineGap);
8323 pt->x = lineGap + column * (squareSize + lineGap);
8324 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8326 *color = SquareColor(row, column);
8329 /* Convert window coords to square */
8332 BoardSquare(x, y, column, row)
8333 int x; int y; int * column; int * row;
8335 *column = EventToSquare(x, BOARD_WIDTH);
8336 if (flipView && *column >= 0)
8337 *column = BOARD_WIDTH - 1 - *column;
8338 *row = EventToSquare(y, BOARD_HEIGHT);
8339 if (!flipView && *row >= 0)
8340 *row = BOARD_HEIGHT - 1 - *row;
8345 #undef Max /* just in case */
8347 #define Max(a, b) ((a) > (b) ? (a) : (b))
8348 #define Min(a, b) ((a) < (b) ? (a) : (b))
8351 SetRect(rect, x, y, width, height)
8352 XRectangle * rect; int x; int y; int width; int height;
8356 rect->width = width;
8357 rect->height = height;
8360 /* Test if two frames overlap. If they do, return
8361 intersection rect within old and location of
8362 that rect within new. */
8365 Intersect(old, new, size, area, pt)
8366 XPoint * old; XPoint * new;
8367 int size; XRectangle * area; XPoint * pt;
8369 if (old->x > new->x + size || new->x > old->x + size ||
8370 old->y > new->y + size || new->y > old->y + size) {
8373 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8374 size - abs(old->x - new->x), size - abs(old->y - new->y));
8375 pt->x = Max(old->x - new->x, 0);
8376 pt->y = Max(old->y - new->y, 0);
8381 /* For two overlapping frames, return the rect(s)
8382 in the old that do not intersect with the new. */
8385 CalcUpdateRects(old, new, size, update, nUpdates)
8386 XPoint * old; XPoint * new; int size;
8387 XRectangle update[]; int * nUpdates;
8391 /* If old = new (shouldn't happen) then nothing to draw */
8392 if (old->x == new->x && old->y == new->y) {
8396 /* Work out what bits overlap. Since we know the rects
8397 are the same size we don't need a full intersect calc. */
8399 /* Top or bottom edge? */
8400 if (new->y > old->y) {
8401 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8403 } else if (old->y > new->y) {
8404 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8405 size, old->y - new->y);
8408 /* Left or right edge - don't overlap any update calculated above. */
8409 if (new->x > old->x) {
8410 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8411 new->x - old->x, size - abs(new->y - old->y));
8413 } else if (old->x > new->x) {
8414 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8415 old->x - new->x, size - abs(new->y - old->y));
8422 /* Generate a series of frame coords from start->mid->finish.
8423 The movement rate doubles until the half way point is
8424 reached, then halves back down to the final destination,
8425 which gives a nice slow in/out effect. The algorithmn
8426 may seem to generate too many intermediates for short
8427 moves, but remember that the purpose is to attract the
8428 viewers attention to the piece about to be moved and
8429 then to where it ends up. Too few frames would be less
8433 Tween(start, mid, finish, factor, frames, nFrames)
8434 XPoint * start; XPoint * mid;
8435 XPoint * finish; int factor;
8436 XPoint frames[]; int * nFrames;
8438 int fraction, n, count;
8442 /* Slow in, stepping 1/16th, then 1/8th, ... */
8444 for (n = 0; n < factor; n++)
8446 for (n = 0; n < factor; n++) {
8447 frames[count].x = start->x + (mid->x - start->x) / fraction;
8448 frames[count].y = start->y + (mid->y - start->y) / fraction;
8450 fraction = fraction / 2;
8454 frames[count] = *mid;
8457 /* Slow out, stepping 1/2, then 1/4, ... */
8459 for (n = 0; n < factor; n++) {
8460 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8461 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8463 fraction = fraction * 2;
8468 /* Draw a piece on the screen without disturbing what's there */
8471 SelectGCMask(piece, clip, outline, mask)
8472 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8476 /* Bitmap for piece being moved. */
8477 if (appData.monoMode) {
8478 *mask = *pieceToSolid(piece);
8479 } else if (useImages) {
8481 *mask = xpmMask[piece];
8483 *mask = ximMaskPm[piece];
8486 *mask = *pieceToSolid(piece);
8489 /* GC for piece being moved. Square color doesn't matter, but
8490 since it gets modified we make a copy of the original. */
8492 if (appData.monoMode)
8497 if (appData.monoMode)
8502 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8504 /* Outline only used in mono mode and is not modified */
8506 *outline = bwPieceGC;
8508 *outline = wbPieceGC;
8512 OverlayPiece(piece, clip, outline, dest)
8513 ChessSquare piece; GC clip; GC outline; Drawable dest;
8518 /* Draw solid rectangle which will be clipped to shape of piece */
8519 XFillRectangle(xDisplay, dest, clip,
8520 0, 0, squareSize, squareSize);
8521 if (appData.monoMode)
8522 /* Also draw outline in contrasting color for black
8523 on black / white on white cases */
8524 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8525 0, 0, squareSize, squareSize, 0, 0, 1);
8527 /* Copy the piece */
8532 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8534 0, 0, squareSize, squareSize,
8539 /* Animate the movement of a single piece */
8542 BeginAnimation(anim, piece, startColor, start)
8550 /* The old buffer is initialised with the start square (empty) */
8551 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8552 anim->prevFrame = *start;
8554 /* The piece will be drawn using its own bitmap as a matte */
8555 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8556 XSetClipMask(xDisplay, anim->pieceGC, mask);
8560 AnimationFrame(anim, frame, piece)
8565 XRectangle updates[4];
8570 /* Save what we are about to draw into the new buffer */
8571 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8572 frame->x, frame->y, squareSize, squareSize,
8575 /* Erase bits of the previous frame */
8576 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8577 /* Where the new frame overlapped the previous,
8578 the contents in newBuf are wrong. */
8579 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8580 overlap.x, overlap.y,
8581 overlap.width, overlap.height,
8583 /* Repaint the areas in the old that don't overlap new */
8584 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8585 for (i = 0; i < count; i++)
8586 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8587 updates[i].x - anim->prevFrame.x,
8588 updates[i].y - anim->prevFrame.y,
8589 updates[i].width, updates[i].height,
8590 updates[i].x, updates[i].y);
8592 /* Easy when no overlap */
8593 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8594 0, 0, squareSize, squareSize,
8595 anim->prevFrame.x, anim->prevFrame.y);
8598 /* Save this frame for next time round */
8599 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8600 0, 0, squareSize, squareSize,
8602 anim->prevFrame = *frame;
8604 /* Draw piece over original screen contents, not current,
8605 and copy entire rect. Wipes out overlapping piece images. */
8606 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8607 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8608 0, 0, squareSize, squareSize,
8609 frame->x, frame->y);
8613 EndAnimation (anim, finish)
8617 XRectangle updates[4];
8622 /* The main code will redraw the final square, so we
8623 only need to erase the bits that don't overlap. */
8624 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8625 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8626 for (i = 0; i < count; i++)
8627 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8628 updates[i].x - anim->prevFrame.x,
8629 updates[i].y - anim->prevFrame.y,
8630 updates[i].width, updates[i].height,
8631 updates[i].x, updates[i].y);
8633 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8634 0, 0, squareSize, squareSize,
8635 anim->prevFrame.x, anim->prevFrame.y);
8640 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8642 ChessSquare piece; int startColor;
8643 XPoint * start; XPoint * finish;
8644 XPoint frames[]; int nFrames;
8648 BeginAnimation(anim, piece, startColor, start);
8649 for (n = 0; n < nFrames; n++) {
8650 AnimationFrame(anim, &(frames[n]), piece);
8651 FrameDelay(appData.animSpeed);
8653 EndAnimation(anim, finish);
8656 /* Main control logic for deciding what to animate and how */
8659 AnimateMove(board, fromX, fromY, toX, toY)
8668 XPoint start, finish, mid;
8669 XPoint frames[kFactor * 2 + 1];
8670 int nFrames, startColor, endColor;
8672 /* Are we animating? */
8673 if (!appData.animate || appData.blindfold)
8676 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8677 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8678 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8680 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8681 piece = board[fromY][fromX];
8682 if (piece >= EmptySquare) return;
8687 hop = (piece == WhiteKnight || piece == BlackKnight);
8690 if (appData.debugMode) {
8691 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8692 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8693 piece, fromX, fromY, toX, toY); }
8695 ScreenSquare(fromX, fromY, &start, &startColor);
8696 ScreenSquare(toX, toY, &finish, &endColor);
8699 /* Knight: make diagonal movement then straight */
8700 if (abs(toY - fromY) < abs(toX - fromX)) {
8701 mid.x = start.x + (finish.x - start.x) / 2;
8705 mid.y = start.y + (finish.y - start.y) / 2;
8708 mid.x = start.x + (finish.x - start.x) / 2;
8709 mid.y = start.y + (finish.y - start.y) / 2;
8712 /* Don't use as many frames for very short moves */
8713 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8714 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8716 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8717 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8719 /* Be sure end square is redrawn */
8720 damage[toY][toX] = True;
8724 DragPieceBegin(x, y)
8727 int boardX, boardY, color;
8730 /* Are we animating? */
8731 if (!appData.animateDragging || appData.blindfold)
8734 /* Figure out which square we start in and the
8735 mouse position relative to top left corner. */
8736 BoardSquare(x, y, &boardX, &boardY);
8737 player.startBoardX = boardX;
8738 player.startBoardY = boardY;
8739 ScreenSquare(boardX, boardY, &corner, &color);
8740 player.startSquare = corner;
8741 player.startColor = color;
8742 /* As soon as we start dragging, the piece will jump slightly to
8743 be centered over the mouse pointer. */
8744 player.mouseDelta.x = squareSize/2;
8745 player.mouseDelta.y = squareSize/2;
8746 /* Initialise animation */
8747 player.dragPiece = PieceForSquare(boardX, boardY);
8749 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8750 player.dragActive = True;
8751 BeginAnimation(&player, player.dragPiece, color, &corner);
8752 /* Mark this square as needing to be redrawn. Note that
8753 we don't remove the piece though, since logically (ie
8754 as seen by opponent) the move hasn't been made yet. */
8755 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8756 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8757 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8758 corner.x, corner.y, squareSize, squareSize,
8759 0, 0); // [HGM] zh: unstack in stead of grab
8760 damage[boardY][boardX] = True;
8762 player.dragActive = False;
8772 /* Are we animating? */
8773 if (!appData.animateDragging || appData.blindfold)
8777 if (! player.dragActive)
8779 /* Move piece, maintaining same relative position
8780 of mouse within square */
8781 corner.x = x - player.mouseDelta.x;
8782 corner.y = y - player.mouseDelta.y;
8783 AnimationFrame(&player, &corner, player.dragPiece);
8785 if (appData.highlightDragging) {
8787 BoardSquare(x, y, &boardX, &boardY);
8788 SetHighlights(fromX, fromY, boardX, boardY);
8797 int boardX, boardY, color;
8800 /* Are we animating? */
8801 if (!appData.animateDragging || appData.blindfold)
8805 if (! player.dragActive)
8807 /* Last frame in sequence is square piece is
8808 placed on, which may not match mouse exactly. */
8809 BoardSquare(x, y, &boardX, &boardY);
8810 ScreenSquare(boardX, boardY, &corner, &color);
8811 EndAnimation(&player, &corner);
8813 /* Be sure end square is redrawn */
8814 damage[boardY][boardX] = True;
8816 /* This prevents weird things happening with fast successive
8817 clicks which on my Sun at least can cause motion events
8818 without corresponding press/release. */
8819 player.dragActive = False;
8822 /* Handle expose event while piece being dragged */
8827 if (!player.dragActive || appData.blindfold)
8830 /* What we're doing: logically, the move hasn't been made yet,
8831 so the piece is still in it's original square. But visually
8832 it's being dragged around the board. So we erase the square
8833 that the piece is on and draw it at the last known drag point. */
8834 BlankSquare(player.startSquare.x, player.startSquare.y,
8835 player.startColor, EmptySquare, xBoardWindow);
8836 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8837 damage[player.startBoardY][player.startBoardX] = TRUE;
8840 #include <sys/ioctl.h>
8841 int get_term_width()
8843 int fd, default_width;
8846 default_width = 79; // this is FICS default anyway...
8848 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8850 if (!ioctl(fd, TIOCGSIZE, &win))
8851 default_width = win.ts_cols;
8852 #elif defined(TIOCGWINSZ)
8854 if (!ioctl(fd, TIOCGWINSZ, &win))
8855 default_width = win.ws_col;
8857 return default_width;
8860 void update_ics_width()
8862 static int old_width = 0;
8863 int new_width = get_term_width();
8865 if (old_width != new_width)
8866 ics_printf("set width %d\n", new_width);
8867 old_width = new_width;
8870 void NotifyFrontendLogin()