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 BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
373 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
375 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
378 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
380 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
382 void AutocommProc P((Widget w, XEvent *event, String *prms,
384 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AutobsProc P((Widget w, XEvent *event, String *prms,
388 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
393 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
396 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
398 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
400 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
404 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
406 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
408 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
410 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
412 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
416 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
418 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
420 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
422 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void DisplayMove P((int moveNumber));
434 void DisplayTitle P((char *title));
435 void ICSInitScript P((void));
436 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
437 void ErrorPopUp P((char *title, char *text, int modal));
438 void ErrorPopDown P((void));
439 static char *ExpandPathName P((char *path));
440 static void CreateAnimVars P((void));
441 static void DragPieceMove P((int x, int y));
442 static void DrawDragPiece P((void));
443 char *ModeToWidgetName P((GameMode mode));
444 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void GameListOptionsPopDown P(());
453 void ShufflePopDown P(());
454 void EnginePopDown P(());
455 void UciPopDown P(());
456 void TimeControlPopDown P(());
457 void NewVariantPopDown P(());
458 void SettingsPopDown P(());
459 void update_ics_width P(());
460 int get_term_width P(());
461 int CopyMemoProc P(());
463 * XBoard depends on Xt R4 or higher
465 int xtVersion = XtSpecificationRelease;
470 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
471 jailSquareColor, highlightSquareColor, premoveHighlightColor;
472 Pixel lowTimeWarningColor;
473 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
474 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
475 wjPieceGC, bjPieceGC, prelineGC, countGC;
476 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
477 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
478 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
479 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
480 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
481 ICSInputShell, fileNameShell, askQuestionShell;
482 Widget historyShell, evalGraphShell, gameListShell;
483 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
484 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
485 Font clockFontID, coordFontID, countFontID;
486 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
487 XtAppContext appContext;
489 char *oldICSInteractionTitle;
493 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
495 Position commentX = -1, commentY = -1;
496 Dimension commentW, commentH;
497 typedef unsigned int BoardSize;
499 Boolean chessProgram;
501 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
502 int squareSize, smallLayout = 0, tinyLayout = 0,
503 marginW, marginH, // [HGM] for run-time resizing
504 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
505 ICSInputBoxUp = False, askQuestionUp = False,
506 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
507 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
508 Pixel timerForegroundPixel, timerBackgroundPixel;
509 Pixel buttonForegroundPixel, buttonBackgroundPixel;
510 char *chessDir, *programName, *programVersion,
511 *gameCopyFilename, *gamePasteFilename;
512 Boolean alwaysOnTop = False;
513 Boolean saveSettingsOnExit;
514 char *settingsFileName;
515 char *icsTextMenuString;
517 char *firstChessProgramNames;
518 char *secondChessProgramNames;
520 WindowPlacement wpMain;
521 WindowPlacement wpConsole;
522 WindowPlacement wpComment;
523 WindowPlacement wpMoveHistory;
524 WindowPlacement wpEvalGraph;
525 WindowPlacement wpEngineOutput;
526 WindowPlacement wpGameList;
527 WindowPlacement wpTags;
531 Pixmap pieceBitmap[2][(int)BlackPawn];
532 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
533 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
534 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
535 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
536 int useImages, useImageSqs;
537 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
538 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
539 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
540 XImage *ximLightSquare, *ximDarkSquare;
543 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
544 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
546 #define White(piece) ((int)(piece) < (int)BlackPawn)
548 /* Variables for doing smooth animation. This whole thing
549 would be much easier if the board was double-buffered,
550 but that would require a fairly major rewrite. */
555 GC blitGC, pieceGC, outlineGC;
556 XPoint startSquare, prevFrame, mouseDelta;
560 int startBoardX, startBoardY;
563 /* There can be two pieces being animated at once: a player
564 can begin dragging a piece before the remote opponent has moved. */
566 static AnimState game, player;
568 /* Bitmaps for use as masks when drawing XPM pieces.
569 Need one for each black and white piece. */
570 static Pixmap xpmMask[BlackKing + 1];
572 /* This magic number is the number of intermediate frames used
573 in each half of the animation. For short moves it's reduced
574 by 1. The total number of frames will be factor * 2 + 1. */
577 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
579 MenuItem fileMenu[] = {
580 {N_("New Game"), ResetProc},
581 {N_("New Shuffle Game ..."), ShuffleMenuProc},
582 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
583 {"----", NothingProc},
584 {N_("Load Game"), LoadGameProc},
585 {N_("Load Next Game"), LoadNextGameProc},
586 {N_("Load Previous Game"), LoadPrevGameProc},
587 {N_("Reload Same Game"), ReloadGameProc},
588 {N_("Save Game"), SaveGameProc},
589 {"----", NothingProc},
590 {N_("Copy Game"), CopyGameProc},
591 {N_("Paste Game"), PasteGameProc},
592 {"----", NothingProc},
593 {N_("Load Position"), LoadPositionProc},
594 {N_("Load Next Position"), LoadNextPositionProc},
595 {N_("Load Previous Position"), LoadPrevPositionProc},
596 {N_("Reload Same Position"), ReloadPositionProc},
597 {N_("Save Position"), SavePositionProc},
598 {"----", NothingProc},
599 {N_("Copy Position"), CopyPositionProc},
600 {N_("Paste Position"), PastePositionProc},
601 {"----", NothingProc},
602 {N_("Mail Move"), MailMoveProc},
603 {N_("Reload CMail Message"), ReloadCmailMsgProc},
604 {"----", NothingProc},
605 {N_("Exit"), QuitProc},
609 MenuItem modeMenu[] = {
610 {N_("Machine White"), MachineWhiteProc},
611 {N_("Machine Black"), MachineBlackProc},
612 {N_("Two Machines"), TwoMachinesProc},
613 {N_("Analysis Mode"), AnalyzeModeProc},
614 {N_("Analyze File"), AnalyzeFileProc },
615 {N_("ICS Client"), IcsClientProc},
616 {N_("Edit Game"), EditGameProc},
617 {N_("Edit Position"), EditPositionProc},
618 {N_("Training"), TrainingProc},
619 {"----", NothingProc},
620 {N_("Show Engine Output"), EngineOutputProc},
621 {N_("Show Evaluation Graph"), EvalGraphProc},
622 {N_("Show Game List"), ShowGameListProc},
623 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
624 {"----", NothingProc},
625 {N_("Edit Tags"), EditTagsProc},
626 {N_("Edit Comment"), EditCommentProc},
627 {N_("ICS Input Box"), IcsInputBoxProc},
628 {N_("Pause"), PauseProc},
632 MenuItem actionMenu[] = {
633 {N_("Accept"), AcceptProc},
634 {N_("Decline"), DeclineProc},
635 {N_("Rematch"), RematchProc},
636 {"----", NothingProc},
637 {N_("Call Flag"), CallFlagProc},
638 {N_("Draw"), DrawProc},
639 {N_("Adjourn"), AdjournProc},
640 {N_("Abort"), AbortProc},
641 {N_("Resign"), ResignProc},
642 {"----", NothingProc},
643 {N_("Stop Observing"), StopObservingProc},
644 {N_("Stop Examining"), StopExaminingProc},
645 {"----", NothingProc},
646 {N_("Adjudicate to White"), AdjuWhiteProc},
647 {N_("Adjudicate to Black"), AdjuBlackProc},
648 {N_("Adjudicate Draw"), AdjuDrawProc},
652 MenuItem stepMenu[] = {
653 {N_("Backward"), BackwardProc},
654 {N_("Forward"), ForwardProc},
655 {N_("Back to Start"), ToStartProc},
656 {N_("Forward to End"), ToEndProc},
657 {N_("Revert"), RevertProc},
658 {N_("Truncate Game"), TruncateGameProc},
659 {"----", NothingProc},
660 {N_("Move Now"), MoveNowProc},
661 {N_("Retract Move"), RetractMoveProc},
665 MenuItem optionsMenu[] = {
666 {N_("Flip View"), FlipViewProc},
667 {"----", NothingProc},
668 {N_("Adjudications ..."), EngineMenuProc},
669 {N_("General Settings ..."), UciMenuProc},
670 {N_("Engine #1 Settings ..."), FirstSettingsProc},
671 {N_("Engine #2 Settings ..."), SecondSettingsProc},
672 {N_("Time Control ..."), TimeControlProc},
673 {N_("Game List ..."), GameListOptionsPopUp},
674 {"----", NothingProc},
675 {N_("Always Queen"), AlwaysQueenProc},
676 {N_("Animate Dragging"), AnimateDraggingProc},
677 {N_("Animate Moving"), AnimateMovingProc},
678 {N_("Auto Comment"), AutocommProc},
679 {N_("Auto Flag"), AutoflagProc},
680 {N_("Auto Flip View"), AutoflipProc},
681 {N_("Auto Observe"), AutobsProc},
682 {N_("Auto Raise Board"), AutoraiseProc},
683 {N_("Auto Save"), AutosaveProc},
684 {N_("Blindfold"), BlindfoldProc},
685 {N_("Flash Moves"), FlashMovesProc},
686 {N_("Get Move List"), GetMoveListProc},
688 {N_("Highlight Dragging"), HighlightDraggingProc},
690 {N_("Highlight Last Move"), HighlightLastMoveProc},
691 {N_("Move Sound"), MoveSoundProc},
692 {N_("ICS Alarm"), IcsAlarmProc},
693 {N_("Old Save Style"), OldSaveStyleProc},
694 {N_("Periodic Updates"), PeriodicUpdatesProc},
695 {N_("Ponder Next Move"), PonderNextMoveProc},
696 {N_("Popup Exit Message"), PopupExitMessageProc},
697 {N_("Popup Move Errors"), PopupMoveErrorsProc},
698 {N_("Premove"), PremoveProc},
699 {N_("Quiet Play"), QuietPlayProc},
700 {N_("Show Coords"), ShowCoordsProc},
701 {N_("Hide Thinking"), HideThinkingProc},
702 {N_("Test Legality"), TestLegalityProc},
703 {"----", NothingProc},
704 {N_("Save Settings Now"), SaveSettingsProc},
705 {N_("Save Settings on Exit"), SaveOnExitProc},
709 MenuItem helpMenu[] = {
710 {N_("Info XBoard"), InfoProc},
711 {N_("Man XBoard"), ManProc},
712 {"----", NothingProc},
713 {N_("Hint"), HintProc},
714 {N_("Book"), BookProc},
715 {"----", NothingProc},
716 {N_("About XBoard"), AboutProc},
721 {N_("File"), fileMenu},
722 {N_("Mode"), modeMenu},
723 {N_("Action"), actionMenu},
724 {N_("Step"), stepMenu},
725 {N_("Options"), optionsMenu},
726 {N_("Help"), helpMenu},
730 #define PAUSE_BUTTON N_("P")
731 MenuItem buttonBar[] = {
734 {PAUSE_BUTTON, PauseProc},
740 #define PIECE_MENU_SIZE 18
741 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
742 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
743 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
744 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
745 N_("Empty square"), N_("Clear board") },
746 { N_("Black"), "----", 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") }
751 /* must be in same order as PieceMenuStrings! */
752 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
753 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
754 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
755 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
756 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
757 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
758 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
759 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
760 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
763 #define DROP_MENU_SIZE 6
764 String dropMenuStrings[DROP_MENU_SIZE] = {
765 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
767 /* must be in same order as PieceMenuStrings! */
768 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
769 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
770 WhiteRook, WhiteQueen
778 DropMenuEnables dmEnables[] = {
796 { XtNborderWidth, 0 },
797 { XtNdefaultDistance, 0 },
801 { XtNborderWidth, 0 },
802 { XtNresizable, (XtArgVal) True },
806 { XtNborderWidth, 0 },
812 { XtNjustify, (XtArgVal) XtJustifyRight },
813 { XtNlabel, (XtArgVal) "..." },
814 { XtNresizable, (XtArgVal) True },
815 { XtNresize, (XtArgVal) False }
818 Arg messageArgs[] = {
819 { XtNjustify, (XtArgVal) XtJustifyLeft },
820 { XtNlabel, (XtArgVal) "..." },
821 { XtNresizable, (XtArgVal) True },
822 { XtNresize, (XtArgVal) False }
826 { XtNborderWidth, 0 },
827 { XtNjustify, (XtArgVal) XtJustifyLeft }
830 XtResource clientResources[] = {
831 { "flashCount", "flashCount", XtRInt, sizeof(int),
832 XtOffset(AppDataPtr, flashCount), XtRImmediate,
833 (XtPointer) FLASH_COUNT },
836 XrmOptionDescRec shellOptions[] = {
837 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
838 { "-flash", "flashCount", XrmoptionNoArg, "3" },
839 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
842 XtActionsRec boardActions[] = {
843 { "DrawPosition", DrawPositionProc },
844 { "HandleUserMove", HandleUserMove },
845 { "AnimateUserMove", AnimateUserMove },
846 { "HandlePV", HandlePV },
847 { "UnLoadPV", UnLoadPV },
848 { "FileNameAction", FileNameAction },
849 { "AskQuestionProc", AskQuestionProc },
850 { "AskQuestionReplyAction", AskQuestionReplyAction },
851 { "PieceMenuPopup", PieceMenuPopup },
852 { "WhiteClock", WhiteClock },
853 { "BlackClock", BlackClock },
854 { "Iconify", Iconify },
855 { "ResetProc", ResetProc },
856 { "LoadGameProc", LoadGameProc },
857 { "LoadNextGameProc", LoadNextGameProc },
858 { "LoadPrevGameProc", LoadPrevGameProc },
859 { "LoadSelectedProc", LoadSelectedProc },
860 { "SetFilterProc", SetFilterProc },
861 { "ReloadGameProc", ReloadGameProc },
862 { "LoadPositionProc", LoadPositionProc },
863 { "LoadNextPositionProc", LoadNextPositionProc },
864 { "LoadPrevPositionProc", LoadPrevPositionProc },
865 { "ReloadPositionProc", ReloadPositionProc },
866 { "CopyPositionProc", CopyPositionProc },
867 { "PastePositionProc", PastePositionProc },
868 { "CopyGameProc", CopyGameProc },
869 { "PasteGameProc", PasteGameProc },
870 { "SaveGameProc", SaveGameProc },
871 { "SavePositionProc", SavePositionProc },
872 { "MailMoveProc", MailMoveProc },
873 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
874 { "QuitProc", QuitProc },
875 { "MachineWhiteProc", MachineWhiteProc },
876 { "MachineBlackProc", MachineBlackProc },
877 { "AnalysisModeProc", AnalyzeModeProc },
878 { "AnalyzeFileProc", AnalyzeFileProc },
879 { "TwoMachinesProc", TwoMachinesProc },
880 { "IcsClientProc", IcsClientProc },
881 { "EditGameProc", EditGameProc },
882 { "EditPositionProc", EditPositionProc },
883 { "TrainingProc", EditPositionProc },
884 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
885 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
886 { "ShowGameListProc", ShowGameListProc },
887 { "ShowMoveListProc", HistoryShowProc},
888 { "EditTagsProc", EditCommentProc },
889 { "EditCommentProc", EditCommentProc },
890 { "IcsAlarmProc", IcsAlarmProc },
891 { "IcsInputBoxProc", IcsInputBoxProc },
892 { "PauseProc", PauseProc },
893 { "AcceptProc", AcceptProc },
894 { "DeclineProc", DeclineProc },
895 { "RematchProc", RematchProc },
896 { "CallFlagProc", CallFlagProc },
897 { "DrawProc", DrawProc },
898 { "AdjournProc", AdjournProc },
899 { "AbortProc", AbortProc },
900 { "ResignProc", ResignProc },
901 { "AdjuWhiteProc", AdjuWhiteProc },
902 { "AdjuBlackProc", AdjuBlackProc },
903 { "AdjuDrawProc", AdjuDrawProc },
904 { "EnterKeyProc", EnterKeyProc },
905 { "UpKeyProc", UpKeyProc },
906 { "DownKeyProc", DownKeyProc },
907 { "StopObservingProc", StopObservingProc },
908 { "StopExaminingProc", StopExaminingProc },
909 { "BackwardProc", BackwardProc },
910 { "ForwardProc", ForwardProc },
911 { "ToStartProc", ToStartProc },
912 { "ToEndProc", ToEndProc },
913 { "RevertProc", RevertProc },
914 { "TruncateGameProc", TruncateGameProc },
915 { "MoveNowProc", MoveNowProc },
916 { "RetractMoveProc", RetractMoveProc },
917 { "AlwaysQueenProc", AlwaysQueenProc },
918 { "AnimateDraggingProc", AnimateDraggingProc },
919 { "AnimateMovingProc", AnimateMovingProc },
920 { "AutoflagProc", AutoflagProc },
921 { "AutoflipProc", AutoflipProc },
922 { "AutobsProc", AutobsProc },
923 { "AutoraiseProc", AutoraiseProc },
924 { "AutosaveProc", AutosaveProc },
925 { "BlindfoldProc", BlindfoldProc },
926 { "FlashMovesProc", FlashMovesProc },
927 { "FlipViewProc", FlipViewProc },
928 { "GetMoveListProc", GetMoveListProc },
930 { "HighlightDraggingProc", HighlightDraggingProc },
932 { "HighlightLastMoveProc", HighlightLastMoveProc },
933 { "IcsAlarmProc", IcsAlarmProc },
934 { "MoveSoundProc", MoveSoundProc },
935 { "OldSaveStyleProc", OldSaveStyleProc },
936 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
937 { "PonderNextMoveProc", PonderNextMoveProc },
938 { "PopupExitMessageProc", PopupExitMessageProc },
939 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
940 { "PremoveProc", PremoveProc },
941 { "QuietPlayProc", QuietPlayProc },
942 { "ShowCoordsProc", ShowCoordsProc },
943 { "ShowThinkingProc", ShowThinkingProc },
944 { "HideThinkingProc", HideThinkingProc },
945 { "TestLegalityProc", TestLegalityProc },
946 { "SaveSettingsProc", SaveSettingsProc },
947 { "SaveOnExitProc", SaveOnExitProc },
948 { "InfoProc", InfoProc },
949 { "ManProc", ManProc },
950 { "HintProc", HintProc },
951 { "BookProc", BookProc },
952 { "AboutGameProc", AboutGameProc },
953 { "AboutProc", AboutProc },
954 { "DebugProc", DebugProc },
955 { "NothingProc", NothingProc },
956 { "CommentPopDown", (XtActionProc) CommentPopDown },
957 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
958 { "TagsPopDown", (XtActionProc) TagsPopDown },
959 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
960 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
961 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
962 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
963 { "GameListPopDown", (XtActionProc) GameListPopDown },
964 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
965 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
966 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
967 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
968 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
969 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
970 { "EnginePopDown", (XtActionProc) EnginePopDown },
971 { "UciPopDown", (XtActionProc) UciPopDown },
972 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
973 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
974 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
975 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
978 char globalTranslations[] =
979 ":<Key>R: ResignProc() \n \
980 :<Key>r: ResetProc() \n \
981 :<Key>g: LoadGameProc() \n \
982 :<Key>N: LoadNextGameProc() \n \
983 :<Key>P: LoadPrevGameProc() \n \
984 :<Key>Q: QuitProc() \n \
985 :<Key>F: ToEndProc() \n \
986 :<Key>f: ForwardProc() \n \
987 :<Key>B: ToStartProc() \n \
988 :<Key>b: BackwardProc() \n \
989 :<Key>p: PauseProc() \n \
990 :<Key>d: DrawProc() \n \
991 :<Key>t: CallFlagProc() \n \
992 :<Key>i: Iconify() \n \
993 :<Key>c: Iconify() \n \
994 :<Key>v: FlipViewProc() \n \
995 <KeyDown>Control_L: BackwardProc() \n \
996 <KeyUp>Control_L: ForwardProc() \n \
997 <KeyDown>Control_R: BackwardProc() \n \
998 <KeyUp>Control_R: ForwardProc() \n \
999 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1000 \"Send to chess program:\",,1) \n \
1001 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1002 \"Send to second chess program:\",,2) \n";
1004 char boardTranslations[] =
1005 "<Btn1Down>: HandleUserMove() \n \
1006 <Btn1Up>: HandleUserMove() \n \
1007 <Btn1Motion>: AnimateUserMove() \n \
1008 <Btn3Motion>: HandlePV() \n \
1009 <Btn3Up>: PieceMenuPopup(menuB) \n \
1010 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1011 PieceMenuPopup(menuB) \n \
1012 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1013 PieceMenuPopup(menuW) \n \
1014 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1015 PieceMenuPopup(menuW) \n \
1016 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1017 PieceMenuPopup(menuB) \n";
1019 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1020 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1022 char ICSInputTranslations[] =
1023 "<Key>Up: UpKeyProc() \n "
1024 "<Key>Down: DownKeyProc() \n "
1025 "<Key>Return: EnterKeyProc() \n";
1027 String xboardResources[] = {
1028 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1029 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1030 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1035 /* Max possible square size */
1036 #define MAXSQSIZE 256
1038 static int xpm_avail[MAXSQSIZE];
1040 #ifdef HAVE_DIR_STRUCT
1042 /* Extract piece size from filename */
1044 xpm_getsize(name, len, ext)
1055 if ((p=strchr(name, '.')) == NULL ||
1056 StrCaseCmp(p+1, ext) != 0)
1062 while (*p && isdigit(*p))
1069 /* Setup xpm_avail */
1071 xpm_getavail(dirname, ext)
1079 for (i=0; i<MAXSQSIZE; ++i)
1082 if (appData.debugMode)
1083 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1085 dir = opendir(dirname);
1088 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1089 programName, dirname);
1093 while ((ent=readdir(dir)) != NULL) {
1094 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1095 if (i > 0 && i < MAXSQSIZE)
1105 xpm_print_avail(fp, ext)
1111 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1118 /* Return XPM piecesize closest to size */
1120 xpm_closest_to(dirname, size, ext)
1126 int sm_diff = MAXSQSIZE;
1130 xpm_getavail(dirname, ext);
1132 if (appData.debugMode)
1133 xpm_print_avail(stderr, ext);
1135 for (i=1; i<MAXSQSIZE; ++i) {
1138 diff = (diff<0) ? -diff : diff;
1139 if (diff < sm_diff) {
1147 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1153 #else /* !HAVE_DIR_STRUCT */
1154 /* If we are on a system without a DIR struct, we can't
1155 read the directory, so we can't collect a list of
1156 filenames, etc., so we can't do any size-fitting. */
1158 xpm_closest_to(dirname, size, ext)
1163 fprintf(stderr, _("\
1164 Warning: No DIR structure found on this system --\n\
1165 Unable to autosize for XPM/XIM pieces.\n\
1166 Please report this error to frankm@hiwaay.net.\n\
1167 Include system type & operating system in message.\n"));
1170 #endif /* HAVE_DIR_STRUCT */
1172 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1173 "magenta", "cyan", "white" };
1177 TextColors textColors[(int)NColorClasses];
1179 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1181 parse_color(str, which)
1185 char *p, buf[100], *d;
1188 if (strlen(str) > 99) /* watch bounds on buf */
1193 for (i=0; i<which; ++i) {
1200 /* Could be looking at something like:
1202 .. in which case we want to stop on a comma also */
1203 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1207 return -1; /* Use default for empty field */
1210 if (which == 2 || isdigit(*p))
1213 while (*p && isalpha(*p))
1218 for (i=0; i<8; ++i) {
1219 if (!StrCaseCmp(buf, cnames[i]))
1220 return which? (i+40) : (i+30);
1222 if (!StrCaseCmp(buf, "default")) return -1;
1224 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1229 parse_cpair(cc, str)
1233 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1234 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1239 /* bg and attr are optional */
1240 textColors[(int)cc].bg = parse_color(str, 1);
1241 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1242 textColors[(int)cc].attr = 0;
1248 /* Arrange to catch delete-window events */
1249 Atom wm_delete_window;
1251 CatchDeleteWindow(Widget w, String procname)
1254 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1255 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1256 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1263 XtSetArg(args[0], XtNiconic, False);
1264 XtSetValues(shellWidget, args, 1);
1266 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1269 //---------------------------------------------------------------------------------------------------------
1270 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1273 #define CW_USEDEFAULT (1<<31)
1274 #define ICS_TEXT_MENU_SIZE 90
1275 #define DEBUG_FILE "xboard.debug"
1276 #define SetCurrentDirectory chdir
1277 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1281 // these two must some day move to frontend.h, when they are implemented
1282 Boolean GameListIsUp();
1284 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1287 // front-end part of option handling
1289 // [HGM] This platform-dependent table provides the location for storing the color info
1290 extern char *crWhite, * crBlack;
1294 &appData.whitePieceColor,
1295 &appData.blackPieceColor,
1296 &appData.lightSquareColor,
1297 &appData.darkSquareColor,
1298 &appData.highlightSquareColor,
1299 &appData.premoveHighlightColor,
1300 &appData.lowTimeWarningColor,
1311 // [HGM] font: keep a font for each square size, even non-stndard ones
1312 #define NUM_SIZES 18
1313 #define MAX_SIZE 130
1314 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1315 char *fontTable[NUM_FONTS][MAX_SIZE];
1318 ParseFont(char *name, int number)
1319 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1321 if(sscanf(name, "size%d:", &size)) {
1322 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1323 // defer processing it until we know if it matches our board size
1324 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1325 fontTable[number][size] = strdup(strchr(name, ':')+1);
1326 fontValid[number][size] = True;
1331 case 0: // CLOCK_FONT
1332 appData.clockFont = strdup(name);
1334 case 1: // MESSAGE_FONT
1335 appData.font = strdup(name);
1337 case 2: // COORD_FONT
1338 appData.coordFont = strdup(name);
1343 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1348 { // only 2 fonts currently
1349 appData.clockFont = CLOCK_FONT_NAME;
1350 appData.coordFont = COORD_FONT_NAME;
1351 appData.font = DEFAULT_FONT_NAME;
1356 { // no-op, until we identify the code for this already in XBoard and move it here
1360 ParseColor(int n, char *name)
1361 { // in XBoard, just copy the color-name string
1362 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1366 ParseTextAttribs(ColorClass cc, char *s)
1368 (&appData.colorShout)[cc] = strdup(s);
1372 ParseBoardSize(void *addr, char *name)
1374 appData.boardSize = strdup(name);
1379 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1383 SetCommPortDefaults()
1384 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1387 // [HGM] args: these three cases taken out to stay in front-end
1389 SaveFontArg(FILE *f, ArgDescriptor *ad)
1391 char *name, buf[MSG_SIZ];
1392 int i, n = (int)ad->argLoc;
1394 case 0: // CLOCK_FONT
1395 name = appData.clockFont;
1397 case 1: // MESSAGE_FONT
1398 name = appData.font;
1400 case 2: // COORD_FONT
1401 name = appData.coordFont;
1406 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1407 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1408 fontTable[n][squareSize] = strdup(name);
1409 fontValid[n][squareSize] = True;
1412 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1413 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1418 { // nothing to do, as the sounds are at all times represented by their text-string names already
1422 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1423 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1424 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1428 SaveColor(FILE *f, ArgDescriptor *ad)
1429 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1430 if(colorVariable[(int)ad->argLoc])
1431 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1435 SaveBoardSize(FILE *f, char *name, void *addr)
1436 { // wrapper to shield back-end from BoardSize & sizeInfo
1437 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1441 ParseCommPortSettings(char *s)
1442 { // no such option in XBoard (yet)
1445 extern Widget engineOutputShell;
1446 extern Widget tagsShell, editTagsShell;
1448 GetActualPlacement(Widget wg, WindowPlacement *wp)
1458 XtSetArg(args[i], XtNx, &x); i++;
1459 XtSetArg(args[i], XtNy, &y); i++;
1460 XtSetArg(args[i], XtNwidth, &w); i++;
1461 XtSetArg(args[i], XtNheight, &h); i++;
1462 XtGetValues(wg, args, i);
1471 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1472 // In XBoard this will have to wait until awareness of window parameters is implemented
1473 GetActualPlacement(shellWidget, &wpMain);
1474 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1475 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1476 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1477 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1478 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1479 else GetActualPlacement(editShell, &wpComment);
1480 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1481 else GetActualPlacement(editTagsShell, &wpTags);
1485 PrintCommPortSettings(FILE *f, char *name)
1486 { // This option does not exist in XBoard
1490 MySearchPath(char *installDir, char *name, char *fullname)
1491 { // just append installDir and name. Perhaps ExpandPath should be used here?
1492 name = ExpandPathName(name);
1493 if(name && name[0] == '/') strcpy(fullname, name); else {
1494 sprintf(fullname, "%s%c%s", installDir, '/', name);
1500 MyGetFullPathName(char *name, char *fullname)
1501 { // should use ExpandPath?
1502 name = ExpandPathName(name);
1503 strcpy(fullname, name);
1508 EnsureOnScreen(int *x, int *y, int minX, int minY)
1515 { // [HGM] args: allows testing if main window is realized from back-end
1516 return xBoardWindow != 0;
1520 PopUpStartupDialog()
1521 { // start menu not implemented in XBoard
1524 ConvertToLine(int argc, char **argv)
1526 static char line[128*1024], buf[1024];
1530 for(i=1; i<argc; i++) {
1531 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1532 && argv[i][0] != '{' )
1533 sprintf(buf, "{%s} ", argv[i]);
1534 else sprintf(buf, "%s ", argv[i]);
1537 line[strlen(line)-1] = NULLCHAR;
1541 //--------------------------------------------------------------------------------------------
1544 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1546 #define BoardSize int
1547 void InitDrawingSizes(BoardSize boardSize, int flags)
1548 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1549 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1551 XtGeometryResult gres;
1554 if(!formWidget) return;
1557 * Enable shell resizing.
1559 shellArgs[0].value = (XtArgVal) &w;
1560 shellArgs[1].value = (XtArgVal) &h;
1561 XtGetValues(shellWidget, shellArgs, 2);
1563 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1564 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1565 XtSetValues(shellWidget, &shellArgs[2], 4);
1567 XtSetArg(args[0], XtNdefaultDistance, &sep);
1568 XtGetValues(formWidget, args, 1);
1570 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1571 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1574 XtSetArg(args[0], XtNwidth, boardWidth);
1575 XtSetArg(args[1], XtNheight, boardHeight);
1576 XtSetValues(boardWidget, args, 2);
1578 timerWidth = (boardWidth - sep) / 2;
1579 XtSetArg(args[0], XtNwidth, timerWidth);
1580 XtSetValues(whiteTimerWidget, args, 1);
1581 XtSetValues(blackTimerWidget, args, 1);
1583 XawFormDoLayout(formWidget, False);
1585 if (appData.titleInWindow) {
1587 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1588 XtSetArg(args[i], XtNheight, &h); i++;
1589 XtGetValues(titleWidget, args, i);
1591 w = boardWidth - 2*bor;
1593 XtSetArg(args[0], XtNwidth, &w);
1594 XtGetValues(menuBarWidget, args, 1);
1595 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1598 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1599 if (gres != XtGeometryYes && appData.debugMode) {
1601 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1602 programName, gres, w, h, wr, hr);
1606 XawFormDoLayout(formWidget, True);
1609 * Inhibit shell resizing.
1611 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1612 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1613 shellArgs[4].value = shellArgs[2].value = w;
1614 shellArgs[5].value = shellArgs[3].value = h;
1615 XtSetValues(shellWidget, &shellArgs[0], 6);
1617 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1620 for(i=0; i<4; i++) {
1622 for(p=0; p<=(int)WhiteKing; p++)
1623 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1624 if(gameInfo.variant == VariantShogi) {
1625 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1626 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1627 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1628 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1629 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1632 if(gameInfo.variant == VariantGothic) {
1633 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1637 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1638 for(p=0; p<=(int)WhiteKing; p++)
1639 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1640 if(gameInfo.variant == VariantShogi) {
1641 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1642 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1643 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1644 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1645 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1648 if(gameInfo.variant == VariantGothic) {
1649 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1655 for(i=0; i<2; i++) {
1657 for(p=0; p<=(int)WhiteKing; p++)
1658 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1659 if(gameInfo.variant == VariantShogi) {
1660 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1661 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1662 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1663 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1664 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1667 if(gameInfo.variant == VariantGothic) {
1668 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1679 void EscapeExpand(char *p, char *q)
1680 { // [HGM] initstring: routine to shape up string arguments
1681 while(*p++ = *q++) if(p[-1] == '\\')
1683 case 'n': p[-1] = '\n'; break;
1684 case 'r': p[-1] = '\r'; break;
1685 case 't': p[-1] = '\t'; break;
1686 case '\\': p[-1] = '\\'; break;
1687 case 0: *p = 0; return;
1688 default: p[-1] = q[-1]; break;
1697 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1698 XSetWindowAttributes window_attributes;
1700 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1701 XrmValue vFrom, vTo;
1702 XtGeometryResult gres;
1705 int forceMono = False;
1707 srandom(time(0)); // [HGM] book: make random truly random
1709 setbuf(stdout, NULL);
1710 setbuf(stderr, NULL);
1713 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1714 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1718 programName = strrchr(argv[0], '/');
1719 if (programName == NULL)
1720 programName = argv[0];
1725 XtSetLanguageProc(NULL, NULL, NULL);
1726 bindtextdomain(PACKAGE, LOCALEDIR);
1727 textdomain(PACKAGE);
1731 XtAppInitialize(&appContext, "XBoard", shellOptions,
1732 XtNumber(shellOptions),
1733 &argc, argv, xboardResources, NULL, 0);
1734 appData.boardSize = "";
1735 InitAppData(ConvertToLine(argc, argv));
1737 if (p == NULL) p = "/tmp";
1738 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1739 gameCopyFilename = (char*) malloc(i);
1740 gamePasteFilename = (char*) malloc(i);
1741 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1742 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1744 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1745 clientResources, XtNumber(clientResources),
1748 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1749 static char buf[MSG_SIZ];
1750 EscapeExpand(buf, appData.initString);
1751 appData.initString = strdup(buf);
1752 EscapeExpand(buf, appData.secondInitString);
1753 appData.secondInitString = strdup(buf);
1754 EscapeExpand(buf, appData.firstComputerString);
1755 appData.firstComputerString = strdup(buf);
1756 EscapeExpand(buf, appData.secondComputerString);
1757 appData.secondComputerString = strdup(buf);
1760 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1763 if (chdir(chessDir) != 0) {
1764 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1770 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1771 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1772 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1773 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1776 setbuf(debugFP, NULL);
1779 /* [HGM,HR] make sure board size is acceptable */
1780 if(appData.NrFiles > BOARD_FILES ||
1781 appData.NrRanks > BOARD_RANKS )
1782 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1785 /* This feature does not work; animation needs a rewrite */
1786 appData.highlightDragging = FALSE;
1790 xDisplay = XtDisplay(shellWidget);
1791 xScreen = DefaultScreen(xDisplay);
1792 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1794 gameInfo.variant = StringToVariant(appData.variant);
1795 InitPosition(FALSE);
1798 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1800 if (isdigit(appData.boardSize[0])) {
1801 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1802 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1803 &fontPxlSize, &smallLayout, &tinyLayout);
1805 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1806 programName, appData.boardSize);
1810 /* Find some defaults; use the nearest known size */
1811 SizeDefaults *szd, *nearest;
1812 int distance = 99999;
1813 nearest = szd = sizeDefaults;
1814 while (szd->name != NULL) {
1815 if (abs(szd->squareSize - squareSize) < distance) {
1817 distance = abs(szd->squareSize - squareSize);
1818 if (distance == 0) break;
1822 if (i < 2) lineGap = nearest->lineGap;
1823 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1824 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1825 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1826 if (i < 6) smallLayout = nearest->smallLayout;
1827 if (i < 7) tinyLayout = nearest->tinyLayout;
1830 SizeDefaults *szd = sizeDefaults;
1831 if (*appData.boardSize == NULLCHAR) {
1832 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1833 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1836 if (szd->name == NULL) szd--;
1837 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1839 while (szd->name != NULL &&
1840 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1841 if (szd->name == NULL) {
1842 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1843 programName, appData.boardSize);
1847 squareSize = szd->squareSize;
1848 lineGap = szd->lineGap;
1849 clockFontPxlSize = szd->clockFontPxlSize;
1850 coordFontPxlSize = szd->coordFontPxlSize;
1851 fontPxlSize = szd->fontPxlSize;
1852 smallLayout = szd->smallLayout;
1853 tinyLayout = szd->tinyLayout;
1854 // [HGM] font: use defaults from settings file if available and not overruled
1856 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1857 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1858 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1859 appData.font = fontTable[MESSAGE_FONT][squareSize];
1860 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1861 appData.coordFont = fontTable[COORD_FONT][squareSize];
1863 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1864 if (strlen(appData.pixmapDirectory) > 0) {
1865 p = ExpandPathName(appData.pixmapDirectory);
1867 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1868 appData.pixmapDirectory);
1871 if (appData.debugMode) {
1872 fprintf(stderr, _("\
1873 XBoard square size (hint): %d\n\
1874 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1876 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1877 if (appData.debugMode) {
1878 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1882 /* [HR] height treated separately (hacked) */
1883 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1884 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1885 if (appData.showJail == 1) {
1886 /* Jail on top and bottom */
1887 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1888 XtSetArg(boardArgs[2], XtNheight,
1889 boardHeight + 2*(lineGap + squareSize));
1890 } else if (appData.showJail == 2) {
1892 XtSetArg(boardArgs[1], XtNwidth,
1893 boardWidth + 2*(lineGap + squareSize));
1894 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1897 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1898 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1902 * Determine what fonts to use.
1904 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1905 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1906 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1907 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1908 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1909 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1910 appData.font = FindFont(appData.font, fontPxlSize);
1911 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1912 countFontStruct = XQueryFont(xDisplay, countFontID);
1913 // appData.font = FindFont(appData.font, fontPxlSize);
1915 xdb = XtDatabase(xDisplay);
1916 XrmPutStringResource(&xdb, "*font", appData.font);
1919 * Detect if there are not enough colors available and adapt.
1921 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1922 appData.monoMode = True;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.lightSquareColor;
1927 vFrom.size = strlen(appData.lightSquareColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 lightSquareColor = *(Pixel *) vTo.addr;
1936 if (!appData.monoMode) {
1937 vFrom.addr = (caddr_t) appData.darkSquareColor;
1938 vFrom.size = strlen(appData.darkSquareColor);
1939 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1940 if (vTo.addr == NULL) {
1941 appData.monoMode = True;
1944 darkSquareColor = *(Pixel *) vTo.addr;
1947 if (!appData.monoMode) {
1948 vFrom.addr = (caddr_t) appData.whitePieceColor;
1949 vFrom.size = strlen(appData.whitePieceColor);
1950 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1951 if (vTo.addr == NULL) {
1952 appData.monoMode = True;
1955 whitePieceColor = *(Pixel *) vTo.addr;
1958 if (!appData.monoMode) {
1959 vFrom.addr = (caddr_t) appData.blackPieceColor;
1960 vFrom.size = strlen(appData.blackPieceColor);
1961 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1962 if (vTo.addr == NULL) {
1963 appData.monoMode = True;
1966 blackPieceColor = *(Pixel *) vTo.addr;
1970 if (!appData.monoMode) {
1971 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1972 vFrom.size = strlen(appData.highlightSquareColor);
1973 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1974 if (vTo.addr == NULL) {
1975 appData.monoMode = True;
1978 highlightSquareColor = *(Pixel *) vTo.addr;
1982 if (!appData.monoMode) {
1983 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1984 vFrom.size = strlen(appData.premoveHighlightColor);
1985 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1986 if (vTo.addr == NULL) {
1987 appData.monoMode = True;
1990 premoveHighlightColor = *(Pixel *) vTo.addr;
1995 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1998 if (appData.bitmapDirectory == NULL ||
1999 appData.bitmapDirectory[0] == NULLCHAR)
2000 appData.bitmapDirectory = DEF_BITMAP_DIR;
2003 if (appData.lowTimeWarning && !appData.monoMode) {
2004 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2005 vFrom.size = strlen(appData.lowTimeWarningColor);
2006 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2007 if (vTo.addr == NULL)
2008 appData.monoMode = True;
2010 lowTimeWarningColor = *(Pixel *) vTo.addr;
2013 if (appData.monoMode && appData.debugMode) {
2014 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2015 (unsigned long) XWhitePixel(xDisplay, xScreen),
2016 (unsigned long) XBlackPixel(xDisplay, xScreen));
2019 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2020 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2021 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2022 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2023 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2024 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2025 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2026 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2027 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2028 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2030 if (appData.colorize) {
2032 _("%s: can't parse color names; disabling colorization\n"),
2035 appData.colorize = FALSE;
2037 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2038 textColors[ColorNone].attr = 0;
2040 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2046 layoutName = "tinyLayout";
2047 } else if (smallLayout) {
2048 layoutName = "smallLayout";
2050 layoutName = "normalLayout";
2052 /* Outer layoutWidget is there only to provide a name for use in
2053 resources that depend on the layout style */
2055 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2056 layoutArgs, XtNumber(layoutArgs));
2058 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2059 formArgs, XtNumber(formArgs));
2060 XtSetArg(args[0], XtNdefaultDistance, &sep);
2061 XtGetValues(formWidget, args, 1);
2064 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2065 XtSetArg(args[0], XtNtop, XtChainTop);
2066 XtSetArg(args[1], XtNbottom, XtChainTop);
2067 XtSetArg(args[2], XtNright, XtChainLeft);
2068 XtSetValues(menuBarWidget, args, 3);
2070 widgetList[j++] = whiteTimerWidget =
2071 XtCreateWidget("whiteTime", labelWidgetClass,
2072 formWidget, timerArgs, XtNumber(timerArgs));
2073 XtSetArg(args[0], XtNfont, clockFontStruct);
2074 XtSetArg(args[1], XtNtop, XtChainTop);
2075 XtSetArg(args[2], XtNbottom, XtChainTop);
2076 XtSetValues(whiteTimerWidget, args, 3);
2078 widgetList[j++] = blackTimerWidget =
2079 XtCreateWidget("blackTime", labelWidgetClass,
2080 formWidget, timerArgs, XtNumber(timerArgs));
2081 XtSetArg(args[0], XtNfont, clockFontStruct);
2082 XtSetArg(args[1], XtNtop, XtChainTop);
2083 XtSetArg(args[2], XtNbottom, XtChainTop);
2084 XtSetValues(blackTimerWidget, args, 3);
2086 if (appData.titleInWindow) {
2087 widgetList[j++] = titleWidget =
2088 XtCreateWidget("title", labelWidgetClass, formWidget,
2089 titleArgs, XtNumber(titleArgs));
2090 XtSetArg(args[0], XtNtop, XtChainTop);
2091 XtSetArg(args[1], XtNbottom, XtChainTop);
2092 XtSetValues(titleWidget, args, 2);
2095 if (appData.showButtonBar) {
2096 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2097 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2098 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2099 XtSetArg(args[2], XtNtop, XtChainTop);
2100 XtSetArg(args[3], XtNbottom, XtChainTop);
2101 XtSetValues(buttonBarWidget, args, 4);
2104 widgetList[j++] = messageWidget =
2105 XtCreateWidget("message", labelWidgetClass, formWidget,
2106 messageArgs, XtNumber(messageArgs));
2107 XtSetArg(args[0], XtNtop, XtChainTop);
2108 XtSetArg(args[1], XtNbottom, XtChainTop);
2109 XtSetValues(messageWidget, args, 2);
2111 widgetList[j++] = boardWidget =
2112 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2113 XtNumber(boardArgs));
2115 XtManageChildren(widgetList, j);
2117 timerWidth = (boardWidth - sep) / 2;
2118 XtSetArg(args[0], XtNwidth, timerWidth);
2119 XtSetValues(whiteTimerWidget, args, 1);
2120 XtSetValues(blackTimerWidget, args, 1);
2122 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2123 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2124 XtGetValues(whiteTimerWidget, args, 2);
2126 if (appData.showButtonBar) {
2127 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2128 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2129 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2133 * formWidget uses these constraints but they are stored
2137 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2138 XtSetValues(menuBarWidget, args, i);
2139 if (appData.titleInWindow) {
2142 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2143 XtSetValues(whiteTimerWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2146 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2147 XtSetValues(blackTimerWidget, args, i);
2149 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2150 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2151 XtSetValues(titleWidget, args, i);
2153 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2154 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2155 XtSetValues(messageWidget, args, i);
2156 if (appData.showButtonBar) {
2158 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2159 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2160 XtSetValues(buttonBarWidget, args, i);
2164 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2165 XtSetValues(whiteTimerWidget, args, i);
2167 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2168 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2169 XtSetValues(blackTimerWidget, args, i);
2171 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2172 XtSetValues(titleWidget, args, i);
2174 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2175 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2176 XtSetValues(messageWidget, args, i);
2177 if (appData.showButtonBar) {
2179 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2180 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2181 XtSetValues(buttonBarWidget, args, i);
2186 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2187 XtSetValues(whiteTimerWidget, args, i);
2189 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2190 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2191 XtSetValues(blackTimerWidget, args, i);
2193 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2194 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2195 XtSetValues(messageWidget, args, i);
2196 if (appData.showButtonBar) {
2198 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2199 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2200 XtSetValues(buttonBarWidget, args, i);
2204 XtSetArg(args[0], XtNfromVert, messageWidget);
2205 XtSetArg(args[1], XtNtop, XtChainTop);
2206 XtSetArg(args[2], XtNbottom, XtChainBottom);
2207 XtSetArg(args[3], XtNleft, XtChainLeft);
2208 XtSetArg(args[4], XtNright, XtChainRight);
2209 XtSetValues(boardWidget, args, 5);
2211 XtRealizeWidget(shellWidget);
2214 XtSetArg(args[0], XtNx, wpMain.x);
2215 XtSetArg(args[1], XtNy, wpMain.y);
2216 XtSetValues(shellWidget, args, 2);
2220 * Correct the width of the message and title widgets.
2221 * It is not known why some systems need the extra fudge term.
2222 * The value "2" is probably larger than needed.
2224 XawFormDoLayout(formWidget, False);
2226 #define WIDTH_FUDGE 2
2228 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2229 XtSetArg(args[i], XtNheight, &h); i++;
2230 XtGetValues(messageWidget, args, i);
2231 if (appData.showButtonBar) {
2233 XtSetArg(args[i], XtNwidth, &w); i++;
2234 XtGetValues(buttonBarWidget, args, i);
2235 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2237 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2240 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2241 if (gres != XtGeometryYes && appData.debugMode) {
2242 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2243 programName, gres, w, h, wr, hr);
2246 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2247 /* The size used for the child widget in layout lags one resize behind
2248 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2250 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2251 if (gres != XtGeometryYes && appData.debugMode) {
2252 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2253 programName, gres, w, h, wr, hr);
2256 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2257 XtSetArg(args[1], XtNright, XtChainRight);
2258 XtSetValues(messageWidget, args, 2);
2260 if (appData.titleInWindow) {
2262 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2263 XtSetArg(args[i], XtNheight, &h); i++;
2264 XtGetValues(titleWidget, args, i);
2266 w = boardWidth - 2*bor;
2268 XtSetArg(args[0], XtNwidth, &w);
2269 XtGetValues(menuBarWidget, args, 1);
2270 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2273 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2274 if (gres != XtGeometryYes && appData.debugMode) {
2276 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2277 programName, gres, w, h, wr, hr);
2280 XawFormDoLayout(formWidget, True);
2282 xBoardWindow = XtWindow(boardWidget);
2284 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2285 // not need to go into InitDrawingSizes().
2289 * Create X checkmark bitmap and initialize option menu checks.
2291 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2292 checkmark_bits, checkmark_width, checkmark_height);
2293 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2294 if (appData.alwaysPromoteToQueen) {
2295 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2298 if (appData.animateDragging) {
2299 XtSetValues(XtNameToWidget(menuBarWidget,
2300 "menuOptions.Animate Dragging"),
2303 if (appData.animate) {
2304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2307 if (appData.autoComment) {
2308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2311 if (appData.autoCallFlag) {
2312 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2315 if (appData.autoFlipView) {
2316 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2319 if (appData.autoObserve) {
2320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2323 if (appData.autoRaiseBoard) {
2324 XtSetValues(XtNameToWidget(menuBarWidget,
2325 "menuOptions.Auto Raise Board"), args, 1);
2327 if (appData.autoSaveGames) {
2328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2331 if (appData.saveGameFile[0] != NULLCHAR) {
2332 /* Can't turn this off from menu */
2333 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2335 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2339 if (appData.blindfold) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Blindfold"), args, 1);
2343 if (appData.flashCount > 0) {
2344 XtSetValues(XtNameToWidget(menuBarWidget,
2345 "menuOptions.Flash Moves"),
2348 if (appData.getMoveList) {
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2353 if (appData.highlightDragging) {
2354 XtSetValues(XtNameToWidget(menuBarWidget,
2355 "menuOptions.Highlight Dragging"),
2359 if (appData.highlightLastMove) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,
2361 "menuOptions.Highlight Last Move"),
2364 if (appData.icsAlarm) {
2365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2368 if (appData.ringBellAfterMoves) {
2369 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2372 if (appData.oldSaveStyle) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Old Save Style"), args, 1);
2376 if (appData.periodicUpdates) {
2377 XtSetValues(XtNameToWidget(menuBarWidget,
2378 "menuOptions.Periodic Updates"), args, 1);
2380 if (appData.ponderNextMove) {
2381 XtSetValues(XtNameToWidget(menuBarWidget,
2382 "menuOptions.Ponder Next Move"), args, 1);
2384 if (appData.popupExitMessage) {
2385 XtSetValues(XtNameToWidget(menuBarWidget,
2386 "menuOptions.Popup Exit Message"), args, 1);
2388 if (appData.popupMoveErrors) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,
2390 "menuOptions.Popup Move Errors"), args, 1);
2392 if (appData.premove) {
2393 XtSetValues(XtNameToWidget(menuBarWidget,
2394 "menuOptions.Premove"), args, 1);
2396 if (appData.quietPlay) {
2397 XtSetValues(XtNameToWidget(menuBarWidget,
2398 "menuOptions.Quiet Play"), args, 1);
2400 if (appData.showCoords) {
2401 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2404 if (appData.hideThinkingFromHuman) {
2405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2408 if (appData.testLegality) {
2409 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2412 if (saveSettingsOnExit) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2420 ReadBitmap(&wIconPixmap, "icon_white.bm",
2421 icon_white_bits, icon_white_width, icon_white_height);
2422 ReadBitmap(&bIconPixmap, "icon_black.bm",
2423 icon_black_bits, icon_black_width, icon_black_height);
2424 iconPixmap = wIconPixmap;
2426 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2427 XtSetValues(shellWidget, args, i);
2430 * Create a cursor for the board widget.
2432 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2433 XChangeWindowAttributes(xDisplay, xBoardWindow,
2434 CWCursor, &window_attributes);
2437 * Inhibit shell resizing.
2439 shellArgs[0].value = (XtArgVal) &w;
2440 shellArgs[1].value = (XtArgVal) &h;
2441 XtGetValues(shellWidget, shellArgs, 2);
2442 shellArgs[4].value = shellArgs[2].value = w;
2443 shellArgs[5].value = shellArgs[3].value = h;
2444 XtSetValues(shellWidget, &shellArgs[2], 4);
2445 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2446 marginH = h - boardHeight;
2448 CatchDeleteWindow(shellWidget, "QuitProc");
2453 if (appData.bitmapDirectory[0] != NULLCHAR) {
2460 /* Create regular pieces */
2461 if (!useImages) CreatePieces();
2466 if (appData.animate || appData.animateDragging)
2469 XtAugmentTranslations(formWidget,
2470 XtParseTranslationTable(globalTranslations));
2471 XtAugmentTranslations(boardWidget,
2472 XtParseTranslationTable(boardTranslations));
2473 XtAugmentTranslations(whiteTimerWidget,
2474 XtParseTranslationTable(whiteTranslations));
2475 XtAugmentTranslations(blackTimerWidget,
2476 XtParseTranslationTable(blackTranslations));
2478 /* Why is the following needed on some versions of X instead
2479 * of a translation? */
2480 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2481 (XtEventHandler) EventProc, NULL);
2484 /* [AS] Restore layout */
2485 if( wpMoveHistory.visible ) {
2489 if( wpEvalGraph.visible )
2494 if( wpEngineOutput.visible ) {
2495 EngineOutputPopUp();
2500 if (errorExitStatus == -1) {
2501 if (appData.icsActive) {
2502 /* We now wait until we see "login:" from the ICS before
2503 sending the logon script (problems with timestamp otherwise) */
2504 /*ICSInitScript();*/
2505 if (appData.icsInputBox) ICSInputBoxPopUp();
2509 signal(SIGWINCH, TermSizeSigHandler);
2511 signal(SIGINT, IntSigHandler);
2512 signal(SIGTERM, IntSigHandler);
2513 if (*appData.cmailGameName != NULLCHAR) {
2514 signal(SIGUSR1, CmailSigHandler);
2517 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2520 XtAppMainLoop(appContext);
2521 if (appData.debugMode) fclose(debugFP); // [DM] debug
2528 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2529 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2531 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2532 unlink(gameCopyFilename);
2533 unlink(gamePasteFilename);
2536 RETSIGTYPE TermSizeSigHandler(int sig)
2549 CmailSigHandler(sig)
2555 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2557 /* Activate call-back function CmailSigHandlerCallBack() */
2558 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2560 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2564 CmailSigHandlerCallBack(isr, closure, message, count, error)
2572 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2574 /**** end signal code ****/
2584 f = fopen(appData.icsLogon, "r");
2590 strcat(buf, appData.icsLogon);
2591 f = fopen(buf, "r");
2595 ProcessICSInitScript(f);
2602 EditCommentPopDown();
2617 if (!menuBarWidget) return;
2618 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2620 DisplayError("menuStep.Revert", 0);
2622 XtSetSensitive(w, !grey);
2627 SetMenuEnables(enab)
2631 if (!menuBarWidget) return;
2632 while (enab->name != NULL) {
2633 w = XtNameToWidget(menuBarWidget, enab->name);
2635 DisplayError(enab->name, 0);
2637 XtSetSensitive(w, enab->value);
2643 Enables icsEnables[] = {
2644 { "menuFile.Mail Move", False },
2645 { "menuFile.Reload CMail Message", False },
2646 { "menuMode.Machine Black", False },
2647 { "menuMode.Machine White", False },
2648 { "menuMode.Analysis Mode", False },
2649 { "menuMode.Analyze File", False },
2650 { "menuMode.Two Machines", False },
2652 { "menuHelp.Hint", False },
2653 { "menuHelp.Book", False },
2654 { "menuStep.Move Now", False },
2655 { "menuOptions.Periodic Updates", False },
2656 { "menuOptions.Hide Thinking", False },
2657 { "menuOptions.Ponder Next Move", False },
2662 Enables ncpEnables[] = {
2663 { "menuFile.Mail Move", False },
2664 { "menuFile.Reload CMail Message", False },
2665 { "menuMode.Machine White", False },
2666 { "menuMode.Machine Black", False },
2667 { "menuMode.Analysis Mode", False },
2668 { "menuMode.Analyze File", False },
2669 { "menuMode.Two Machines", False },
2670 { "menuMode.ICS Client", False },
2671 { "menuMode.ICS Input Box", False },
2672 { "Action", False },
2673 { "menuStep.Revert", False },
2674 { "menuStep.Move Now", False },
2675 { "menuStep.Retract Move", False },
2676 { "menuOptions.Auto Comment", False },
2677 { "menuOptions.Auto Flag", False },
2678 { "menuOptions.Auto Flip View", False },
2679 { "menuOptions.Auto Observe", False },
2680 { "menuOptions.Auto Raise Board", False },
2681 { "menuOptions.Get Move List", False },
2682 { "menuOptions.ICS Alarm", False },
2683 { "menuOptions.Move Sound", False },
2684 { "menuOptions.Quiet Play", False },
2685 { "menuOptions.Hide Thinking", False },
2686 { "menuOptions.Periodic Updates", False },
2687 { "menuOptions.Ponder Next Move", False },
2688 { "menuHelp.Hint", False },
2689 { "menuHelp.Book", False },
2693 Enables gnuEnables[] = {
2694 { "menuMode.ICS Client", False },
2695 { "menuMode.ICS Input Box", False },
2696 { "menuAction.Accept", False },
2697 { "menuAction.Decline", False },
2698 { "menuAction.Rematch", False },
2699 { "menuAction.Adjourn", False },
2700 { "menuAction.Stop Examining", False },
2701 { "menuAction.Stop Observing", False },
2702 { "menuStep.Revert", False },
2703 { "menuOptions.Auto Comment", False },
2704 { "menuOptions.Auto Observe", False },
2705 { "menuOptions.Auto Raise Board", False },
2706 { "menuOptions.Get Move List", False },
2707 { "menuOptions.Premove", False },
2708 { "menuOptions.Quiet Play", False },
2710 /* The next two options rely on SetCmailMode being called *after* */
2711 /* SetGNUMode so that when GNU is being used to give hints these */
2712 /* menu options are still available */
2714 { "menuFile.Mail Move", False },
2715 { "menuFile.Reload CMail Message", False },
2719 Enables cmailEnables[] = {
2721 { "menuAction.Call Flag", False },
2722 { "menuAction.Draw", True },
2723 { "menuAction.Adjourn", False },
2724 { "menuAction.Abort", False },
2725 { "menuAction.Stop Observing", False },
2726 { "menuAction.Stop Examining", False },
2727 { "menuFile.Mail Move", True },
2728 { "menuFile.Reload CMail Message", True },
2732 Enables trainingOnEnables[] = {
2733 { "menuMode.Edit Comment", False },
2734 { "menuMode.Pause", False },
2735 { "menuStep.Forward", False },
2736 { "menuStep.Backward", False },
2737 { "menuStep.Forward to End", False },
2738 { "menuStep.Back to Start", False },
2739 { "menuStep.Move Now", False },
2740 { "menuStep.Truncate Game", False },
2744 Enables trainingOffEnables[] = {
2745 { "menuMode.Edit Comment", True },
2746 { "menuMode.Pause", True },
2747 { "menuStep.Forward", True },
2748 { "menuStep.Backward", True },
2749 { "menuStep.Forward to End", True },
2750 { "menuStep.Back to Start", True },
2751 { "menuStep.Move Now", True },
2752 { "menuStep.Truncate Game", True },
2756 Enables machineThinkingEnables[] = {
2757 { "menuFile.Load Game", False },
2758 { "menuFile.Load Next Game", False },
2759 { "menuFile.Load Previous Game", False },
2760 { "menuFile.Reload Same Game", False },
2761 { "menuFile.Paste Game", False },
2762 { "menuFile.Load Position", False },
2763 { "menuFile.Load Next Position", False },
2764 { "menuFile.Load Previous Position", False },
2765 { "menuFile.Reload Same Position", False },
2766 { "menuFile.Paste Position", False },
2767 { "menuMode.Machine White", False },
2768 { "menuMode.Machine Black", False },
2769 { "menuMode.Two Machines", False },
2770 { "menuStep.Retract Move", False },
2774 Enables userThinkingEnables[] = {
2775 { "menuFile.Load Game", True },
2776 { "menuFile.Load Next Game", True },
2777 { "menuFile.Load Previous Game", True },
2778 { "menuFile.Reload Same Game", True },
2779 { "menuFile.Paste Game", True },
2780 { "menuFile.Load Position", True },
2781 { "menuFile.Load Next Position", True },
2782 { "menuFile.Load Previous Position", True },
2783 { "menuFile.Reload Same Position", True },
2784 { "menuFile.Paste Position", True },
2785 { "menuMode.Machine White", True },
2786 { "menuMode.Machine Black", True },
2787 { "menuMode.Two Machines", True },
2788 { "menuStep.Retract Move", True },
2794 SetMenuEnables(icsEnables);
2797 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2798 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2805 SetMenuEnables(ncpEnables);
2811 SetMenuEnables(gnuEnables);
2817 SetMenuEnables(cmailEnables);
2823 SetMenuEnables(trainingOnEnables);
2824 if (appData.showButtonBar) {
2825 XtSetSensitive(buttonBarWidget, False);
2831 SetTrainingModeOff()
2833 SetMenuEnables(trainingOffEnables);
2834 if (appData.showButtonBar) {
2835 XtSetSensitive(buttonBarWidget, True);
2840 SetUserThinkingEnables()
2842 if (appData.noChessProgram) return;
2843 SetMenuEnables(userThinkingEnables);
2847 SetMachineThinkingEnables()
2849 if (appData.noChessProgram) return;
2850 SetMenuEnables(machineThinkingEnables);
2852 case MachinePlaysBlack:
2853 case MachinePlaysWhite:
2854 case TwoMachinesPlay:
2855 XtSetSensitive(XtNameToWidget(menuBarWidget,
2856 ModeToWidgetName(gameMode)), True);
2863 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2864 #define HISTORY_SIZE 64
\r
2865 static char *history[HISTORY_SIZE];
\r
2866 int histIn = 0, histP = 0;
\r
2869 SaveInHistory(char *cmd)
\r
2871 if (history[histIn] != NULL) {
\r
2872 free(history[histIn]);
\r
2873 history[histIn] = NULL;
\r
2875 if (*cmd == NULLCHAR) return;
\r
2876 history[histIn] = StrSave(cmd);
\r
2877 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2878 if (history[histIn] != NULL) {
\r
2879 free(history[histIn]);
\r
2880 history[histIn] = NULL;
\r
2886 PrevInHistory(char *cmd)
\r
2889 if (histP == histIn) {
\r
2890 if (history[histIn] != NULL) free(history[histIn]);
\r
2891 history[histIn] = StrSave(cmd);
\r
2893 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2894 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2896 return history[histP];
\r
2902 if (histP == histIn) return NULL;
\r
2903 histP = (histP + 1) % HISTORY_SIZE;
\r
2904 return history[histP];
\r
2906 // end of borrowed code
\r
2908 #define Abs(n) ((n)<0 ? -(n) : (n))
2911 * Find a font that matches "pattern" that is as close as
2912 * possible to the targetPxlSize. Prefer fonts that are k
2913 * pixels smaller to fonts that are k pixels larger. The
2914 * pattern must be in the X Consortium standard format,
2915 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2916 * The return value should be freed with XtFree when no
2919 char *FindFont(pattern, targetPxlSize)
2923 char **fonts, *p, *best, *scalable, *scalableTail;
2924 int i, j, nfonts, minerr, err, pxlSize;
2927 char **missing_list;
2929 char *def_string, *base_fnt_lst, strInt[3];
2931 XFontStruct **fnt_list;
2933 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2934 sprintf(strInt, "%d", targetPxlSize);
2935 p = strstr(pattern, "--");
2936 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2937 strcat(base_fnt_lst, strInt);
2938 strcat(base_fnt_lst, strchr(p + 2, '-'));
2940 if ((fntSet = XCreateFontSet(xDisplay,
2944 &def_string)) == NULL) {
2946 fprintf(stderr, _("Unable to create font set.\n"));
2950 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2952 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2954 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2955 programName, pattern);
2963 for (i=0; i<nfonts; i++) {
2966 if (*p != '-') continue;
2968 if (*p == NULLCHAR) break;
2969 if (*p++ == '-') j++;
2971 if (j < 7) continue;
2974 scalable = fonts[i];
2977 err = pxlSize - targetPxlSize;
2978 if (Abs(err) < Abs(minerr) ||
2979 (minerr > 0 && err < 0 && -err == minerr)) {
2985 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2986 /* If the error is too big and there is a scalable font,
2987 use the scalable font. */
2988 int headlen = scalableTail - scalable;
2989 p = (char *) XtMalloc(strlen(scalable) + 10);
2990 while (isdigit(*scalableTail)) scalableTail++;
2991 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2993 p = (char *) XtMalloc(strlen(best) + 1);
2996 if (appData.debugMode) {
2997 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2998 pattern, targetPxlSize, p);
3001 if (missing_count > 0)
3002 XFreeStringList(missing_list);
3003 XFreeFontSet(xDisplay, fntSet);
3005 XFreeFontNames(fonts);
3012 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3013 | GCBackground | GCFunction | GCPlaneMask;
3014 XGCValues gc_values;
3017 gc_values.plane_mask = AllPlanes;
3018 gc_values.line_width = lineGap;
3019 gc_values.line_style = LineSolid;
3020 gc_values.function = GXcopy;
3022 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3023 gc_values.background = XBlackPixel(xDisplay, xScreen);
3024 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3026 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3027 gc_values.background = XWhitePixel(xDisplay, xScreen);
3028 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3029 XSetFont(xDisplay, coordGC, coordFontID);
3031 // [HGM] make font for holdings counts (white on black0
3032 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3033 gc_values.background = XBlackPixel(xDisplay, xScreen);
3034 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3035 XSetFont(xDisplay, countGC, countFontID);
3037 if (appData.monoMode) {
3038 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3039 gc_values.background = XWhitePixel(xDisplay, xScreen);
3040 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3042 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3043 gc_values.background = XBlackPixel(xDisplay, xScreen);
3044 lightSquareGC = wbPieceGC
3045 = XtGetGC(shellWidget, value_mask, &gc_values);
3047 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3048 gc_values.background = XWhitePixel(xDisplay, xScreen);
3049 darkSquareGC = bwPieceGC
3050 = XtGetGC(shellWidget, value_mask, &gc_values);
3052 if (DefaultDepth(xDisplay, xScreen) == 1) {
3053 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3054 gc_values.function = GXcopyInverted;
3055 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3056 gc_values.function = GXcopy;
3057 if (XBlackPixel(xDisplay, xScreen) == 1) {
3058 bwPieceGC = darkSquareGC;
3059 wbPieceGC = copyInvertedGC;
3061 bwPieceGC = copyInvertedGC;
3062 wbPieceGC = lightSquareGC;
3066 gc_values.foreground = highlightSquareColor;
3067 gc_values.background = highlightSquareColor;
3068 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3070 gc_values.foreground = premoveHighlightColor;
3071 gc_values.background = premoveHighlightColor;
3072 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3074 gc_values.foreground = lightSquareColor;
3075 gc_values.background = darkSquareColor;
3076 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3078 gc_values.foreground = darkSquareColor;
3079 gc_values.background = lightSquareColor;
3080 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3082 gc_values.foreground = jailSquareColor;
3083 gc_values.background = jailSquareColor;
3084 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3086 gc_values.foreground = whitePieceColor;
3087 gc_values.background = darkSquareColor;
3088 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3090 gc_values.foreground = whitePieceColor;
3091 gc_values.background = lightSquareColor;
3092 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3094 gc_values.foreground = whitePieceColor;
3095 gc_values.background = jailSquareColor;
3096 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3098 gc_values.foreground = blackPieceColor;
3099 gc_values.background = darkSquareColor;
3100 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3102 gc_values.foreground = blackPieceColor;
3103 gc_values.background = lightSquareColor;
3104 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 gc_values.foreground = blackPieceColor;
3107 gc_values.background = jailSquareColor;
3108 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3112 void loadXIM(xim, xmask, filename, dest, mask)
3125 fp = fopen(filename, "rb");
3127 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3134 for (y=0; y<h; ++y) {
3135 for (x=0; x<h; ++x) {
3140 XPutPixel(xim, x, y, blackPieceColor);
3142 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3145 XPutPixel(xim, x, y, darkSquareColor);
3147 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3150 XPutPixel(xim, x, y, whitePieceColor);
3152 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3155 XPutPixel(xim, x, y, lightSquareColor);
3157 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3163 /* create Pixmap of piece */
3164 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3166 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3169 /* create Pixmap of clipmask
3170 Note: We assume the white/black pieces have the same
3171 outline, so we make only 6 masks. This is okay
3172 since the XPM clipmask routines do the same. */
3174 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3176 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3179 /* now create the 1-bit version */
3180 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3183 values.foreground = 1;
3184 values.background = 0;
3186 /* Don't use XtGetGC, not read only */
3187 maskGC = XCreateGC(xDisplay, *mask,
3188 GCForeground | GCBackground, &values);
3189 XCopyPlane(xDisplay, temp, *mask, maskGC,
3190 0, 0, squareSize, squareSize, 0, 0, 1);
3191 XFreePixmap(xDisplay, temp);
3196 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3198 void CreateXIMPieces()
3203 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3208 /* The XSynchronize calls were copied from CreatePieces.
3209 Not sure if needed, but can't hurt */
3210 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3213 /* temp needed by loadXIM() */
3214 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3215 0, 0, ss, ss, AllPlanes, XYPixmap);
3217 if (strlen(appData.pixmapDirectory) == 0) {
3221 if (appData.monoMode) {
3222 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3226 fprintf(stderr, _("\nLoading XIMs...\n"));
3228 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3229 fprintf(stderr, "%d", piece+1);
3230 for (kind=0; kind<4; kind++) {
3231 fprintf(stderr, ".");
3232 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3233 ExpandPathName(appData.pixmapDirectory),
3234 piece <= (int) WhiteKing ? "" : "w",
3235 pieceBitmapNames[piece],
3237 ximPieceBitmap[kind][piece] =
3238 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3239 0, 0, ss, ss, AllPlanes, XYPixmap);
3240 if (appData.debugMode)
3241 fprintf(stderr, _("(File:%s:) "), buf);
3242 loadXIM(ximPieceBitmap[kind][piece],
3244 &(xpmPieceBitmap2[kind][piece]),
3245 &(ximMaskPm2[piece]));
3246 if(piece <= (int)WhiteKing)
3247 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3249 fprintf(stderr," ");
3251 /* Load light and dark squares */
3252 /* If the LSQ and DSQ pieces don't exist, we will
3253 draw them with solid squares. */
3254 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3255 if (access(buf, 0) != 0) {
3259 fprintf(stderr, _("light square "));
3261 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3262 0, 0, ss, ss, AllPlanes, XYPixmap);
3263 if (appData.debugMode)
3264 fprintf(stderr, _("(File:%s:) "), buf);
3266 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3267 fprintf(stderr, _("dark square "));
3268 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3269 ExpandPathName(appData.pixmapDirectory), ss);
3270 if (appData.debugMode)
3271 fprintf(stderr, _("(File:%s:) "), buf);
3273 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3274 0, 0, ss, ss, AllPlanes, XYPixmap);
3275 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3276 xpmJailSquare = xpmLightSquare;
3278 fprintf(stderr, _("Done.\n"));
3280 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3284 void CreateXPMPieces()
3288 u_int ss = squareSize;
3290 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3291 XpmColorSymbol symbols[4];
3293 /* The XSynchronize calls were copied from CreatePieces.
3294 Not sure if needed, but can't hurt */
3295 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3297 /* Setup translations so piece colors match square colors */
3298 symbols[0].name = "light_piece";
3299 symbols[0].value = appData.whitePieceColor;
3300 symbols[1].name = "dark_piece";
3301 symbols[1].value = appData.blackPieceColor;
3302 symbols[2].name = "light_square";
3303 symbols[2].value = appData.lightSquareColor;
3304 symbols[3].name = "dark_square";
3305 symbols[3].value = appData.darkSquareColor;
3307 attr.valuemask = XpmColorSymbols;
3308 attr.colorsymbols = symbols;
3309 attr.numsymbols = 4;
3311 if (appData.monoMode) {
3312 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3316 if (strlen(appData.pixmapDirectory) == 0) {
3317 XpmPieces* pieces = builtInXpms;
3320 while (pieces->size != squareSize && pieces->size) pieces++;
3321 if (!pieces->size) {
3322 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3325 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3326 for (kind=0; kind<4; kind++) {
3328 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3329 pieces->xpm[piece][kind],
3330 &(xpmPieceBitmap2[kind][piece]),
3331 NULL, &attr)) != 0) {
3332 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3336 if(piece <= (int) WhiteKing)
3337 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3341 xpmJailSquare = xpmLightSquare;
3345 fprintf(stderr, _("\nLoading XPMs...\n"));
3348 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3349 fprintf(stderr, "%d ", piece+1);
3350 for (kind=0; kind<4; kind++) {
3351 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3352 ExpandPathName(appData.pixmapDirectory),
3353 piece > (int) WhiteKing ? "w" : "",
3354 pieceBitmapNames[piece],
3356 if (appData.debugMode) {
3357 fprintf(stderr, _("(File:%s:) "), buf);
3359 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3360 &(xpmPieceBitmap2[kind][piece]),
3361 NULL, &attr)) != 0) {
3362 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3363 // [HGM] missing: read of unorthodox piece failed; substitute King.
3364 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3365 ExpandPathName(appData.pixmapDirectory),
3367 if (appData.debugMode) {
3368 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3370 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3371 &(xpmPieceBitmap2[kind][piece]),
3375 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3380 if(piece <= (int) WhiteKing)
3381 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3384 /* Load light and dark squares */
3385 /* If the LSQ and DSQ pieces don't exist, we will
3386 draw them with solid squares. */
3387 fprintf(stderr, _("light square "));
3388 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3389 if (access(buf, 0) != 0) {
3393 if (appData.debugMode)
3394 fprintf(stderr, _("(File:%s:) "), buf);
3396 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3397 &xpmLightSquare, NULL, &attr)) != 0) {
3398 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3401 fprintf(stderr, _("dark square "));
3402 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3403 ExpandPathName(appData.pixmapDirectory), ss);
3404 if (appData.debugMode) {
3405 fprintf(stderr, _("(File:%s:) "), buf);
3407 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3408 &xpmDarkSquare, NULL, &attr)) != 0) {
3409 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3413 xpmJailSquare = xpmLightSquare;
3414 fprintf(stderr, _("Done.\n"));
3416 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3419 #endif /* HAVE_LIBXPM */
3422 /* No built-in bitmaps */
3427 u_int ss = squareSize;
3429 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3432 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3433 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3434 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3435 pieceBitmapNames[piece],
3436 ss, kind == SOLID ? 's' : 'o');
3437 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3438 if(piece <= (int)WhiteKing)
3439 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3443 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3447 /* With built-in bitmaps */
3450 BuiltInBits* bib = builtInBits;
3453 u_int ss = squareSize;
3455 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3458 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3460 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3461 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3462 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3463 pieceBitmapNames[piece],
3464 ss, kind == SOLID ? 's' : 'o');
3465 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3466 bib->bits[kind][piece], ss, ss);
3467 if(piece <= (int)WhiteKing)
3468 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3472 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3477 void ReadBitmap(pm, name, bits, wreq, hreq)
3480 unsigned char bits[];
3486 char msg[MSG_SIZ], fullname[MSG_SIZ];
3488 if (*appData.bitmapDirectory != NULLCHAR) {
3489 strcpy(fullname, appData.bitmapDirectory);
3490 strcat(fullname, "/");
3491 strcat(fullname, name);
3492 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3493 &w, &h, pm, &x_hot, &y_hot);
3494 fprintf(stderr, "load %s\n", name);
3495 if (errcode != BitmapSuccess) {
3497 case BitmapOpenFailed:
3498 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3500 case BitmapFileInvalid:
3501 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3503 case BitmapNoMemory:
3504 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3508 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3512 fprintf(stderr, _("%s: %s...using built-in\n"),
3514 } else if (w != wreq || h != hreq) {
3516 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3517 programName, fullname, w, h, wreq, hreq);
3523 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3532 if (lineGap == 0) return;
3534 /* [HR] Split this into 2 loops for non-square boards. */
3536 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3537 gridSegments[i].x1 = 0;
3538 gridSegments[i].x2 =
3539 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3540 gridSegments[i].y1 = gridSegments[i].y2
3541 = lineGap / 2 + (i * (squareSize + lineGap));
3544 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3545 gridSegments[j + i].y1 = 0;
3546 gridSegments[j + i].y2 =
3547 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3548 gridSegments[j + i].x1 = gridSegments[j + i].x2
3549 = lineGap / 2 + (j * (squareSize + lineGap));
3553 static void MenuBarSelect(w, addr, index)
3558 XtActionProc proc = (XtActionProc) addr;
3560 (proc)(NULL, NULL, NULL, NULL);
3563 void CreateMenuBarPopup(parent, name, mb)
3573 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3576 XtSetArg(args[j], XtNleftMargin, 20); j++;
3577 XtSetArg(args[j], XtNrightMargin, 20); j++;
3579 while (mi->string != NULL) {
3580 if (strcmp(mi->string, "----") == 0) {
3581 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3584 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3585 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3587 XtAddCallback(entry, XtNcallback,
3588 (XtCallbackProc) MenuBarSelect,
3589 (caddr_t) mi->proc);
3595 Widget CreateMenuBar(mb)
3599 Widget anchor, menuBar;
3601 char menuName[MSG_SIZ];
3604 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3605 XtSetArg(args[j], XtNvSpace, 0); j++;
3606 XtSetArg(args[j], XtNborderWidth, 0); j++;
3607 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3608 formWidget, args, j);
3610 while (mb->name != NULL) {
3611 strcpy(menuName, "menu");
3612 strcat(menuName, mb->name);
3614 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3617 shortName[0] = _(mb->name)[0];
3618 shortName[1] = NULLCHAR;
3619 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3622 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3625 XtSetArg(args[j], XtNborderWidth, 0); j++;
3626 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3628 CreateMenuBarPopup(menuBar, menuName, mb);
3634 Widget CreateButtonBar(mi)
3638 Widget button, buttonBar;
3642 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3644 XtSetArg(args[j], XtNhSpace, 0); j++;
3646 XtSetArg(args[j], XtNborderWidth, 0); j++;
3647 XtSetArg(args[j], XtNvSpace, 0); j++;
3648 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3649 formWidget, args, j);
3651 while (mi->string != NULL) {
3654 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3655 XtSetArg(args[j], XtNborderWidth, 0); j++;
3657 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3658 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3659 buttonBar, args, j);
3660 XtAddCallback(button, XtNcallback,
3661 (XtCallbackProc) MenuBarSelect,
3662 (caddr_t) mi->proc);
3669 CreatePieceMenu(name, color)
3676 ChessSquare selection;
3678 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3679 boardWidget, args, 0);
3681 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3682 String item = pieceMenuStrings[color][i];
3684 if (strcmp(item, "----") == 0) {
3685 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3688 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3689 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3691 selection = pieceMenuTranslation[color][i];
3692 XtAddCallback(entry, XtNcallback,
3693 (XtCallbackProc) PieceMenuSelect,
3694 (caddr_t) selection);
3695 if (selection == WhitePawn || selection == BlackPawn) {
3696 XtSetArg(args[0], XtNpopupOnEntry, entry);
3697 XtSetValues(menu, args, 1);
3710 ChessSquare selection;
3712 whitePieceMenu = CreatePieceMenu("menuW", 0);
3713 blackPieceMenu = CreatePieceMenu("menuB", 1);
3715 XtRegisterGrabAction(PieceMenuPopup, True,
3716 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3717 GrabModeAsync, GrabModeAsync);
3719 XtSetArg(args[0], XtNlabel, _("Drop"));
3720 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3721 boardWidget, args, 1);
3722 for (i = 0; i < DROP_MENU_SIZE; i++) {
3723 String item = dropMenuStrings[i];
3725 if (strcmp(item, "----") == 0) {
3726 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3729 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3730 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3732 selection = dropMenuTranslation[i];
3733 XtAddCallback(entry, XtNcallback,
3734 (XtCallbackProc) DropMenuSelect,
3735 (caddr_t) selection);
3740 void SetupDropMenu()
3748 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3749 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3750 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3751 dmEnables[i].piece);
3752 XtSetSensitive(entry, p != NULL || !appData.testLegality
3753 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3754 && !appData.icsActive));
3756 while (p && *p++ == dmEnables[i].piece) count++;
3757 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3759 XtSetArg(args[j], XtNlabel, label); j++;
3760 XtSetValues(entry, args, j);
3764 void PieceMenuPopup(w, event, params, num_params)
3768 Cardinal *num_params;
3770 String whichMenu; int menuNr;
3771 if (event->type == ButtonRelease)
3772 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3773 else if (event->type == ButtonPress)
3774 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3776 case 0: whichMenu = params[0]; break;
3777 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3779 case -1: if (errorUp) ErrorPopDown();
3782 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3785 static void PieceMenuSelect(w, piece, junk)
3790 if (pmFromX < 0 || pmFromY < 0) return;
3791 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3794 static void DropMenuSelect(w, piece, junk)
3799 if (pmFromX < 0 || pmFromY < 0) return;
3800 DropMenuEvent(piece, pmFromX, pmFromY);
3803 void WhiteClock(w, event, prms, nprms)
3809 if (gameMode == EditPosition || gameMode == IcsExamining) {
3810 SetWhiteToPlayEvent();
3811 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3816 void BlackClock(w, event, prms, nprms)
3822 if (gameMode == EditPosition || gameMode == IcsExamining) {
3823 SetBlackToPlayEvent();
3824 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3831 * If the user selects on a border boundary, return -1; if off the board,
3832 * return -2. Otherwise map the event coordinate to the square.
3834 int EventToSquare(x, limit)
3842 if ((x % (squareSize + lineGap)) >= squareSize)
3844 x /= (squareSize + lineGap);
3850 static void do_flash_delay(msec)
3856 static void drawHighlight(file, rank, gc)
3862 if (lineGap == 0 || appData.blindfold) return;
3865 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3866 (squareSize + lineGap);
3867 y = lineGap/2 + rank * (squareSize + lineGap);
3869 x = lineGap/2 + file * (squareSize + lineGap);
3870 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3871 (squareSize + lineGap);
3874 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3875 squareSize+lineGap, squareSize+lineGap);
3878 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3879 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3882 SetHighlights(fromX, fromY, toX, toY)
3883 int fromX, fromY, toX, toY;
3885 if (hi1X != fromX || hi1Y != fromY) {
3886 if (hi1X >= 0 && hi1Y >= 0) {
3887 drawHighlight(hi1X, hi1Y, lineGC);
3889 } // [HGM] first erase both, then draw new!
3890 if (hi2X != toX || hi2Y != toY) {
3891 if (hi2X >= 0 && hi2Y >= 0) {
3892 drawHighlight(hi2X, hi2Y, lineGC);
3895 if (hi1X != fromX || hi1Y != fromY) {
3896 if (fromX >= 0 && fromY >= 0) {
3897 drawHighlight(fromX, fromY, highlineGC);
3900 if (hi2X != toX || hi2Y != toY) {
3901 if (toX >= 0 && toY >= 0) {
3902 drawHighlight(toX, toY, highlineGC);
3914 SetHighlights(-1, -1, -1, -1);
3919 SetPremoveHighlights(fromX, fromY, toX, toY)
3920 int fromX, fromY, toX, toY;
3922 if (pm1X != fromX || pm1Y != fromY) {
3923 if (pm1X >= 0 && pm1Y >= 0) {
3924 drawHighlight(pm1X, pm1Y, lineGC);
3926 if (fromX >= 0 && fromY >= 0) {
3927 drawHighlight(fromX, fromY, prelineGC);
3930 if (pm2X != toX || pm2Y != toY) {
3931 if (pm2X >= 0 && pm2Y >= 0) {
3932 drawHighlight(pm2X, pm2Y, lineGC);
3934 if (toX >= 0 && toY >= 0) {
3935 drawHighlight(toX, toY, prelineGC);
3945 ClearPremoveHighlights()
3947 SetPremoveHighlights(-1, -1, -1, -1);
3950 static void BlankSquare(x, y, color, piece, dest)
3955 if (useImages && useImageSqs) {
3959 pm = xpmLightSquare;
3964 case 2: /* neutral */
3969 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3970 squareSize, squareSize, x, y);
3980 case 2: /* neutral */
3985 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3990 I split out the routines to draw a piece so that I could
3991 make a generic flash routine.
3993 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3995 int square_color, x, y;
3998 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3999 switch (square_color) {
4001 case 2: /* neutral */
4003 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4004 ? *pieceToOutline(piece)
4005 : *pieceToSolid(piece),
4006 dest, bwPieceGC, 0, 0,
4007 squareSize, squareSize, x, y);
4010 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4011 ? *pieceToSolid(piece)
4012 : *pieceToOutline(piece),
4013 dest, wbPieceGC, 0, 0,
4014 squareSize, squareSize, x, y);
4019 static void monoDrawPiece(piece, square_color, x, y, dest)
4021 int square_color, x, y;
4024 switch (square_color) {
4026 case 2: /* neutral */
4028 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4029 ? *pieceToOutline(piece)
4030 : *pieceToSolid(piece),
4031 dest, bwPieceGC, 0, 0,
4032 squareSize, squareSize, x, y, 1);
4035 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4036 ? *pieceToSolid(piece)
4037 : *pieceToOutline(piece),
4038 dest, wbPieceGC, 0, 0,
4039 squareSize, squareSize, x, y, 1);
4044 static void colorDrawPiece(piece, square_color, x, y, dest)
4046 int square_color, x, y;
4049 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4050 switch (square_color) {
4052 XCopyPlane(xDisplay, *pieceToSolid(piece),
4053 dest, (int) piece < (int) BlackPawn
4054 ? wlPieceGC : blPieceGC, 0, 0,
4055 squareSize, squareSize, x, y, 1);
4058 XCopyPlane(xDisplay, *pieceToSolid(piece),
4059 dest, (int) piece < (int) BlackPawn
4060 ? wdPieceGC : bdPieceGC, 0, 0,
4061 squareSize, squareSize, x, y, 1);
4063 case 2: /* neutral */
4065 XCopyPlane(xDisplay, *pieceToSolid(piece),
4066 dest, (int) piece < (int) BlackPawn
4067 ? wjPieceGC : bjPieceGC, 0, 0,
4068 squareSize, squareSize, x, y, 1);
4073 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4075 int square_color, x, y;
4080 switch (square_color) {
4082 case 2: /* neutral */
4084 if ((int)piece < (int) BlackPawn) {
4092 if ((int)piece < (int) BlackPawn) {
4100 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4101 dest, wlPieceGC, 0, 0,
4102 squareSize, squareSize, x, y);
4105 typedef void (*DrawFunc)();
4107 DrawFunc ChooseDrawFunc()
4109 if (appData.monoMode) {
4110 if (DefaultDepth(xDisplay, xScreen) == 1) {
4111 return monoDrawPiece_1bit;
4113 return monoDrawPiece;
4117 return colorDrawPieceImage;
4119 return colorDrawPiece;
4123 /* [HR] determine square color depending on chess variant. */
4124 static int SquareColor(row, column)
4129 if (gameInfo.variant == VariantXiangqi) {
4130 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4132 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4134 } else if (row <= 4) {
4140 square_color = ((column + row) % 2) == 1;
4143 /* [hgm] holdings: next line makes all holdings squares light */
4144 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4146 return square_color;
4149 void DrawSquare(row, column, piece, do_flash)
4150 int row, column, do_flash;
4153 int square_color, x, y, direction, font_ascent, font_descent;
4156 XCharStruct overall;
4160 /* Calculate delay in milliseconds (2-delays per complete flash) */
4161 flash_delay = 500 / appData.flashRate;
4164 x = lineGap + ((BOARD_WIDTH-1)-column) *
4165 (squareSize + lineGap);
4166 y = lineGap + row * (squareSize + lineGap);
4168 x = lineGap + column * (squareSize + lineGap);
4169 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4170 (squareSize + lineGap);
4173 square_color = SquareColor(row, column);
4175 if ( // [HGM] holdings: blank out area between board and holdings
4176 column == BOARD_LEFT-1 || column == BOARD_RGHT
4177 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4178 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4179 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4181 // [HGM] print piece counts next to holdings
4182 string[1] = NULLCHAR;
4183 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4184 string[0] = '0' + piece;
4185 XTextExtents(countFontStruct, string, 1, &direction,
4186 &font_ascent, &font_descent, &overall);
4187 if (appData.monoMode) {
4188 XDrawImageString(xDisplay, xBoardWindow, countGC,
4189 x + squareSize - overall.width - 2,
4190 y + font_ascent + 1, string, 1);
4192 XDrawString(xDisplay, xBoardWindow, countGC,
4193 x + squareSize - overall.width - 2,
4194 y + font_ascent + 1, string, 1);
4197 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4198 string[0] = '0' + piece;
4199 XTextExtents(countFontStruct, string, 1, &direction,
4200 &font_ascent, &font_descent, &overall);
4201 if (appData.monoMode) {
4202 XDrawImageString(xDisplay, xBoardWindow, countGC,
4203 x + 2, y + font_ascent + 1, string, 1);
4205 XDrawString(xDisplay, xBoardWindow, countGC,
4206 x + 2, y + font_ascent + 1, string, 1);
4210 if (piece == EmptySquare || appData.blindfold) {
4211 BlankSquare(x, y, square_color, piece, xBoardWindow);
4213 drawfunc = ChooseDrawFunc();
4214 if (do_flash && appData.flashCount > 0) {
4215 for (i=0; i<appData.flashCount; ++i) {
4217 drawfunc(piece, square_color, x, y, xBoardWindow);
4218 XSync(xDisplay, False);
4219 do_flash_delay(flash_delay);
4221 BlankSquare(x, y, square_color, piece, xBoardWindow);
4222 XSync(xDisplay, False);
4223 do_flash_delay(flash_delay);
4226 drawfunc(piece, square_color, x, y, xBoardWindow);
4230 string[1] = NULLCHAR;
4231 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4232 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4233 string[0] = 'a' + column - BOARD_LEFT;
4234 XTextExtents(coordFontStruct, string, 1, &direction,
4235 &font_ascent, &font_descent, &overall);
4236 if (appData.monoMode) {
4237 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4238 x + squareSize - overall.width - 2,
4239 y + squareSize - font_descent - 1, string, 1);
4241 XDrawString(xDisplay, xBoardWindow, coordGC,
4242 x + squareSize - overall.width - 2,
4243 y + squareSize - font_descent - 1, string, 1);
4246 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4247 string[0] = ONE + row;
4248 XTextExtents(coordFontStruct, string, 1, &direction,
4249 &font_ascent, &font_descent, &overall);
4250 if (appData.monoMode) {
4251 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4252 x + 2, y + font_ascent + 1, string, 1);
4254 XDrawString(xDisplay, xBoardWindow, coordGC,
4255 x + 2, y + font_ascent + 1, string, 1);
4258 if(marker[row][column]) {
4259 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4260 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4265 /* Why is this needed on some versions of X? */
4266 void EventProc(widget, unused, event)
4271 if (!XtIsRealized(widget))
4274 switch (event->type) {
4276 if (event->xexpose.count > 0) return; /* no clipping is done */
4277 XDrawPosition(widget, True, NULL);
4280 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4287 void DrawPosition(fullRedraw, board)
4288 /*Boolean*/int fullRedraw;
4291 XDrawPosition(boardWidget, fullRedraw, board);
4294 /* Returns 1 if there are "too many" differences between b1 and b2
4295 (i.e. more than 1 move was made) */
4296 static int too_many_diffs(b1, b2)
4302 for (i=0; i<BOARD_HEIGHT; ++i) {
4303 for (j=0; j<BOARD_WIDTH; ++j) {
4304 if (b1[i][j] != b2[i][j]) {
4305 if (++c > 4) /* Castling causes 4 diffs */
4314 /* Matrix describing castling maneuvers */
4315 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4316 static int castling_matrix[4][5] = {
4317 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4318 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4319 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4320 { 7, 7, 4, 5, 6 } /* 0-0, black */
4323 /* Checks whether castling occurred. If it did, *rrow and *rcol
4324 are set to the destination (row,col) of the rook that moved.
4326 Returns 1 if castling occurred, 0 if not.
4328 Note: Only handles a max of 1 castling move, so be sure
4329 to call too_many_diffs() first.
4331 static int check_castle_draw(newb, oldb, rrow, rcol)
4338 /* For each type of castling... */
4339 for (i=0; i<4; ++i) {
4340 r = castling_matrix[i];
4342 /* Check the 4 squares involved in the castling move */
4344 for (j=1; j<=4; ++j) {
4345 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4352 /* All 4 changed, so it must be a castling move */
4361 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4362 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4364 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4367 void DrawSeekBackground( int left, int top, int right, int bottom )
4369 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4372 void DrawSeekText(char *buf, int x, int y)
4374 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4377 void DrawSeekDot(int x, int y, int colorNr)
4379 int square = colorNr & 0x80;
4382 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4384 XFillRectangle(xDisplay, xBoardWindow, color,
4385 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4387 XFillArc(xDisplay, xBoardWindow, color,
4388 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4391 static int damage[BOARD_RANKS][BOARD_FILES];
4394 * event handler for redrawing the board
4396 void XDrawPosition(w, repaint, board)
4398 /*Boolean*/int repaint;
4402 static int lastFlipView = 0;
4403 static int lastBoardValid = 0;
4404 static Board lastBoard;
4408 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4410 if (board == NULL) {
4411 if (!lastBoardValid) return;
4414 if (!lastBoardValid || lastFlipView != flipView) {
4415 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4421 * It would be simpler to clear the window with XClearWindow()
4422 * but this causes a very distracting flicker.
4425 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4427 /* If too much changes (begin observing new game, etc.), don't
4429 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4431 /* Special check for castling so we don't flash both the king
4432 and the rook (just flash the king). */
4434 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4435 /* Draw rook with NO flashing. King will be drawn flashing later */
4436 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4437 lastBoard[rrow][rcol] = board[rrow][rcol];
4441 /* First pass -- Draw (newly) empty squares and repair damage.
4442 This prevents you from having a piece show up twice while it
4443 is flashing on its new square */
4444 for (i = 0; i < BOARD_HEIGHT; i++)
4445 for (j = 0; j < BOARD_WIDTH; j++)
4446 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4448 DrawSquare(i, j, board[i][j], 0);
4449 damage[i][j] = False;
4452 /* Second pass -- Draw piece(s) in new position and flash them */
4453 for (i = 0; i < BOARD_HEIGHT; i++)
4454 for (j = 0; j < BOARD_WIDTH; j++)
4455 if (board[i][j] != lastBoard[i][j]) {
4456 DrawSquare(i, j, board[i][j], do_flash);
4460 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4461 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4463 for (i = 0; i < BOARD_HEIGHT; i++)
4464 for (j = 0; j < BOARD_WIDTH; j++) {
4465 DrawSquare(i, j, board[i][j], 0);
4466 damage[i][j] = False;
4470 CopyBoard(lastBoard, board);
4472 lastFlipView = flipView;
4474 /* Draw highlights */
4475 if (pm1X >= 0 && pm1Y >= 0) {
4476 drawHighlight(pm1X, pm1Y, prelineGC);
4478 if (pm2X >= 0 && pm2Y >= 0) {
4479 drawHighlight(pm2X, pm2Y, prelineGC);
4481 if (hi1X >= 0 && hi1Y >= 0) {
4482 drawHighlight(hi1X, hi1Y, highlineGC);
4484 if (hi2X >= 0 && hi2Y >= 0) {
4485 drawHighlight(hi2X, hi2Y, highlineGC);
4488 /* If piece being dragged around board, must redraw that too */
4491 XSync(xDisplay, False);
4496 * event handler for redrawing the board
4498 void DrawPositionProc(w, event, prms, nprms)
4504 XDrawPosition(w, True, NULL);
4509 * event handler for parsing user moves
4511 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4512 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4513 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4514 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4515 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4516 // and at the end FinishMove() to perform the move after optional promotion popups.
4517 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4518 void HandleUserMove(w, event, prms, nprms)
4524 if (w != boardWidget || errorExitStatus != -1) return;
4527 if (event->type == ButtonPress) {
4528 XtPopdown(promotionShell);
4529 XtDestroyWidget(promotionShell);
4530 promotionUp = False;
4538 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4539 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4540 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4543 void AnimateUserMove (Widget w, XEvent * event,
4544 String * params, Cardinal * nParams)
4546 DragPieceMove(event->xmotion.x, event->xmotion.y);
4549 void HandlePV (Widget w, XEvent * event,
4550 String * params, Cardinal * nParams)
4551 { // [HGM] pv: walk PV
4552 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4555 Widget CommentCreate(name, text, mutable, callback, lines)
4557 int /*Boolean*/ mutable;
4558 XtCallbackProc callback;
4562 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4567 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4568 XtGetValues(boardWidget, args, j);
4571 XtSetArg(args[j], XtNresizable, True); j++;
4574 XtCreatePopupShell(name, topLevelShellWidgetClass,
4575 shellWidget, args, j);
4578 XtCreatePopupShell(name, transientShellWidgetClass,
4579 shellWidget, args, j);
4582 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4583 layoutArgs, XtNumber(layoutArgs));
4585 XtCreateManagedWidget("form", formWidgetClass, layout,
4586 formArgs, XtNumber(formArgs));
4590 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4591 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4593 XtSetArg(args[j], XtNstring, text); j++;
4594 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4595 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4596 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4597 XtSetArg(args[j], XtNright, XtChainRight); j++;
4598 XtSetArg(args[j], XtNresizable, True); j++;
4599 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4600 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4601 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4602 XtSetArg(args[j], XtNautoFill, True); j++;
4603 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4605 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4609 XtSetArg(args[j], XtNfromVert, edit); j++;
4610 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4611 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4612 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4613 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4615 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4616 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4619 XtSetArg(args[j], XtNfromVert, edit); j++;
4620 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4621 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4622 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4623 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4624 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4626 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4627 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4630 XtSetArg(args[j], XtNfromVert, edit); j++;
4631 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4632 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4633 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4634 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4635 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4637 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4638 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4641 XtSetArg(args[j], XtNfromVert, edit); j++;
4642 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4643 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4644 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4645 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4647 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4648 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4651 XtSetArg(args[j], XtNfromVert, edit); j++;
4652 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4653 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4654 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4655 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4656 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4658 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4659 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4662 XtRealizeWidget(shell);
4664 if (commentX == -1) {
4667 Dimension pw_height;
4668 Dimension ew_height;
4671 XtSetArg(args[j], XtNheight, &ew_height); j++;
4672 XtGetValues(edit, args, j);
4675 XtSetArg(args[j], XtNheight, &pw_height); j++;
4676 XtGetValues(shell, args, j);
4677 commentH = pw_height + (lines - 1) * ew_height;
4678 commentW = bw_width - 16;
4680 XSync(xDisplay, False);
4682 /* This code seems to tickle an X bug if it is executed too soon
4683 after xboard starts up. The coordinates get transformed as if
4684 the main window was positioned at (0, 0).
4686 XtTranslateCoords(shellWidget,
4687 (bw_width - commentW) / 2, 0 - commentH / 2,
4688 &commentX, &commentY);
4690 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4691 RootWindowOfScreen(XtScreen(shellWidget)),
4692 (bw_width - commentW) / 2, 0 - commentH / 2,
4697 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4700 if(wpComment.width > 0) {
4701 commentX = wpComment.x;
4702 commentY = wpComment.y;
4703 commentW = wpComment.width;
4704 commentH = wpComment.height;
4708 XtSetArg(args[j], XtNheight, commentH); j++;
4709 XtSetArg(args[j], XtNwidth, commentW); j++;
4710 XtSetArg(args[j], XtNx, commentX); j++;
4711 XtSetArg(args[j], XtNy, commentY); j++;
4712 XtSetValues(shell, args, j);
4713 XtSetKeyboardFocus(shell, edit);
4718 /* Used for analysis window and ICS input window */
4719 Widget MiscCreate(name, text, mutable, callback, lines)
4721 int /*Boolean*/ mutable;
4722 XtCallbackProc callback;
4726 Widget shell, layout, form, edit;
4728 Dimension bw_width, pw_height, ew_height, w, h;
4734 XtSetArg(args[j], XtNresizable, True); j++;
4737 XtCreatePopupShell(name, topLevelShellWidgetClass,
4738 shellWidget, args, j);
4741 XtCreatePopupShell(name, transientShellWidgetClass,
4742 shellWidget, args, j);
4745 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4746 layoutArgs, XtNumber(layoutArgs));
4748 XtCreateManagedWidget("form", formWidgetClass, layout,
4749 formArgs, XtNumber(formArgs));
4753 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4754 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4756 XtSetArg(args[j], XtNstring, text); j++;
4757 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4758 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4759 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4760 XtSetArg(args[j], XtNright, XtChainRight); j++;
4761 XtSetArg(args[j], XtNresizable, True); j++;
4762 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4763 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4764 XtSetArg(args[j], XtNautoFill, True); j++;
4765 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4767 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4769 XtRealizeWidget(shell);
4772 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4773 XtGetValues(boardWidget, args, j);
4776 XtSetArg(args[j], XtNheight, &ew_height); j++;
4777 XtGetValues(edit, args, j);
4780 XtSetArg(args[j], XtNheight, &pw_height); j++;
4781 XtGetValues(shell, args, j);
4782 h = pw_height + (lines - 1) * ew_height;
4785 XSync(xDisplay, False);
4787 /* This code seems to tickle an X bug if it is executed too soon
4788 after xboard starts up. The coordinates get transformed as if
4789 the main window was positioned at (0, 0).
4791 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4793 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4794 RootWindowOfScreen(XtScreen(shellWidget)),
4795 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4799 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4802 XtSetArg(args[j], XtNheight, h); j++;
4803 XtSetArg(args[j], XtNwidth, w); j++;
4804 XtSetArg(args[j], XtNx, x); j++;
4805 XtSetArg(args[j], XtNy, y); j++;
4806 XtSetValues(shell, args, j);
4812 static int savedIndex; /* gross that this is global */
4814 void EditCommentPopUp(index, title, text)
4823 if (text == NULL) text = "";
4825 if (editShell == NULL) {
4827 CommentCreate(title, text, True, EditCommentCallback, 4);
4828 XtRealizeWidget(editShell);
4829 CatchDeleteWindow(editShell, "EditCommentPopDown");
4831 edit = XtNameToWidget(editShell, "*form.text");
4833 XtSetArg(args[j], XtNstring, text); j++;
4834 XtSetValues(edit, args, j);
4836 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4837 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4838 XtSetValues(editShell, args, j);
4841 XtPopup(editShell, XtGrabNone);
4845 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4846 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4850 void EditCommentCallback(w, client_data, call_data)
4852 XtPointer client_data, call_data;
4860 XtSetArg(args[j], XtNlabel, &name); j++;
4861 XtGetValues(w, args, j);
4863 if (strcmp(name, _("ok")) == 0) {
4864 edit = XtNameToWidget(editShell, "*form.text");
4866 XtSetArg(args[j], XtNstring, &val); j++;
4867 XtGetValues(edit, args, j);
4868 ReplaceComment(savedIndex, val);
4869 EditCommentPopDown();
4870 } else if (strcmp(name, _("cancel")) == 0) {
4871 EditCommentPopDown();
4872 } else if (strcmp(name, _("clear")) == 0) {
4873 edit = XtNameToWidget(editShell, "*form.text");
4874 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4875 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4879 void EditCommentPopDown()
4884 if (!editUp) return;
4886 XtSetArg(args[j], XtNx, &commentX); j++;
4887 XtSetArg(args[j], XtNy, &commentY); j++;
4888 XtSetArg(args[j], XtNheight, &commentH); j++;
4889 XtSetArg(args[j], XtNwidth, &commentW); j++;
4890 XtGetValues(editShell, args, j);
4891 XtPopdown(editShell);
4894 XtSetArg(args[j], XtNleftBitmap, None); j++;
4895 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4899 void ICSInputBoxPopUp()
4904 char *title = _("ICS Input");
4907 if (ICSInputShell == NULL) {
4908 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4909 tr = XtParseTranslationTable(ICSInputTranslations);
4910 edit = XtNameToWidget(ICSInputShell, "*form.text");
4911 XtOverrideTranslations(edit, tr);
4912 XtRealizeWidget(ICSInputShell);
4913 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4916 edit = XtNameToWidget(ICSInputShell, "*form.text");
4918 XtSetArg(args[j], XtNstring, ""); j++;
4919 XtSetValues(edit, args, j);
4921 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4922 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4923 XtSetValues(ICSInputShell, args, j);
4926 XtPopup(ICSInputShell, XtGrabNone);
4927 XtSetKeyboardFocus(ICSInputShell, edit);
4929 ICSInputBoxUp = True;
4931 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4932 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4936 void ICSInputSendText()
4943 edit = XtNameToWidget(ICSInputShell, "*form.text");
4945 XtSetArg(args[j], XtNstring, &val); j++;
4946 XtGetValues(edit, args, j);
4948 SendMultiLineToICS(val);
4949 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4950 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4953 void ICSInputBoxPopDown()
4958 if (!ICSInputBoxUp) return;
4960 XtPopdown(ICSInputShell);
4961 ICSInputBoxUp = False;
4963 XtSetArg(args[j], XtNleftBitmap, None); j++;
4964 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4968 void CommentPopUp(title, text)
4975 if (commentShell == NULL) {
4977 CommentCreate(title, text, False, CommentCallback, 4);
4978 XtRealizeWidget(commentShell);
4979 CatchDeleteWindow(commentShell, "CommentPopDown");
4981 edit = XtNameToWidget(commentShell, "*form.text");
4983 XtSetArg(args[j], XtNstring, text); j++;
4984 XtSetValues(edit, args, j);
4986 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4987 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4988 XtSetValues(commentShell, args, j);
4991 XtPopup(commentShell, XtGrabNone);
4992 XSync(xDisplay, False);
4997 void CommentCallback(w, client_data, call_data)
4999 XtPointer client_data, call_data;
5006 XtSetArg(args[j], XtNlabel, &name); j++;
5007 XtGetValues(w, args, j);
5009 if (strcmp(name, _("close")) == 0) {
5011 } else if (strcmp(name, _("edit")) == 0) {
5018 void CommentPopDown()
5023 if (!commentUp) return;
5025 XtSetArg(args[j], XtNx, &commentX); j++;
5026 XtSetArg(args[j], XtNy, &commentY); j++;
5027 XtSetArg(args[j], XtNwidth, &commentW); j++;
5028 XtSetArg(args[j], XtNheight, &commentH); j++;
5029 XtGetValues(commentShell, args, j);
5030 XtPopdown(commentShell);
5031 XSync(xDisplay, False);
5035 void FileNamePopUp(label, def, proc, openMode)
5042 Widget popup, layout, dialog, edit;
5048 fileProc = proc; /* I can't see a way not */
5049 fileOpenMode = openMode; /* to use globals here */
5050 { // [HGM] use file-selector dialog stolen from Ghostview
5052 int index; // this is not supported yet
5054 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5055 NULL, openMode, NULL, &name))
5056 (void) (*fileProc)(f, index=0, name);
5060 void FileNamePopDown()
5062 if (!filenameUp) return;
5063 XtPopdown(fileNameShell);
5064 XtDestroyWidget(fileNameShell);
5069 void FileNameCallback(w, client_data, call_data)
5071 XtPointer client_data, call_data;
5076 XtSetArg(args[0], XtNlabel, &name);
5077 XtGetValues(w, args, 1);
5079 if (strcmp(name, _("cancel")) == 0) {
5084 FileNameAction(w, NULL, NULL, NULL);
5087 void FileNameAction(w, event, prms, nprms)
5099 name = XawDialogGetValueString(w = XtParent(w));
5101 if ((name != NULL) && (*name != NULLCHAR)) {
5103 XtPopdown(w = XtParent(XtParent(w)));
5107 p = strrchr(buf, ' ');
5114 fullname = ExpandPathName(buf);
5116 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5119 f = fopen(fullname, fileOpenMode);
5121 DisplayError(_("Failed to open file"), errno);
5123 (void) (*fileProc)(f, index, buf);
5130 XtPopdown(w = XtParent(XtParent(w)));
5136 void PromotionPopUp()
5139 Widget dialog, layout;
5141 Dimension bw_width, pw_width;
5145 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5146 XtGetValues(boardWidget, args, j);
5149 XtSetArg(args[j], XtNresizable, True); j++;
5150 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5152 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5153 shellWidget, args, j);
5155 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5156 layoutArgs, XtNumber(layoutArgs));
5159 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5160 XtSetArg(args[j], XtNborderWidth, 0); j++;
5161 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5164 if(gameInfo.variant != VariantShogi) {
5165 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5166 (XtPointer) dialog);
5167 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5168 (XtPointer) dialog);
5169 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5170 (XtPointer) dialog);
5171 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5172 (XtPointer) dialog);
5173 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5174 gameInfo.variant == VariantGiveaway) {
5175 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5176 (XtPointer) dialog);
5178 if(gameInfo.variant == VariantCapablanca ||
5179 gameInfo.variant == VariantGothic ||
5180 gameInfo.variant == VariantCapaRandom) {
5181 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5182 (XtPointer) dialog);
5183 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5184 (XtPointer) dialog);
5186 } else // [HGM] shogi
5188 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5189 (XtPointer) dialog);
5190 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5191 (XtPointer) dialog);
5193 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5194 (XtPointer) dialog);
5196 XtRealizeWidget(promotionShell);
5197 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5200 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5201 XtGetValues(promotionShell, args, j);
5203 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5204 lineGap + squareSize/3 +
5205 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5206 0 : 6*(squareSize + lineGap)), &x, &y);
5209 XtSetArg(args[j], XtNx, x); j++;
5210 XtSetArg(args[j], XtNy, y); j++;
5211 XtSetValues(promotionShell, args, j);
5213 XtPopup(promotionShell, XtGrabNone);
5218 void PromotionPopDown()
5220 if (!promotionUp) return;
5221 XtPopdown(promotionShell);
5222 XtDestroyWidget(promotionShell);
5223 promotionUp = False;
5226 void PromotionCallback(w, client_data, call_data)
5228 XtPointer client_data, call_data;
5234 XtSetArg(args[0], XtNlabel, &name);
5235 XtGetValues(w, args, 1);
5239 if (fromX == -1) return;
5241 if (strcmp(name, _("cancel")) == 0) {
5245 } else if (strcmp(name, _("Knight")) == 0) {
5247 } else if (strcmp(name, _("Promote")) == 0) {
5249 } else if (strcmp(name, _("Defer")) == 0) {
5252 promoChar = ToLower(name[0]);
5255 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5257 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5258 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5263 void ErrorCallback(w, client_data, call_data)
5265 XtPointer client_data, call_data;
5268 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5270 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5276 if (!errorUp) return;
5278 XtPopdown(errorShell);
5279 XtDestroyWidget(errorShell);
5280 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5283 void ErrorPopUp(title, label, modal)
5284 char *title, *label;
5288 Widget dialog, layout;
5292 Dimension bw_width, pw_width;
5293 Dimension pw_height;
5297 XtSetArg(args[i], XtNresizable, True); i++;
5298 XtSetArg(args[i], XtNtitle, title); i++;
5300 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5301 shellWidget, args, i);
5303 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5304 layoutArgs, XtNumber(layoutArgs));
5307 XtSetArg(args[i], XtNlabel, label); i++;
5308 XtSetArg(args[i], XtNborderWidth, 0); i++;
5309 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5312 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5314 XtRealizeWidget(errorShell);
5315 CatchDeleteWindow(errorShell, "ErrorPopDown");
5318 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5319 XtGetValues(boardWidget, args, i);
5321 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5322 XtSetArg(args[i], XtNheight, &pw_height); i++;
5323 XtGetValues(errorShell, args, i);
5326 /* This code seems to tickle an X bug if it is executed too soon
5327 after xboard starts up. The coordinates get transformed as if
5328 the main window was positioned at (0, 0).
5330 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5331 0 - pw_height + squareSize / 3, &x, &y);
5333 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5334 RootWindowOfScreen(XtScreen(boardWidget)),
5335 (bw_width - pw_width) / 2,
5336 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5340 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5343 XtSetArg(args[i], XtNx, x); i++;
5344 XtSetArg(args[i], XtNy, y); i++;
5345 XtSetValues(errorShell, args, i);
5348 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5351 /* Disable all user input other than deleting the window */
5352 static int frozen = 0;
5356 /* Grab by a widget that doesn't accept input */
5357 XtAddGrab(messageWidget, TRUE, FALSE);
5361 /* Undo a FreezeUI */
5364 if (!frozen) return;
5365 XtRemoveGrab(messageWidget);
5369 char *ModeToWidgetName(mode)
5373 case BeginningOfGame:
5374 if (appData.icsActive)
5375 return "menuMode.ICS Client";
5376 else if (appData.noChessProgram ||
5377 *appData.cmailGameName != NULLCHAR)
5378 return "menuMode.Edit Game";
5380 return "menuMode.Machine Black";
5381 case MachinePlaysBlack:
5382 return "menuMode.Machine Black";
5383 case MachinePlaysWhite:
5384 return "menuMode.Machine White";
5386 return "menuMode.Analysis Mode";
5388 return "menuMode.Analyze File";
5389 case TwoMachinesPlay:
5390 return "menuMode.Two Machines";
5392 return "menuMode.Edit Game";
5393 case PlayFromGameFile:
5394 return "menuFile.Load Game";
5396 return "menuMode.Edit Position";
5398 return "menuMode.Training";
5399 case IcsPlayingWhite:
5400 case IcsPlayingBlack:
5404 return "menuMode.ICS Client";
5411 void ModeHighlight()
5414 static int oldPausing = FALSE;
5415 static GameMode oldmode = (GameMode) -1;
5418 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5420 if (pausing != oldPausing) {
5421 oldPausing = pausing;
5423 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5425 XtSetArg(args[0], XtNleftBitmap, None);
5427 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5430 if (appData.showButtonBar) {
5431 /* Always toggle, don't set. Previous code messes up when
5432 invoked while the button is pressed, as releasing it
5433 toggles the state again. */
5436 XtSetArg(args[0], XtNbackground, &oldbg);
5437 XtSetArg(args[1], XtNforeground, &oldfg);
5438 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5440 XtSetArg(args[0], XtNbackground, oldfg);
5441 XtSetArg(args[1], XtNforeground, oldbg);
5443 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5447 wname = ModeToWidgetName(oldmode);
5448 if (wname != NULL) {
5449 XtSetArg(args[0], XtNleftBitmap, None);
5450 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5452 wname = ModeToWidgetName(gameMode);
5453 if (wname != NULL) {
5454 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5455 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5459 /* Maybe all the enables should be handled here, not just this one */
5460 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5461 gameMode == Training || gameMode == PlayFromGameFile);
5466 * Button/menu procedures
5468 void ResetProc(w, event, prms, nprms)
5477 int LoadGamePopUp(f, gameNumber, title)
5482 cmailMsgLoaded = FALSE;
5483 if (gameNumber == 0) {
5484 int error = GameListBuild(f);
5486 DisplayError(_("Cannot build game list"), error);
5487 } else if (!ListEmpty(&gameList) &&
5488 ((ListGame *) gameList.tailPred)->number > 1) {
5489 GameListPopUp(f, title);
5495 return LoadGame(f, gameNumber, title, FALSE);
5498 void LoadGameProc(w, event, prms, nprms)
5504 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5507 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5510 void LoadNextGameProc(w, event, prms, nprms)
5519 void LoadPrevGameProc(w, event, prms, nprms)
5528 void ReloadGameProc(w, event, prms, nprms)
5537 void LoadNextPositionProc(w, event, prms, nprms)
5546 void LoadPrevPositionProc(w, event, prms, nprms)
5555 void ReloadPositionProc(w, event, prms, nprms)
5564 void LoadPositionProc(w, event, prms, nprms)
5570 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5573 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5576 void SaveGameProc(w, event, prms, nprms)
5582 FileNamePopUp(_("Save game file name?"),
5583 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5587 void SavePositionProc(w, event, prms, nprms)
5593 FileNamePopUp(_("Save position file name?"),
5594 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5598 void ReloadCmailMsgProc(w, event, prms, nprms)
5604 ReloadCmailMsgEvent(FALSE);
5607 void MailMoveProc(w, event, prms, nprms)
5616 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5617 char *selected_fen_position=NULL;
5620 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5621 Atom *type_return, XtPointer *value_return,
5622 unsigned long *length_return, int *format_return)
5624 char *selection_tmp;
5626 if (!selected_fen_position) return False; /* should never happen */
5627 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5628 /* note: since no XtSelectionDoneProc was registered, Xt will
5629 * automatically call XtFree on the value returned. So have to
5630 * make a copy of it allocated with XtMalloc */
5631 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5632 strcpy(selection_tmp, selected_fen_position);
5634 *value_return=selection_tmp;
5635 *length_return=strlen(selection_tmp);
5636 *type_return=*target;
5637 *format_return = 8; /* bits per byte */
5639 } else if (*target == XA_TARGETS(xDisplay)) {
5640 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5641 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5642 targets_tmp[1] = XA_STRING;
5643 *value_return = targets_tmp;
5644 *type_return = XA_ATOM;
5646 *format_return = 8 * sizeof(Atom);
5647 if (*format_return > 32) {
5648 *length_return *= *format_return / 32;
5649 *format_return = 32;
5657 /* note: when called from menu all parameters are NULL, so no clue what the
5658 * Widget which was clicked on was, or what the click event was
5660 void CopyPositionProc(w, event, prms, nprms)
5667 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5668 * have a notion of a position that is selected but not copied.
5669 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5671 if(gameMode == EditPosition) EditPositionDone(TRUE);
5672 if (selected_fen_position) free(selected_fen_position);
5673 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5674 if (!selected_fen_position) return;
5675 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5677 SendPositionSelection,
5678 NULL/* lose_ownership_proc */ ,
5679 NULL/* transfer_done_proc */);
5680 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5682 SendPositionSelection,
5683 NULL/* lose_ownership_proc */ ,
5684 NULL/* transfer_done_proc */);
5687 /* function called when the data to Paste is ready */
5689 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5690 Atom *type, XtPointer value, unsigned long *len, int *format)
5693 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5694 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5695 EditPositionPasteFEN(fenstr);
5699 /* called when Paste Position button is pressed,
5700 * all parameters will be NULL */
5701 void PastePositionProc(w, event, prms, nprms)
5707 XtGetSelectionValue(menuBarWidget,
5708 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5709 /* (XtSelectionCallbackProc) */ PastePositionCB,
5710 NULL, /* client_data passed to PastePositionCB */
5712 /* better to use the time field from the event that triggered the
5713 * call to this function, but that isn't trivial to get
5721 SendGameSelection(Widget w, Atom *selection, Atom *target,
5722 Atom *type_return, XtPointer *value_return,
5723 unsigned long *length_return, int *format_return)
5725 char *selection_tmp;
5727 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5728 FILE* f = fopen(gameCopyFilename, "r");
5731 if (f == NULL) return False;
5735 selection_tmp = XtMalloc(len + 1);
5736 count = fread(selection_tmp, 1, len, f);
5738 XtFree(selection_tmp);
5741 selection_tmp[len] = NULLCHAR;
5742 *value_return = selection_tmp;
5743 *length_return = len;
5744 *type_return = *target;
5745 *format_return = 8; /* bits per byte */
5747 } else if (*target == XA_TARGETS(xDisplay)) {
5748 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5749 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5750 targets_tmp[1] = XA_STRING;
5751 *value_return = targets_tmp;
5752 *type_return = XA_ATOM;
5754 *format_return = 8 * sizeof(Atom);
5755 if (*format_return > 32) {
5756 *length_return *= *format_return / 32;
5757 *format_return = 32;
5765 /* note: when called from menu all parameters are NULL, so no clue what the
5766 * Widget which was clicked on was, or what the click event was
5768 void CopyGameProc(w, event, prms, nprms)
5776 ret = SaveGameToFile(gameCopyFilename, FALSE);
5780 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5781 * have a notion of a game that is selected but not copied.
5782 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5784 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5787 NULL/* lose_ownership_proc */ ,
5788 NULL/* transfer_done_proc */);
5789 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5792 NULL/* lose_ownership_proc */ ,
5793 NULL/* transfer_done_proc */);
5796 /* function called when the data to Paste is ready */
5798 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5799 Atom *type, XtPointer value, unsigned long *len, int *format)
5802 if (value == NULL || *len == 0) {
5803 return; /* nothing had been selected to copy */
5805 f = fopen(gamePasteFilename, "w");
5807 DisplayError(_("Can't open temp file"), errno);
5810 fwrite(value, 1, *len, f);
5813 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5816 /* called when Paste Game button is pressed,
5817 * all parameters will be NULL */
5818 void PasteGameProc(w, event, prms, nprms)
5824 XtGetSelectionValue(menuBarWidget,
5825 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5826 /* (XtSelectionCallbackProc) */ PasteGameCB,
5827 NULL, /* client_data passed to PasteGameCB */
5829 /* better to use the time field from the event that triggered the
5830 * call to this function, but that isn't trivial to get
5840 SaveGameProc(NULL, NULL, NULL, NULL);
5844 void QuitProc(w, event, prms, nprms)
5853 void PauseProc(w, event, prms, nprms)
5863 void MachineBlackProc(w, event, prms, nprms)
5869 MachineBlackEvent();
5872 void MachineWhiteProc(w, event, prms, nprms)
5878 MachineWhiteEvent();
5881 void AnalyzeModeProc(w, event, prms, nprms)
5889 if (!first.analysisSupport) {
5890 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5891 DisplayError(buf, 0);
5894 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5895 if (appData.icsActive) {
5896 if (gameMode != IcsObserving) {
5897 sprintf(buf,_("You are not observing a game"));
5898 DisplayError(buf, 0);
5900 if (appData.icsEngineAnalyze) {
5901 if (appData.debugMode)
5902 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5908 /* if enable, use want disable icsEngineAnalyze */
5909 if (appData.icsEngineAnalyze) {
5914 appData.icsEngineAnalyze = TRUE;
5915 if (appData.debugMode)
5916 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5918 if (!appData.showThinking)
5919 ShowThinkingProc(w,event,prms,nprms);
5924 void AnalyzeFileProc(w, event, prms, nprms)
5930 if (!first.analysisSupport) {
5932 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5933 DisplayError(buf, 0);
5938 if (!appData.showThinking)
5939 ShowThinkingProc(w,event,prms,nprms);
5942 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5943 AnalysisPeriodicEvent(1);
5946 void TwoMachinesProc(w, event, prms, nprms)
5955 void IcsClientProc(w, event, prms, nprms)
5964 void EditGameProc(w, event, prms, nprms)
5973 void EditPositionProc(w, event, prms, nprms)
5979 EditPositionEvent();
5982 void TrainingProc(w, event, prms, nprms)
5991 void EditCommentProc(w, event, prms, nprms)
5998 EditCommentPopDown();
6004 void IcsInputBoxProc(w, event, prms, nprms)
6010 if (ICSInputBoxUp) {
6011 ICSInputBoxPopDown();
6017 void AcceptProc(w, event, prms, nprms)
6026 void DeclineProc(w, event, prms, nprms)
6035 void RematchProc(w, event, prms, nprms)
6044 void CallFlagProc(w, event, prms, nprms)
6053 void DrawProc(w, event, prms, nprms)
6062 void AbortProc(w, event, prms, nprms)
6071 void AdjournProc(w, event, prms, nprms)
6080 void ResignProc(w, event, prms, nprms)
6089 void AdjuWhiteProc(w, event, prms, nprms)
6095 UserAdjudicationEvent(+1);
6098 void AdjuBlackProc(w, event, prms, nprms)
6104 UserAdjudicationEvent(-1);
6107 void AdjuDrawProc(w, event, prms, nprms)
6113 UserAdjudicationEvent(0);
6116 void EnterKeyProc(w, event, prms, nprms)
6122 if (ICSInputBoxUp == True)
6126 void UpKeyProc(w, event, prms, nprms)
6131 { // [HGM] input: let up-arrow recall previous line from history
6138 if (!ICSInputBoxUp) return;
6139 edit = XtNameToWidget(ICSInputShell, "*form.text");
6141 XtSetArg(args[j], XtNstring, &val); j++;
6142 XtGetValues(edit, args, j);
6143 val = PrevInHistory(val);
6144 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6145 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6147 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6148 XawTextReplace(edit, 0, 0, &t);
6149 XawTextSetInsertionPoint(edit, 9999);
6153 void DownKeyProc(w, event, prms, nprms)
6158 { // [HGM] input: let down-arrow recall next line from history
6163 if (!ICSInputBoxUp) return;
6164 edit = XtNameToWidget(ICSInputShell, "*form.text");
6165 val = NextInHistory();
6166 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6167 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6169 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6170 XawTextReplace(edit, 0, 0, &t);
6171 XawTextSetInsertionPoint(edit, 9999);
6175 void StopObservingProc(w, event, prms, nprms)
6181 StopObservingEvent();
6184 void StopExaminingProc(w, event, prms, nprms)
6190 StopExaminingEvent();
6194 void ForwardProc(w, event, prms, nprms)
6204 void BackwardProc(w, event, prms, nprms)
6213 void ToStartProc(w, event, prms, nprms)
6222 void ToEndProc(w, event, prms, nprms)
6231 void RevertProc(w, event, prms, nprms)
6240 void TruncateGameProc(w, event, prms, nprms)
6246 TruncateGameEvent();
6248 void RetractMoveProc(w, event, prms, nprms)
6257 void MoveNowProc(w, event, prms, nprms)
6267 void AlwaysQueenProc(w, event, prms, nprms)
6275 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6277 if (appData.alwaysPromoteToQueen) {
6278 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6280 XtSetArg(args[0], XtNleftBitmap, None);
6282 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6286 void AnimateDraggingProc(w, event, prms, nprms)
6294 appData.animateDragging = !appData.animateDragging;
6296 if (appData.animateDragging) {
6297 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6300 XtSetArg(args[0], XtNleftBitmap, None);
6302 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6306 void AnimateMovingProc(w, event, prms, nprms)
6314 appData.animate = !appData.animate;
6316 if (appData.animate) {
6317 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6320 XtSetArg(args[0], XtNleftBitmap, None);
6322 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6326 void AutocommProc(w, event, prms, nprms)
6334 appData.autoComment = !appData.autoComment;
6336 if (appData.autoComment) {
6337 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6339 XtSetArg(args[0], XtNleftBitmap, None);
6341 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6346 void AutoflagProc(w, event, prms, nprms)
6354 appData.autoCallFlag = !appData.autoCallFlag;
6356 if (appData.autoCallFlag) {
6357 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6359 XtSetArg(args[0], XtNleftBitmap, None);
6361 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6365 void AutoflipProc(w, event, prms, nprms)
6373 appData.autoFlipView = !appData.autoFlipView;
6375 if (appData.autoFlipView) {
6376 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6378 XtSetArg(args[0], XtNleftBitmap, None);
6380 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6384 void AutobsProc(w, event, prms, nprms)
6392 appData.autoObserve = !appData.autoObserve;
6394 if (appData.autoObserve) {
6395 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6397 XtSetArg(args[0], XtNleftBitmap, None);
6399 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6403 void AutoraiseProc(w, event, prms, nprms)
6411 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6413 if (appData.autoRaiseBoard) {
6414 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6416 XtSetArg(args[0], XtNleftBitmap, None);
6418 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6422 void AutosaveProc(w, event, prms, nprms)
6430 appData.autoSaveGames = !appData.autoSaveGames;
6432 if (appData.autoSaveGames) {
6433 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6435 XtSetArg(args[0], XtNleftBitmap, None);
6437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6441 void BlindfoldProc(w, event, prms, nprms)
6449 appData.blindfold = !appData.blindfold;
6451 if (appData.blindfold) {
6452 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6454 XtSetArg(args[0], XtNleftBitmap, None);
6456 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6459 DrawPosition(True, NULL);
6462 void TestLegalityProc(w, event, prms, nprms)
6470 appData.testLegality = !appData.testLegality;
6472 if (appData.testLegality) {
6473 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6475 XtSetArg(args[0], XtNleftBitmap, None);
6477 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6482 void FlashMovesProc(w, event, prms, nprms)
6490 if (appData.flashCount == 0) {
6491 appData.flashCount = 3;
6493 appData.flashCount = -appData.flashCount;
6496 if (appData.flashCount > 0) {
6497 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6499 XtSetArg(args[0], XtNleftBitmap, None);
6501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6505 void FlipViewProc(w, event, prms, nprms)
6511 flipView = !flipView;
6512 DrawPosition(True, NULL);
6515 void GetMoveListProc(w, event, prms, nprms)
6523 appData.getMoveList = !appData.getMoveList;
6525 if (appData.getMoveList) {
6526 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6529 XtSetArg(args[0], XtNleftBitmap, None);
6531 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6536 void HighlightDraggingProc(w, event, prms, nprms)
6544 appData.highlightDragging = !appData.highlightDragging;
6546 if (appData.highlightDragging) {
6547 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6549 XtSetArg(args[0], XtNleftBitmap, None);
6551 XtSetValues(XtNameToWidget(menuBarWidget,
6552 "menuOptions.Highlight Dragging"), args, 1);
6556 void HighlightLastMoveProc(w, event, prms, nprms)
6564 appData.highlightLastMove = !appData.highlightLastMove;
6566 if (appData.highlightLastMove) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget,
6572 "menuOptions.Highlight Last Move"), args, 1);
6575 void IcsAlarmProc(w, event, prms, nprms)
6583 appData.icsAlarm = !appData.icsAlarm;
6585 if (appData.icsAlarm) {
6586 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6588 XtSetArg(args[0], XtNleftBitmap, None);
6590 XtSetValues(XtNameToWidget(menuBarWidget,
6591 "menuOptions.ICS Alarm"), args, 1);
6594 void MoveSoundProc(w, event, prms, nprms)
6602 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6604 if (appData.ringBellAfterMoves) {
6605 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6607 XtSetArg(args[0], XtNleftBitmap, None);
6609 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6614 void OldSaveStyleProc(w, event, prms, nprms)
6622 appData.oldSaveStyle = !appData.oldSaveStyle;
6624 if (appData.oldSaveStyle) {
6625 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6627 XtSetArg(args[0], XtNleftBitmap, None);
6629 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6633 void PeriodicUpdatesProc(w, event, prms, nprms)
6641 PeriodicUpdatesEvent(!appData.periodicUpdates);
6643 if (appData.periodicUpdates) {
6644 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6646 XtSetArg(args[0], XtNleftBitmap, None);
6648 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6652 void PonderNextMoveProc(w, event, prms, nprms)
6660 PonderNextMoveEvent(!appData.ponderNextMove);
6662 if (appData.ponderNextMove) {
6663 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6665 XtSetArg(args[0], XtNleftBitmap, None);
6667 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6671 void PopupExitMessageProc(w, event, prms, nprms)
6679 appData.popupExitMessage = !appData.popupExitMessage;
6681 if (appData.popupExitMessage) {
6682 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6684 XtSetArg(args[0], XtNleftBitmap, None);
6686 XtSetValues(XtNameToWidget(menuBarWidget,
6687 "menuOptions.Popup Exit Message"), args, 1);
6690 void PopupMoveErrorsProc(w, event, prms, nprms)
6698 appData.popupMoveErrors = !appData.popupMoveErrors;
6700 if (appData.popupMoveErrors) {
6701 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6703 XtSetArg(args[0], XtNleftBitmap, None);
6705 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6709 void PremoveProc(w, event, prms, nprms)
6717 appData.premove = !appData.premove;
6719 if (appData.premove) {
6720 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6722 XtSetArg(args[0], XtNleftBitmap, None);
6724 XtSetValues(XtNameToWidget(menuBarWidget,
6725 "menuOptions.Premove"), args, 1);
6728 void QuietPlayProc(w, event, prms, nprms)
6736 appData.quietPlay = !appData.quietPlay;
6738 if (appData.quietPlay) {
6739 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6741 XtSetArg(args[0], XtNleftBitmap, None);
6743 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6747 void ShowCoordsProc(w, event, prms, nprms)
6755 appData.showCoords = !appData.showCoords;
6757 if (appData.showCoords) {
6758 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6760 XtSetArg(args[0], XtNleftBitmap, None);
6762 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6765 DrawPosition(True, NULL);
6768 void ShowThinkingProc(w, event, prms, nprms)
6774 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6775 ShowThinkingEvent();
6778 void HideThinkingProc(w, event, prms, nprms)
6786 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6787 ShowThinkingEvent();
6789 if (appData.hideThinkingFromHuman) {
6790 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6792 XtSetArg(args[0], XtNleftBitmap, None);
6794 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6798 void SaveOnExitProc(w, event, prms, nprms)
6806 saveSettingsOnExit = !saveSettingsOnExit;
6808 if (saveSettingsOnExit) {
6809 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6811 XtSetArg(args[0], XtNleftBitmap, None);
6813 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6817 void SaveSettingsProc(w, event, prms, nprms)
6823 SaveSettings(settingsFileName);
6826 void InfoProc(w, event, prms, nprms)
6833 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6838 void ManProc(w, event, prms, nprms)
6846 if (nprms && *nprms > 0)
6850 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6854 void HintProc(w, event, prms, nprms)
6863 void BookProc(w, event, prms, nprms)
6872 void AboutProc(w, event, prms, nprms)
6880 char *zippy = " (with Zippy code)";
6884 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6885 programVersion, zippy,
6886 "Copyright 1991 Digital Equipment Corporation",
6887 "Enhancements Copyright 1992-2009 Free Software Foundation",
6888 "Enhancements Copyright 2005 Alessandro Scotti",
6889 PACKAGE, " is free software and carries NO WARRANTY;",
6890 "see the file COPYING for more information.");
6891 ErrorPopUp(_("About XBoard"), buf, FALSE);
6894 void DebugProc(w, event, prms, nprms)
6900 appData.debugMode = !appData.debugMode;
6903 void AboutGameProc(w, event, prms, nprms)
6912 void NothingProc(w, event, prms, nprms)
6921 void Iconify(w, event, prms, nprms)
6930 XtSetArg(args[0], XtNiconic, True);
6931 XtSetValues(shellWidget, args, 1);
6934 void DisplayMessage(message, extMessage)
6935 char *message, *extMessage;
6937 /* display a message in the message widget */
6946 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6951 message = extMessage;
6955 /* need to test if messageWidget already exists, since this function
6956 can also be called during the startup, if for example a Xresource
6957 is not set up correctly */
6960 XtSetArg(arg, XtNlabel, message);
6961 XtSetValues(messageWidget, &arg, 1);
6967 void DisplayTitle(text)
6972 char title[MSG_SIZ];
6975 if (text == NULL) text = "";
6977 if (appData.titleInWindow) {
6979 XtSetArg(args[i], XtNlabel, text); i++;
6980 XtSetValues(titleWidget, args, i);
6983 if (*text != NULLCHAR) {
6985 strcpy(title, text);
6986 } else if (appData.icsActive) {
6987 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6988 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6989 } else if (appData.cmailGameName[0] != NULLCHAR) {
6990 snprintf(icon, sizeof(icon), "%s", "CMail");
6991 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6993 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6994 } else if (gameInfo.variant == VariantGothic) {
6995 strcpy(icon, programName);
6996 strcpy(title, GOTHIC);
6999 } else if (gameInfo.variant == VariantFalcon) {
7000 strcpy(icon, programName);
7001 strcpy(title, FALCON);
7003 } else if (appData.noChessProgram) {
7004 strcpy(icon, programName);
7005 strcpy(title, programName);
7007 strcpy(icon, first.tidy);
7008 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7011 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7012 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7013 XtSetValues(shellWidget, args, i);
7017 void DisplayError(message, error)
7024 if (appData.debugMode || appData.matchMode) {
7025 fprintf(stderr, "%s: %s\n", programName, message);
7028 if (appData.debugMode || appData.matchMode) {
7029 fprintf(stderr, "%s: %s: %s\n",
7030 programName, message, strerror(error));
7032 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7035 ErrorPopUp(_("Error"), message, FALSE);
7039 void DisplayMoveError(message)
7044 DrawPosition(FALSE, NULL);
7045 if (appData.debugMode || appData.matchMode) {
7046 fprintf(stderr, "%s: %s\n", programName, message);
7048 if (appData.popupMoveErrors) {
7049 ErrorPopUp(_("Error"), message, FALSE);
7051 DisplayMessage(message, "");
7056 void DisplayFatalError(message, error, status)
7062 errorExitStatus = status;
7064 fprintf(stderr, "%s: %s\n", programName, message);
7066 fprintf(stderr, "%s: %s: %s\n",
7067 programName, message, strerror(error));
7068 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7071 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7072 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7078 void DisplayInformation(message)
7082 ErrorPopUp(_("Information"), message, TRUE);
7085 void DisplayNote(message)
7089 ErrorPopUp(_("Note"), message, FALSE);
7093 NullXErrorCheck(dpy, error_event)
7095 XErrorEvent *error_event;
7100 void DisplayIcsInteractionTitle(message)
7103 if (oldICSInteractionTitle == NULL) {
7104 /* Magic to find the old window title, adapted from vim */
7105 char *wina = getenv("WINDOWID");
7107 Window win = (Window) atoi(wina);
7108 Window root, parent, *children;
7109 unsigned int nchildren;
7110 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7112 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7113 if (!XQueryTree(xDisplay, win, &root, &parent,
7114 &children, &nchildren)) break;
7115 if (children) XFree((void *)children);
7116 if (parent == root || parent == 0) break;
7119 XSetErrorHandler(oldHandler);
7121 if (oldICSInteractionTitle == NULL) {
7122 oldICSInteractionTitle = "xterm";
7125 printf("\033]0;%s\007", message);
7129 char pendingReplyPrefix[MSG_SIZ];
7130 ProcRef pendingReplyPR;
7132 void AskQuestionProc(w, event, prms, nprms)
7139 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7143 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7146 void AskQuestionPopDown()
7148 if (!askQuestionUp) return;
7149 XtPopdown(askQuestionShell);
7150 XtDestroyWidget(askQuestionShell);
7151 askQuestionUp = False;
7154 void AskQuestionReplyAction(w, event, prms, nprms)
7164 reply = XawDialogGetValueString(w = XtParent(w));
7165 strcpy(buf, pendingReplyPrefix);
7166 if (*buf) strcat(buf, " ");
7169 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7170 AskQuestionPopDown();
7172 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7175 void AskQuestionCallback(w, client_data, call_data)
7177 XtPointer client_data, call_data;
7182 XtSetArg(args[0], XtNlabel, &name);
7183 XtGetValues(w, args, 1);
7185 if (strcmp(name, _("cancel")) == 0) {
7186 AskQuestionPopDown();
7188 AskQuestionReplyAction(w, NULL, NULL, NULL);
7192 void AskQuestion(title, question, replyPrefix, pr)
7193 char *title, *question, *replyPrefix;
7197 Widget popup, layout, dialog, edit;
7203 strcpy(pendingReplyPrefix, replyPrefix);
7204 pendingReplyPR = pr;
7207 XtSetArg(args[i], XtNresizable, True); i++;
7208 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7209 askQuestionShell = popup =
7210 XtCreatePopupShell(title, transientShellWidgetClass,
7211 shellWidget, args, i);
7214 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7215 layoutArgs, XtNumber(layoutArgs));
7218 XtSetArg(args[i], XtNlabel, question); i++;
7219 XtSetArg(args[i], XtNvalue, ""); i++;
7220 XtSetArg(args[i], XtNborderWidth, 0); i++;
7221 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7224 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7225 (XtPointer) dialog);
7226 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7227 (XtPointer) dialog);
7229 XtRealizeWidget(popup);
7230 CatchDeleteWindow(popup, "AskQuestionPopDown");
7232 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7233 &x, &y, &win_x, &win_y, &mask);
7235 XtSetArg(args[0], XtNx, x - 10);
7236 XtSetArg(args[1], XtNy, y - 30);
7237 XtSetValues(popup, args, 2);
7239 XtPopup(popup, XtGrabExclusive);
7240 askQuestionUp = True;
7242 edit = XtNameToWidget(dialog, "*value");
7243 XtSetKeyboardFocus(popup, edit);
7251 if (*name == NULLCHAR) {
7253 } else if (strcmp(name, "$") == 0) {
7254 putc(BELLCHAR, stderr);
7257 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7265 PlaySound(appData.soundMove);
7271 PlaySound(appData.soundIcsWin);
7277 PlaySound(appData.soundIcsLoss);
7283 PlaySound(appData.soundIcsDraw);
7287 PlayIcsUnfinishedSound()
7289 PlaySound(appData.soundIcsUnfinished);
7295 PlaySound(appData.soundIcsAlarm);
7301 system("stty echo");
7307 system("stty -echo");
7311 Colorize(cc, continuation)
7316 int count, outCount, error;
7318 if (textColors[(int)cc].bg > 0) {
7319 if (textColors[(int)cc].fg > 0) {
7320 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7321 textColors[(int)cc].fg, textColors[(int)cc].bg);
7323 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7324 textColors[(int)cc].bg);
7327 if (textColors[(int)cc].fg > 0) {
7328 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7329 textColors[(int)cc].fg);
7331 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7334 count = strlen(buf);
7335 outCount = OutputToProcess(NoProc, buf, count, &error);
7336 if (outCount < count) {
7337 DisplayFatalError(_("Error writing to display"), error, 1);
7340 if (continuation) return;
7343 PlaySound(appData.soundShout);
7346 PlaySound(appData.soundSShout);
7349 PlaySound(appData.soundChannel1);
7352 PlaySound(appData.soundChannel);
7355 PlaySound(appData.soundKibitz);
7358 PlaySound(appData.soundTell);
7360 case ColorChallenge:
7361 PlaySound(appData.soundChallenge);
7364 PlaySound(appData.soundRequest);
7367 PlaySound(appData.soundSeek);
7378 return getpwuid(getuid())->pw_name;
7381 static char *ExpandPathName(path)
7384 static char static_buf[2000];
7385 char *d, *s, buf[2000];
7391 while (*s && isspace(*s))
7400 if (*(s+1) == '/') {
7401 strcpy(d, getpwuid(getuid())->pw_dir);
7406 *strchr(buf, '/') = 0;
7407 pwd = getpwnam(buf);
7410 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7414 strcpy(d, pwd->pw_dir);
7415 strcat(d, strchr(s+1, '/'));
7426 static char host_name[MSG_SIZ];
7428 #if HAVE_GETHOSTNAME
7429 gethostname(host_name, MSG_SIZ);
7431 #else /* not HAVE_GETHOSTNAME */
7432 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7433 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7435 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7437 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7438 #endif /* not HAVE_GETHOSTNAME */
7441 XtIntervalId delayedEventTimerXID = 0;
7442 DelayedEventCallback delayedEventCallback = 0;
7447 delayedEventTimerXID = 0;
7448 delayedEventCallback();
7452 ScheduleDelayedEvent(cb, millisec)
7453 DelayedEventCallback cb; long millisec;
7455 if(delayedEventTimerXID && delayedEventCallback == cb)
7456 // [HGM] alive: replace, rather than add or flush identical event
7457 XtRemoveTimeOut(delayedEventTimerXID);
7458 delayedEventCallback = cb;
7459 delayedEventTimerXID =
7460 XtAppAddTimeOut(appContext, millisec,
7461 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7464 DelayedEventCallback
7467 if (delayedEventTimerXID) {
7468 return delayedEventCallback;
7475 CancelDelayedEvent()
7477 if (delayedEventTimerXID) {
7478 XtRemoveTimeOut(delayedEventTimerXID);
7479 delayedEventTimerXID = 0;
7483 XtIntervalId loadGameTimerXID = 0;
7485 int LoadGameTimerRunning()
7487 return loadGameTimerXID != 0;
7490 int StopLoadGameTimer()
7492 if (loadGameTimerXID != 0) {
7493 XtRemoveTimeOut(loadGameTimerXID);
7494 loadGameTimerXID = 0;
7502 LoadGameTimerCallback(arg, id)
7506 loadGameTimerXID = 0;
7511 StartLoadGameTimer(millisec)
7515 XtAppAddTimeOut(appContext, millisec,
7516 (XtTimerCallbackProc) LoadGameTimerCallback,
7520 XtIntervalId analysisClockXID = 0;
7523 AnalysisClockCallback(arg, id)
7527 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7528 || appData.icsEngineAnalyze) { // [DM]
7529 AnalysisPeriodicEvent(0);
7530 StartAnalysisClock();
7535 StartAnalysisClock()
7538 XtAppAddTimeOut(appContext, 2000,
7539 (XtTimerCallbackProc) AnalysisClockCallback,
7543 XtIntervalId clockTimerXID = 0;
7545 int ClockTimerRunning()
7547 return clockTimerXID != 0;
7550 int StopClockTimer()
7552 if (clockTimerXID != 0) {
7553 XtRemoveTimeOut(clockTimerXID);
7562 ClockTimerCallback(arg, id)
7571 StartClockTimer(millisec)
7575 XtAppAddTimeOut(appContext, millisec,
7576 (XtTimerCallbackProc) ClockTimerCallback,
7581 DisplayTimerLabel(w, color, timer, highlight)
7590 /* check for low time warning */
7591 Pixel foregroundOrWarningColor = timerForegroundPixel;
7594 appData.lowTimeWarning &&
7595 (timer / 1000) < appData.icsAlarmTime)
7596 foregroundOrWarningColor = lowTimeWarningColor;
7598 if (appData.clockMode) {
7599 sprintf(buf, "%s: %s", color, TimeString(timer));
7600 XtSetArg(args[0], XtNlabel, buf);
7602 sprintf(buf, "%s ", color);
7603 XtSetArg(args[0], XtNlabel, buf);
7608 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7609 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7611 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7612 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7615 XtSetValues(w, args, 3);
7619 DisplayWhiteClock(timeRemaining, highlight)
7625 if(appData.noGUI) return;
7626 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7627 if (highlight && iconPixmap == bIconPixmap) {
7628 iconPixmap = wIconPixmap;
7629 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7630 XtSetValues(shellWidget, args, 1);
7635 DisplayBlackClock(timeRemaining, highlight)
7641 if(appData.noGUI) return;
7642 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7643 if (highlight && iconPixmap == wIconPixmap) {
7644 iconPixmap = bIconPixmap;
7645 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7646 XtSetValues(shellWidget, args, 1);
7664 int StartChildProcess(cmdLine, dir, pr)
7671 int to_prog[2], from_prog[2];
7675 if (appData.debugMode) {
7676 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7679 /* We do NOT feed the cmdLine to the shell; we just
7680 parse it into blank-separated arguments in the
7681 most simple-minded way possible.
7684 strcpy(buf, cmdLine);
7687 while(*p == ' ') p++;
7689 if(*p == '"' || *p == '\'')
7690 p = strchr(++argv[i-1], *p);
7691 else p = strchr(p, ' ');
7692 if (p == NULL) break;
7697 SetUpChildIO(to_prog, from_prog);
7699 if ((pid = fork()) == 0) {
7701 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7702 close(to_prog[1]); // first close the unused pipe ends
7703 close(from_prog[0]);
7704 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7705 dup2(from_prog[1], 1);
7706 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7707 close(from_prog[1]); // and closing again loses one of the pipes!
7708 if(fileno(stderr) >= 2) // better safe than sorry...
7709 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7711 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7716 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7718 execvp(argv[0], argv);
7720 /* If we get here, exec failed */
7725 /* Parent process */
7727 close(from_prog[1]);
7729 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7732 cp->fdFrom = from_prog[0];
7733 cp->fdTo = to_prog[1];
7738 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7739 static RETSIGTYPE AlarmCallBack(int n)
7745 DestroyChildProcess(pr, signalType)
7749 ChildProc *cp = (ChildProc *) pr;
7751 if (cp->kind != CPReal) return;
7753 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7754 signal(SIGALRM, AlarmCallBack);
7756 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7757 kill(cp->pid, SIGKILL); // kill it forcefully
7758 wait((int *) 0); // and wait again
7762 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7764 /* Process is exiting either because of the kill or because of
7765 a quit command sent by the backend; either way, wait for it to die.
7774 InterruptChildProcess(pr)
7777 ChildProc *cp = (ChildProc *) pr;
7779 if (cp->kind != CPReal) return;
7780 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7783 int OpenTelnet(host, port, pr)
7788 char cmdLine[MSG_SIZ];
7790 if (port[0] == NULLCHAR) {
7791 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7793 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7795 return StartChildProcess(cmdLine, "", pr);
7798 int OpenTCP(host, port, pr)
7804 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7805 #else /* !OMIT_SOCKETS */
7807 struct sockaddr_in sa;
7809 unsigned short uport;
7812 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7816 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7817 sa.sin_family = AF_INET;
7818 sa.sin_addr.s_addr = INADDR_ANY;
7819 uport = (unsigned short) 0;
7820 sa.sin_port = htons(uport);
7821 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7825 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7826 if (!(hp = gethostbyname(host))) {
7828 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7829 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7830 hp->h_addrtype = AF_INET;
7832 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7833 hp->h_addr_list[0] = (char *) malloc(4);
7834 hp->h_addr_list[0][0] = b0;
7835 hp->h_addr_list[0][1] = b1;
7836 hp->h_addr_list[0][2] = b2;
7837 hp->h_addr_list[0][3] = b3;
7842 sa.sin_family = hp->h_addrtype;
7843 uport = (unsigned short) atoi(port);
7844 sa.sin_port = htons(uport);
7845 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7847 if (connect(s, (struct sockaddr *) &sa,
7848 sizeof(struct sockaddr_in)) < 0) {
7852 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7859 #endif /* !OMIT_SOCKETS */
7864 int OpenCommPort(name, pr)
7871 fd = open(name, 2, 0);
7872 if (fd < 0) return errno;
7874 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7884 int OpenLoopback(pr)
7890 SetUpChildIO(to, from);
7892 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7895 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7902 int OpenRcmd(host, user, cmd, pr)
7903 char *host, *user, *cmd;
7906 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7910 #define INPUT_SOURCE_BUF_SIZE 8192
7919 char buf[INPUT_SOURCE_BUF_SIZE];
7924 DoInputCallback(closure, source, xid)
7929 InputSource *is = (InputSource *) closure;
7934 if (is->lineByLine) {
7935 count = read(is->fd, is->unused,
7936 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7938 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7941 is->unused += count;
7943 while (p < is->unused) {
7944 q = memchr(p, '\n', is->unused - p);
7945 if (q == NULL) break;
7947 (is->func)(is, is->closure, p, q - p, 0);
7951 while (p < is->unused) {
7956 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7961 (is->func)(is, is->closure, is->buf, count, error);
7965 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7972 ChildProc *cp = (ChildProc *) pr;
7974 is = (InputSource *) calloc(1, sizeof(InputSource));
7975 is->lineByLine = lineByLine;
7979 is->fd = fileno(stdin);
7981 is->kind = cp->kind;
7982 is->fd = cp->fdFrom;
7985 is->unused = is->buf;
7988 is->xid = XtAppAddInput(appContext, is->fd,
7989 (XtPointer) (XtInputReadMask),
7990 (XtInputCallbackProc) DoInputCallback,
7992 is->closure = closure;
7993 return (InputSourceRef) is;
7997 RemoveInputSource(isr)
8000 InputSource *is = (InputSource *) isr;
8002 if (is->xid == 0) return;
8003 XtRemoveInput(is->xid);
8007 int OutputToProcess(pr, message, count, outError)
8013 static int line = 0;
8014 ChildProc *cp = (ChildProc *) pr;
8019 if (appData.noJoin || !appData.useInternalWrap)
8020 outCount = fwrite(message, 1, count, stdout);
8023 int width = get_term_width();
8024 int len = wrap(NULL, message, count, width, &line);
8025 char *msg = malloc(len);
8029 outCount = fwrite(message, 1, count, stdout);
8032 dbgchk = wrap(msg, message, count, width, &line);
8033 if (dbgchk != len && appData.debugMode)
8034 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8035 outCount = fwrite(msg, 1, dbgchk, stdout);
8041 outCount = write(cp->fdTo, message, count);
8051 /* Output message to process, with "ms" milliseconds of delay
8052 between each character. This is needed when sending the logon
8053 script to ICC, which for some reason doesn't like the
8054 instantaneous send. */
8055 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8062 ChildProc *cp = (ChildProc *) pr;
8067 r = write(cp->fdTo, message++, 1);
8080 /**** Animation code by Hugh Fisher, DCS, ANU.
8082 Known problem: if a window overlapping the board is
8083 moved away while a piece is being animated underneath,
8084 the newly exposed area won't be updated properly.
8085 I can live with this.
8087 Known problem: if you look carefully at the animation
8088 of pieces in mono mode, they are being drawn as solid
8089 shapes without interior detail while moving. Fixing
8090 this would be a major complication for minimal return.
8093 /* Masks for XPM pieces. Black and white pieces can have
8094 different shapes, but in the interest of retaining my
8095 sanity pieces must have the same outline on both light
8096 and dark squares, and all pieces must use the same
8097 background square colors/images. */
8099 static int xpmDone = 0;
8102 CreateAnimMasks (pieceDepth)
8109 unsigned long plane;
8112 /* Need a bitmap just to get a GC with right depth */
8113 buf = XCreatePixmap(xDisplay, xBoardWindow,
8115 values.foreground = 1;
8116 values.background = 0;
8117 /* Don't use XtGetGC, not read only */
8118 maskGC = XCreateGC(xDisplay, buf,
8119 GCForeground | GCBackground, &values);
8120 XFreePixmap(xDisplay, buf);
8122 buf = XCreatePixmap(xDisplay, xBoardWindow,
8123 squareSize, squareSize, pieceDepth);
8124 values.foreground = XBlackPixel(xDisplay, xScreen);
8125 values.background = XWhitePixel(xDisplay, xScreen);
8126 bufGC = XCreateGC(xDisplay, buf,
8127 GCForeground | GCBackground, &values);
8129 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8130 /* Begin with empty mask */
8131 if(!xpmDone) // [HGM] pieces: keep using existing
8132 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8133 squareSize, squareSize, 1);
8134 XSetFunction(xDisplay, maskGC, GXclear);
8135 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8136 0, 0, squareSize, squareSize);
8138 /* Take a copy of the piece */
8143 XSetFunction(xDisplay, bufGC, GXcopy);
8144 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8146 0, 0, squareSize, squareSize, 0, 0);
8148 /* XOR the background (light) over the piece */
8149 XSetFunction(xDisplay, bufGC, GXxor);
8151 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8152 0, 0, squareSize, squareSize, 0, 0);
8154 XSetForeground(xDisplay, bufGC, lightSquareColor);
8155 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8158 /* We now have an inverted piece image with the background
8159 erased. Construct mask by just selecting all the non-zero
8160 pixels - no need to reconstruct the original image. */
8161 XSetFunction(xDisplay, maskGC, GXor);
8163 /* Might be quicker to download an XImage and create bitmap
8164 data from it rather than this N copies per piece, but it
8165 only takes a fraction of a second and there is a much
8166 longer delay for loading the pieces. */
8167 for (n = 0; n < pieceDepth; n ++) {
8168 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8169 0, 0, squareSize, squareSize,
8175 XFreePixmap(xDisplay, buf);
8176 XFreeGC(xDisplay, bufGC);
8177 XFreeGC(xDisplay, maskGC);
8181 InitAnimState (anim, info)
8183 XWindowAttributes * info;
8188 /* Each buffer is square size, same depth as window */
8189 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8190 squareSize, squareSize, info->depth);
8191 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8192 squareSize, squareSize, info->depth);
8194 /* Create a plain GC for blitting */
8195 mask = GCForeground | GCBackground | GCFunction |
8196 GCPlaneMask | GCGraphicsExposures;
8197 values.foreground = XBlackPixel(xDisplay, xScreen);
8198 values.background = XWhitePixel(xDisplay, xScreen);
8199 values.function = GXcopy;
8200 values.plane_mask = AllPlanes;
8201 values.graphics_exposures = False;
8202 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8204 /* Piece will be copied from an existing context at
8205 the start of each new animation/drag. */
8206 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8208 /* Outline will be a read-only copy of an existing */
8209 anim->outlineGC = None;
8215 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8216 XWindowAttributes info;
8218 if (xpmDone && gameInfo.variant == old) return;
8219 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8220 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8222 InitAnimState(&game, &info);
8223 InitAnimState(&player, &info);
8225 /* For XPM pieces, we need bitmaps to use as masks. */
8227 CreateAnimMasks(info.depth);
8233 static Boolean frameWaiting;
8235 static RETSIGTYPE FrameAlarm (sig)
8238 frameWaiting = False;
8239 /* In case System-V style signals. Needed?? */
8240 signal(SIGALRM, FrameAlarm);
8247 struct itimerval delay;
8249 XSync(xDisplay, False);
8252 frameWaiting = True;
8253 signal(SIGALRM, FrameAlarm);
8254 delay.it_interval.tv_sec =
8255 delay.it_value.tv_sec = time / 1000;
8256 delay.it_interval.tv_usec =
8257 delay.it_value.tv_usec = (time % 1000) * 1000;
8258 setitimer(ITIMER_REAL, &delay, NULL);
8259 while (frameWaiting) pause();
8260 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8261 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8262 setitimer(ITIMER_REAL, &delay, NULL);
8272 XSync(xDisplay, False);
8274 usleep(time * 1000);
8279 /* Convert board position to corner of screen rect and color */
8282 ScreenSquare(column, row, pt, color)
8283 int column; int row; XPoint * pt; int * color;
8286 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8287 pt->y = lineGap + row * (squareSize + lineGap);
8289 pt->x = lineGap + column * (squareSize + lineGap);
8290 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8292 *color = SquareColor(row, column);
8295 /* Convert window coords to square */
8298 BoardSquare(x, y, column, row)
8299 int x; int y; int * column; int * row;
8301 *column = EventToSquare(x, BOARD_WIDTH);
8302 if (flipView && *column >= 0)
8303 *column = BOARD_WIDTH - 1 - *column;
8304 *row = EventToSquare(y, BOARD_HEIGHT);
8305 if (!flipView && *row >= 0)
8306 *row = BOARD_HEIGHT - 1 - *row;
8311 #undef Max /* just in case */
8313 #define Max(a, b) ((a) > (b) ? (a) : (b))
8314 #define Min(a, b) ((a) < (b) ? (a) : (b))
8317 SetRect(rect, x, y, width, height)
8318 XRectangle * rect; int x; int y; int width; int height;
8322 rect->width = width;
8323 rect->height = height;
8326 /* Test if two frames overlap. If they do, return
8327 intersection rect within old and location of
8328 that rect within new. */
8331 Intersect(old, new, size, area, pt)
8332 XPoint * old; XPoint * new;
8333 int size; XRectangle * area; XPoint * pt;
8335 if (old->x > new->x + size || new->x > old->x + size ||
8336 old->y > new->y + size || new->y > old->y + size) {
8339 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8340 size - abs(old->x - new->x), size - abs(old->y - new->y));
8341 pt->x = Max(old->x - new->x, 0);
8342 pt->y = Max(old->y - new->y, 0);
8347 /* For two overlapping frames, return the rect(s)
8348 in the old that do not intersect with the new. */
8351 CalcUpdateRects(old, new, size, update, nUpdates)
8352 XPoint * old; XPoint * new; int size;
8353 XRectangle update[]; int * nUpdates;
8357 /* If old = new (shouldn't happen) then nothing to draw */
8358 if (old->x == new->x && old->y == new->y) {
8362 /* Work out what bits overlap. Since we know the rects
8363 are the same size we don't need a full intersect calc. */
8365 /* Top or bottom edge? */
8366 if (new->y > old->y) {
8367 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8369 } else if (old->y > new->y) {
8370 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8371 size, old->y - new->y);
8374 /* Left or right edge - don't overlap any update calculated above. */
8375 if (new->x > old->x) {
8376 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8377 new->x - old->x, size - abs(new->y - old->y));
8379 } else if (old->x > new->x) {
8380 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8381 old->x - new->x, size - abs(new->y - old->y));
8388 /* Generate a series of frame coords from start->mid->finish.
8389 The movement rate doubles until the half way point is
8390 reached, then halves back down to the final destination,
8391 which gives a nice slow in/out effect. The algorithmn
8392 may seem to generate too many intermediates for short
8393 moves, but remember that the purpose is to attract the
8394 viewers attention to the piece about to be moved and
8395 then to where it ends up. Too few frames would be less
8399 Tween(start, mid, finish, factor, frames, nFrames)
8400 XPoint * start; XPoint * mid;
8401 XPoint * finish; int factor;
8402 XPoint frames[]; int * nFrames;
8404 int fraction, n, count;
8408 /* Slow in, stepping 1/16th, then 1/8th, ... */
8410 for (n = 0; n < factor; n++)
8412 for (n = 0; n < factor; n++) {
8413 frames[count].x = start->x + (mid->x - start->x) / fraction;
8414 frames[count].y = start->y + (mid->y - start->y) / fraction;
8416 fraction = fraction / 2;
8420 frames[count] = *mid;
8423 /* Slow out, stepping 1/2, then 1/4, ... */
8425 for (n = 0; n < factor; n++) {
8426 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8427 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8429 fraction = fraction * 2;
8434 /* Draw a piece on the screen without disturbing what's there */
8437 SelectGCMask(piece, clip, outline, mask)
8438 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8442 /* Bitmap for piece being moved. */
8443 if (appData.monoMode) {
8444 *mask = *pieceToSolid(piece);
8445 } else if (useImages) {
8447 *mask = xpmMask[piece];
8449 *mask = ximMaskPm[piece];
8452 *mask = *pieceToSolid(piece);
8455 /* GC for piece being moved. Square color doesn't matter, but
8456 since it gets modified we make a copy of the original. */
8458 if (appData.monoMode)
8463 if (appData.monoMode)
8468 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8470 /* Outline only used in mono mode and is not modified */
8472 *outline = bwPieceGC;
8474 *outline = wbPieceGC;
8478 OverlayPiece(piece, clip, outline, dest)
8479 ChessSquare piece; GC clip; GC outline; Drawable dest;
8484 /* Draw solid rectangle which will be clipped to shape of piece */
8485 XFillRectangle(xDisplay, dest, clip,
8486 0, 0, squareSize, squareSize);
8487 if (appData.monoMode)
8488 /* Also draw outline in contrasting color for black
8489 on black / white on white cases */
8490 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8491 0, 0, squareSize, squareSize, 0, 0, 1);
8493 /* Copy the piece */
8498 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8500 0, 0, squareSize, squareSize,
8505 /* Animate the movement of a single piece */
8508 BeginAnimation(anim, piece, startColor, start)
8516 /* The old buffer is initialised with the start square (empty) */
8517 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8518 anim->prevFrame = *start;
8520 /* The piece will be drawn using its own bitmap as a matte */
8521 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8522 XSetClipMask(xDisplay, anim->pieceGC, mask);
8526 AnimationFrame(anim, frame, piece)
8531 XRectangle updates[4];
8536 /* Save what we are about to draw into the new buffer */
8537 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8538 frame->x, frame->y, squareSize, squareSize,
8541 /* Erase bits of the previous frame */
8542 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8543 /* Where the new frame overlapped the previous,
8544 the contents in newBuf are wrong. */
8545 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8546 overlap.x, overlap.y,
8547 overlap.width, overlap.height,
8549 /* Repaint the areas in the old that don't overlap new */
8550 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8551 for (i = 0; i < count; i++)
8552 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8553 updates[i].x - anim->prevFrame.x,
8554 updates[i].y - anim->prevFrame.y,
8555 updates[i].width, updates[i].height,
8556 updates[i].x, updates[i].y);
8558 /* Easy when no overlap */
8559 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8560 0, 0, squareSize, squareSize,
8561 anim->prevFrame.x, anim->prevFrame.y);
8564 /* Save this frame for next time round */
8565 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8566 0, 0, squareSize, squareSize,
8568 anim->prevFrame = *frame;
8570 /* Draw piece over original screen contents, not current,
8571 and copy entire rect. Wipes out overlapping piece images. */
8572 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8573 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8574 0, 0, squareSize, squareSize,
8575 frame->x, frame->y);
8579 EndAnimation (anim, finish)
8583 XRectangle updates[4];
8588 /* The main code will redraw the final square, so we
8589 only need to erase the bits that don't overlap. */
8590 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8591 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8592 for (i = 0; i < count; i++)
8593 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8594 updates[i].x - anim->prevFrame.x,
8595 updates[i].y - anim->prevFrame.y,
8596 updates[i].width, updates[i].height,
8597 updates[i].x, updates[i].y);
8599 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8600 0, 0, squareSize, squareSize,
8601 anim->prevFrame.x, anim->prevFrame.y);
8606 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8608 ChessSquare piece; int startColor;
8609 XPoint * start; XPoint * finish;
8610 XPoint frames[]; int nFrames;
8614 BeginAnimation(anim, piece, startColor, start);
8615 for (n = 0; n < nFrames; n++) {
8616 AnimationFrame(anim, &(frames[n]), piece);
8617 FrameDelay(appData.animSpeed);
8619 EndAnimation(anim, finish);
8622 /* Main control logic for deciding what to animate and how */
8625 AnimateMove(board, fromX, fromY, toX, toY)
8634 XPoint start, finish, mid;
8635 XPoint frames[kFactor * 2 + 1];
8636 int nFrames, startColor, endColor;
8638 /* Are we animating? */
8639 if (!appData.animate || appData.blindfold)
8642 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8643 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8644 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8646 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8647 piece = board[fromY][fromX];
8648 if (piece >= EmptySquare) return;
8653 hop = (piece == WhiteKnight || piece == BlackKnight);
8656 if (appData.debugMode) {
8657 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8658 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8659 piece, fromX, fromY, toX, toY); }
8661 ScreenSquare(fromX, fromY, &start, &startColor);
8662 ScreenSquare(toX, toY, &finish, &endColor);
8665 /* Knight: make diagonal movement then straight */
8666 if (abs(toY - fromY) < abs(toX - fromX)) {
8667 mid.x = start.x + (finish.x - start.x) / 2;
8671 mid.y = start.y + (finish.y - start.y) / 2;
8674 mid.x = start.x + (finish.x - start.x) / 2;
8675 mid.y = start.y + (finish.y - start.y) / 2;
8678 /* Don't use as many frames for very short moves */
8679 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8680 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8682 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8683 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8685 /* Be sure end square is redrawn */
8686 damage[toY][toX] = True;
8690 DragPieceBegin(x, y)
8693 int boardX, boardY, color;
8696 /* Are we animating? */
8697 if (!appData.animateDragging || appData.blindfold)
8700 /* Figure out which square we start in and the
8701 mouse position relative to top left corner. */
8702 BoardSquare(x, y, &boardX, &boardY);
8703 player.startBoardX = boardX;
8704 player.startBoardY = boardY;
8705 ScreenSquare(boardX, boardY, &corner, &color);
8706 player.startSquare = corner;
8707 player.startColor = color;
8708 /* As soon as we start dragging, the piece will jump slightly to
8709 be centered over the mouse pointer. */
8710 player.mouseDelta.x = squareSize/2;
8711 player.mouseDelta.y = squareSize/2;
8712 /* Initialise animation */
8713 player.dragPiece = PieceForSquare(boardX, boardY);
8715 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8716 player.dragActive = True;
8717 BeginAnimation(&player, player.dragPiece, color, &corner);
8718 /* Mark this square as needing to be redrawn. Note that
8719 we don't remove the piece though, since logically (ie
8720 as seen by opponent) the move hasn't been made yet. */
8721 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8722 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8723 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8724 corner.x, corner.y, squareSize, squareSize,
8725 0, 0); // [HGM] zh: unstack in stead of grab
8726 damage[boardY][boardX] = True;
8728 player.dragActive = False;
8738 /* Are we animating? */
8739 if (!appData.animateDragging || appData.blindfold)
8743 if (! player.dragActive)
8745 /* Move piece, maintaining same relative position
8746 of mouse within square */
8747 corner.x = x - player.mouseDelta.x;
8748 corner.y = y - player.mouseDelta.y;
8749 AnimationFrame(&player, &corner, player.dragPiece);
8751 if (appData.highlightDragging) {
8753 BoardSquare(x, y, &boardX, &boardY);
8754 SetHighlights(fromX, fromY, boardX, boardY);
8763 int boardX, boardY, color;
8766 /* Are we animating? */
8767 if (!appData.animateDragging || appData.blindfold)
8771 if (! player.dragActive)
8773 /* Last frame in sequence is square piece is
8774 placed on, which may not match mouse exactly. */
8775 BoardSquare(x, y, &boardX, &boardY);
8776 ScreenSquare(boardX, boardY, &corner, &color);
8777 EndAnimation(&player, &corner);
8779 /* Be sure end square is redrawn */
8780 damage[boardY][boardX] = True;
8782 /* This prevents weird things happening with fast successive
8783 clicks which on my Sun at least can cause motion events
8784 without corresponding press/release. */
8785 player.dragActive = False;
8788 /* Handle expose event while piece being dragged */
8793 if (!player.dragActive || appData.blindfold)
8796 /* What we're doing: logically, the move hasn't been made yet,
8797 so the piece is still in it's original square. But visually
8798 it's being dragged around the board. So we erase the square
8799 that the piece is on and draw it at the last known drag point. */
8800 BlankSquare(player.startSquare.x, player.startSquare.y,
8801 player.startColor, EmptySquare, xBoardWindow);
8802 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8803 damage[player.startBoardY][player.startBoardX] = TRUE;
8806 #include <sys/ioctl.h>
8807 int get_term_width()
8809 int fd, default_width;
8812 default_width = 79; // this is FICS default anyway...
8814 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8816 if (!ioctl(fd, TIOCGSIZE, &win))
8817 default_width = win.ts_cols;
8818 #elif defined(TIOCGWINSZ)
8820 if (!ioctl(fd, TIOCGWINSZ, &win))
8821 default_width = win.ws_col;
8823 return default_width;
8826 void update_ics_width()
8828 static int old_width = 0;
8829 int new_width = get_term_width();
8831 if (old_width != new_width)
8832 ics_printf("set width %d\n", new_width);
8833 old_width = new_width;
8836 void NotifyFrontendLogin()