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 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. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
210 #define usleep(t) _sleep2(((t)+500)/1000)
214 # define _(s) gettext (s)
215 # define N_(s) gettext_noop (s)
231 int main P((int argc, char **argv));
232 RETSIGTYPE CmailSigHandler P((int sig));
233 RETSIGTYPE IntSigHandler P((int sig));
234 RETSIGTYPE TermSizeSigHandler P((int sig));
235 void CreateGCs P((void));
236 void CreateXIMPieces P((void));
237 void CreateXPMPieces P((void));
238 void CreatePieces P((void));
239 void CreatePieceMenus P((void));
240 Widget CreateMenuBar P((Menu *mb));
241 Widget CreateButtonBar P ((MenuItem *mi));
242 char *FindFont P((char *pattern, int targetPxlSize));
243 void PieceMenuPopup P((Widget w, XEvent *event,
244 String *params, Cardinal *num_params));
245 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
246 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
247 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
248 u_int wreq, u_int hreq));
249 void CreateGrid P((void));
250 int EventToSquare P((int x, int limit));
251 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
252 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
253 void HandleUserMove P((Widget w, XEvent *event,
254 String *prms, Cardinal *nprms));
255 void AnimateUserMove P((Widget w, XEvent * event,
256 String * params, Cardinal * nParams));
257 void WhiteClock P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void BlackClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void DrawPositionProc P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
265 void CommentPopUp P((char *title, char *label));
266 void CommentPopDown P((void));
267 void CommentCallback P((Widget w, XtPointer client_data,
268 XtPointer call_data));
269 void ICSInputBoxPopUp P((void));
270 void ICSInputBoxPopDown P((void));
271 void FileNamePopUp P((char *label, char *def,
272 FileProc proc, char *openMode));
273 void FileNamePopDown P((void));
274 void FileNameCallback P((Widget w, XtPointer client_data,
275 XtPointer call_data));
276 void FileNameAction P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void AskQuestionReplyAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionProc P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionPopDown P((void));
283 void PromotionPopDown P((void));
284 void PromotionCallback P((Widget w, XtPointer client_data,
285 XtPointer call_data));
286 void EditCommentPopDown P((void));
287 void EditCommentCallback P((Widget w, XtPointer client_data,
288 XtPointer call_data));
289 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
290 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
291 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
292 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
294 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
296 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
298 void LoadPositionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
304 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
306 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
308 void PastePositionProc P((Widget w, XEvent *event, String *prms,
310 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void SavePositionProc P((Widget w, XEvent *event,
314 String *prms, Cardinal *nprms));
315 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
318 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
322 void MachineWhiteProc P((Widget w, XEvent *event,
323 String *prms, Cardinal *nprms));
324 void AnalyzeModeProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeFileProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
330 void IcsClientProc P((Widget w, XEvent *event, String *prms,
332 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void EditPositionProc P((Widget w, XEvent *event,
334 String *prms, Cardinal *nprms));
335 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void EditCommentProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void IcsInputBoxProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void StopObservingProc P((Widget w, XEvent *event, String *prms,
354 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
356 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
363 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
365 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
368 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
370 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
372 void AutocommProc P((Widget w, XEvent *event, String *prms,
374 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AutobsProc P((Widget w, XEvent *event, String *prms,
378 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
383 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
386 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
388 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
394 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
396 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
398 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
400 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
402 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
406 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
408 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
410 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
412 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void DisplayMove P((int moveNumber));
424 void DisplayTitle P((char *title));
425 void ICSInitScript P((void));
426 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
427 void ErrorPopUp P((char *title, char *text, int modal));
428 void ErrorPopDown P((void));
429 static char *ExpandPathName P((char *path));
430 static void CreateAnimVars P((void));
431 static void DragPieceMove P((int x, int y));
432 static void DrawDragPiece P((void));
433 char *ModeToWidgetName P((GameMode mode));
434 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void ShufflePopDown P(());
442 void EnginePopDown P(());
443 void UciPopDown P(());
444 void TimeControlPopDown P(());
445 void NewVariantPopDown P(());
446 void SettingsPopDown P(());
447 void update_ics_width P(());
448 int get_term_width P(());
450 * XBoard depends on Xt R4 or higher
452 int xtVersion = XtSpecificationRelease;
457 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
458 jailSquareColor, highlightSquareColor, premoveHighlightColor;
459 Pixel lowTimeWarningColor;
460 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
461 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
462 wjPieceGC, bjPieceGC, prelineGC, countGC;
463 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
464 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
465 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
466 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
467 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
468 ICSInputShell, fileNameShell, askQuestionShell;
469 Widget historyShell, evalGraphShell, gameListShell;
470 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
471 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
472 Font clockFontID, coordFontID, countFontID;
473 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
474 XtAppContext appContext;
476 char *oldICSInteractionTitle;
480 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
482 Position commentX = -1, commentY = -1;
483 Dimension commentW, commentH;
484 typedef unsigned int BoardSize;
486 Boolean chessProgram;
488 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
489 int squareSize, smallLayout = 0, tinyLayout = 0,
490 marginW, marginH, // [HGM] for run-time resizing
491 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
492 ICSInputBoxUp = False, askQuestionUp = False,
493 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
494 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
495 Pixel timerForegroundPixel, timerBackgroundPixel;
496 Pixel buttonForegroundPixel, buttonBackgroundPixel;
497 char *chessDir, *programName, *programVersion,
498 *gameCopyFilename, *gamePasteFilename;
499 Boolean alwaysOnTop = False;
500 Boolean saveSettingsOnExit;
501 char *settingsFileName;
502 char *icsTextMenuString;
504 char *firstChessProgramNames;
505 char *secondChessProgramNames;
507 WindowPlacement wpMain;
508 WindowPlacement wpConsole;
509 WindowPlacement wpComment;
510 WindowPlacement wpMoveHistory;
511 WindowPlacement wpEvalGraph;
512 WindowPlacement wpEngineOutput;
513 WindowPlacement wpGameList;
514 WindowPlacement wpTags;
518 Pixmap pieceBitmap[2][(int)BlackPawn];
519 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
520 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
521 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
522 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
523 int useImages, useImageSqs;
524 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
525 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
526 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
527 XImage *ximLightSquare, *ximDarkSquare;
530 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
531 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
533 #define White(piece) ((int)(piece) < (int)BlackPawn)
535 /* Variables for doing smooth animation. This whole thing
536 would be much easier if the board was double-buffered,
537 but that would require a fairly major rewrite. */
542 GC blitGC, pieceGC, outlineGC;
543 XPoint startSquare, prevFrame, mouseDelta;
547 int startBoardX, startBoardY;
550 /* There can be two pieces being animated at once: a player
551 can begin dragging a piece before the remote opponent has moved. */
553 static AnimState game, player;
555 /* Bitmaps for use as masks when drawing XPM pieces.
556 Need one for each black and white piece. */
557 static Pixmap xpmMask[BlackKing + 1];
559 /* This magic number is the number of intermediate frames used
560 in each half of the animation. For short moves it's reduced
561 by 1. The total number of frames will be factor * 2 + 1. */
564 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
566 MenuItem fileMenu[] = {
567 {N_("New Game"), ResetProc},
568 {N_("New Shuffle Game ..."), ShuffleMenuProc},
569 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
570 {"----", NothingProc},
571 {N_("Load Game"), LoadGameProc},
572 {N_("Load Next Game"), LoadNextGameProc},
573 {N_("Load Previous Game"), LoadPrevGameProc},
574 {N_("Reload Same Game"), ReloadGameProc},
575 {N_("Save Game"), SaveGameProc},
576 {"----", NothingProc},
577 {N_("Copy Game"), CopyGameProc},
578 {N_("Paste Game"), PasteGameProc},
579 {"----", NothingProc},
580 {N_("Load Position"), LoadPositionProc},
581 {N_("Load Next Position"), LoadNextPositionProc},
582 {N_("Load Previous Position"), LoadPrevPositionProc},
583 {N_("Reload Same Position"), ReloadPositionProc},
584 {N_("Save Position"), SavePositionProc},
585 {"----", NothingProc},
586 {N_("Copy Position"), CopyPositionProc},
587 {N_("Paste Position"), PastePositionProc},
588 {"----", NothingProc},
589 {N_("Mail Move"), MailMoveProc},
590 {N_("Reload CMail Message"), ReloadCmailMsgProc},
591 {"----", NothingProc},
592 {N_("Exit"), QuitProc},
596 MenuItem modeMenu[] = {
597 {N_("Machine White"), MachineWhiteProc},
598 {N_("Machine Black"), MachineBlackProc},
599 {N_("Two Machines"), TwoMachinesProc},
600 {N_("Analysis Mode"), AnalyzeModeProc},
601 {N_("Analyze File"), AnalyzeFileProc },
602 {N_("ICS Client"), IcsClientProc},
603 {N_("Edit Game"), EditGameProc},
604 {N_("Edit Position"), EditPositionProc},
605 {N_("Training"), TrainingProc},
606 {"----", NothingProc},
607 {N_("Show Engine Output"), EngineOutputProc},
608 {N_("Show Evaluation Graph"), NothingProc}, // [HGM] evalgr: not functional yet
609 {N_("Show Game List"), ShowGameListProc},
610 {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
611 {"----", NothingProc},
612 {N_("Edit Tags"), EditTagsProc},
613 {N_("Edit Comment"), EditCommentProc},
614 {N_("ICS Input Box"), IcsInputBoxProc},
615 {N_("Pause"), PauseProc},
619 MenuItem actionMenu[] = {
620 {N_("Accept"), AcceptProc},
621 {N_("Decline"), DeclineProc},
622 {N_("Rematch"), RematchProc},
623 {"----", NothingProc},
624 {N_("Call Flag"), CallFlagProc},
625 {N_("Draw"), DrawProc},
626 {N_("Adjourn"), AdjournProc},
627 {N_("Abort"), AbortProc},
628 {N_("Resign"), ResignProc},
629 {"----", NothingProc},
630 {N_("Stop Observing"), StopObservingProc},
631 {N_("Stop Examining"), StopExaminingProc},
632 {"----", NothingProc},
633 {N_("Adjudicate to White"), AdjuWhiteProc},
634 {N_("Adjudicate to Black"), AdjuBlackProc},
635 {N_("Adjudicate Draw"), AdjuDrawProc},
639 MenuItem stepMenu[] = {
640 {N_("Backward"), BackwardProc},
641 {N_("Forward"), ForwardProc},
642 {N_("Back to Start"), ToStartProc},
643 {N_("Forward to End"), ToEndProc},
644 {N_("Revert"), RevertProc},
645 {N_("Truncate Game"), TruncateGameProc},
646 {"----", NothingProc},
647 {N_("Move Now"), MoveNowProc},
648 {N_("Retract Move"), RetractMoveProc},
652 MenuItem optionsMenu[] = {
653 {N_("Flip View"), FlipViewProc},
654 {"----", NothingProc},
655 {N_("Adjudications ..."), EngineMenuProc},
656 {N_("General Settings ..."), UciMenuProc},
657 {N_("Engine #1 Settings ..."), FirstSettingsProc},
658 {N_("Engine #2 Settings ..."), SecondSettingsProc},
659 {N_("Time Control ..."), TimeControlProc},
660 {"----", NothingProc},
661 {N_("Always Queen"), AlwaysQueenProc},
662 {N_("Animate Dragging"), AnimateDraggingProc},
663 {N_("Animate Moving"), AnimateMovingProc},
664 {N_("Auto Comment"), AutocommProc},
665 {N_("Auto Flag"), AutoflagProc},
666 {N_("Auto Flip View"), AutoflipProc},
667 {N_("Auto Observe"), AutobsProc},
668 {N_("Auto Raise Board"), AutoraiseProc},
669 {N_("Auto Save"), AutosaveProc},
670 {N_("Blindfold"), BlindfoldProc},
671 {N_("Flash Moves"), FlashMovesProc},
672 {N_("Get Move List"), GetMoveListProc},
674 {N_("Highlight Dragging"), HighlightDraggingProc},
676 {N_("Highlight Last Move"), HighlightLastMoveProc},
677 {N_("Move Sound"), MoveSoundProc},
678 {N_("ICS Alarm"), IcsAlarmProc},
679 {N_("Old Save Style"), OldSaveStyleProc},
680 {N_("Periodic Updates"), PeriodicUpdatesProc},
681 {N_("Ponder Next Move"), PonderNextMoveProc},
682 {N_("Popup Exit Message"), PopupExitMessageProc},
683 {N_("Popup Move Errors"), PopupMoveErrorsProc},
684 {N_("Premove"), PremoveProc},
685 {N_("Quiet Play"), QuietPlayProc},
686 {N_("Show Coords"), ShowCoordsProc},
687 {N_("Hide Thinking"), HideThinkingProc},
688 {N_("Test Legality"), TestLegalityProc},
689 {"----", NothingProc},
690 {N_("Save Settings Now"), SaveSettingsProc},
691 {N_("Save Settings on Exit"), SaveOnExitProc},
695 MenuItem helpMenu[] = {
696 {N_("Info XBoard"), InfoProc},
697 {N_("Man XBoard"), ManProc},
698 {"----", NothingProc},
699 {N_("Hint"), HintProc},
700 {N_("Book"), BookProc},
701 {"----", NothingProc},
702 {N_("About XBoard"), AboutProc},
707 {N_("File"), fileMenu},
708 {N_("Mode"), modeMenu},
709 {N_("Action"), actionMenu},
710 {N_("Step"), stepMenu},
711 {N_("Options"), optionsMenu},
712 {N_("Help"), helpMenu},
716 #define PAUSE_BUTTON N_("P")
717 MenuItem buttonBar[] = {
720 {PAUSE_BUTTON, PauseProc},
726 #define PIECE_MENU_SIZE 18
727 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
728 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
729 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
730 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
731 N_("Empty square"), N_("Clear board") },
732 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
733 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
734 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
735 N_("Empty square"), N_("Clear board") }
737 /* must be in same order as PieceMenuStrings! */
738 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
739 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
740 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
741 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
742 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
743 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
744 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
745 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
746 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
749 #define DROP_MENU_SIZE 6
750 String dropMenuStrings[DROP_MENU_SIZE] = {
751 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
753 /* must be in same order as PieceMenuStrings! */
754 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
755 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
756 WhiteRook, WhiteQueen
764 DropMenuEnables dmEnables[] = {
782 { XtNborderWidth, 0 },
783 { XtNdefaultDistance, 0 },
787 { XtNborderWidth, 0 },
788 { XtNresizable, (XtArgVal) True },
792 { XtNborderWidth, 0 },
798 { XtNjustify, (XtArgVal) XtJustifyRight },
799 { XtNlabel, (XtArgVal) "..." },
800 { XtNresizable, (XtArgVal) True },
801 { XtNresize, (XtArgVal) False }
804 Arg messageArgs[] = {
805 { XtNjustify, (XtArgVal) XtJustifyLeft },
806 { XtNlabel, (XtArgVal) "..." },
807 { XtNresizable, (XtArgVal) True },
808 { XtNresize, (XtArgVal) False }
812 { XtNborderWidth, 0 },
813 { XtNjustify, (XtArgVal) XtJustifyLeft }
816 XtResource clientResources[] = {
817 { "flashCount", "flashCount", XtRInt, sizeof(int),
818 XtOffset(AppDataPtr, flashCount), XtRImmediate,
819 (XtPointer) FLASH_COUNT },
822 XrmOptionDescRec shellOptions[] = {
823 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
824 { "-flash", "flashCount", XrmoptionNoArg, "3" },
825 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
828 XtActionsRec boardActions[] = {
829 { "DrawPosition", DrawPositionProc },
830 { "HandleUserMove", HandleUserMove },
831 { "AnimateUserMove", AnimateUserMove },
832 { "FileNameAction", FileNameAction },
833 { "AskQuestionProc", AskQuestionProc },
834 { "AskQuestionReplyAction", AskQuestionReplyAction },
835 { "PieceMenuPopup", PieceMenuPopup },
836 { "WhiteClock", WhiteClock },
837 { "BlackClock", BlackClock },
838 { "Iconify", Iconify },
839 { "ResetProc", ResetProc },
840 { "LoadGameProc", LoadGameProc },
841 { "LoadNextGameProc", LoadNextGameProc },
842 { "LoadPrevGameProc", LoadPrevGameProc },
843 { "LoadSelectedProc", LoadSelectedProc },
844 { "ReloadGameProc", ReloadGameProc },
845 { "LoadPositionProc", LoadPositionProc },
846 { "LoadNextPositionProc", LoadNextPositionProc },
847 { "LoadPrevPositionProc", LoadPrevPositionProc },
848 { "ReloadPositionProc", ReloadPositionProc },
849 { "CopyPositionProc", CopyPositionProc },
850 { "PastePositionProc", PastePositionProc },
851 { "CopyGameProc", CopyGameProc },
852 { "PasteGameProc", PasteGameProc },
853 { "SaveGameProc", SaveGameProc },
854 { "SavePositionProc", SavePositionProc },
855 { "MailMoveProc", MailMoveProc },
856 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
857 { "QuitProc", QuitProc },
858 { "MachineWhiteProc", MachineWhiteProc },
859 { "MachineBlackProc", MachineBlackProc },
860 { "AnalysisModeProc", AnalyzeModeProc },
861 { "AnalyzeFileProc", AnalyzeFileProc },
862 { "TwoMachinesProc", TwoMachinesProc },
863 { "IcsClientProc", IcsClientProc },
864 { "EditGameProc", EditGameProc },
865 { "EditPositionProc", EditPositionProc },
866 { "TrainingProc", EditPositionProc },
867 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
868 { "ShowGameListProc", ShowGameListProc },
869 { "ShowMoveListProc", HistoryShowProc},
870 { "EditTagsProc", EditCommentProc },
871 { "EditCommentProc", EditCommentProc },
872 { "IcsAlarmProc", IcsAlarmProc },
873 { "IcsInputBoxProc", IcsInputBoxProc },
874 { "PauseProc", PauseProc },
875 { "AcceptProc", AcceptProc },
876 { "DeclineProc", DeclineProc },
877 { "RematchProc", RematchProc },
878 { "CallFlagProc", CallFlagProc },
879 { "DrawProc", DrawProc },
880 { "AdjournProc", AdjournProc },
881 { "AbortProc", AbortProc },
882 { "ResignProc", ResignProc },
883 { "AdjuWhiteProc", AdjuWhiteProc },
884 { "AdjuBlackProc", AdjuBlackProc },
885 { "AdjuDrawProc", AdjuDrawProc },
886 { "EnterKeyProc", EnterKeyProc },
887 { "StopObservingProc", StopObservingProc },
888 { "StopExaminingProc", StopExaminingProc },
889 { "BackwardProc", BackwardProc },
890 { "ForwardProc", ForwardProc },
891 { "ToStartProc", ToStartProc },
892 { "ToEndProc", ToEndProc },
893 { "RevertProc", RevertProc },
894 { "TruncateGameProc", TruncateGameProc },
895 { "MoveNowProc", MoveNowProc },
896 { "RetractMoveProc", RetractMoveProc },
897 { "AlwaysQueenProc", AlwaysQueenProc },
898 { "AnimateDraggingProc", AnimateDraggingProc },
899 { "AnimateMovingProc", AnimateMovingProc },
900 { "AutoflagProc", AutoflagProc },
901 { "AutoflipProc", AutoflipProc },
902 { "AutobsProc", AutobsProc },
903 { "AutoraiseProc", AutoraiseProc },
904 { "AutosaveProc", AutosaveProc },
905 { "BlindfoldProc", BlindfoldProc },
906 { "FlashMovesProc", FlashMovesProc },
907 { "FlipViewProc", FlipViewProc },
908 { "GetMoveListProc", GetMoveListProc },
910 { "HighlightDraggingProc", HighlightDraggingProc },
912 { "HighlightLastMoveProc", HighlightLastMoveProc },
913 { "IcsAlarmProc", IcsAlarmProc },
914 { "MoveSoundProc", MoveSoundProc },
915 { "OldSaveStyleProc", OldSaveStyleProc },
916 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
917 { "PonderNextMoveProc", PonderNextMoveProc },
918 { "PopupExitMessageProc", PopupExitMessageProc },
919 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
920 { "PremoveProc", PremoveProc },
921 { "QuietPlayProc", QuietPlayProc },
922 { "ShowCoordsProc", ShowCoordsProc },
923 { "ShowThinkingProc", ShowThinkingProc },
924 { "HideThinkingProc", HideThinkingProc },
925 { "TestLegalityProc", TestLegalityProc },
926 { "SaveSettingsProc", SaveSettingsProc },
927 { "SaveOnExitProc", SaveOnExitProc },
928 { "InfoProc", InfoProc },
929 { "ManProc", ManProc },
930 { "HintProc", HintProc },
931 { "BookProc", BookProc },
932 { "AboutGameProc", AboutGameProc },
933 { "AboutProc", AboutProc },
934 { "DebugProc", DebugProc },
935 { "NothingProc", NothingProc },
936 { "CommentPopDown", (XtActionProc) CommentPopDown },
937 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
938 { "TagsPopDown", (XtActionProc) TagsPopDown },
939 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
940 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
941 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
942 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
943 { "GameListPopDown", (XtActionProc) GameListPopDown },
944 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
945 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
946 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
947 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
948 { "EnginePopDown", (XtActionProc) EnginePopDown },
949 { "UciPopDown", (XtActionProc) UciPopDown },
950 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
951 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
952 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
955 char globalTranslations[] =
956 ":<Key>R: ResignProc() \n \
957 :<Key>r: ResetProc() \n \
958 :<Key>g: LoadGameProc() \n \
959 :<Key>N: LoadNextGameProc() \n \
960 :<Key>P: LoadPrevGameProc() \n \
961 :<Key>Q: QuitProc() \n \
962 :<Key>F: ToEndProc() \n \
963 :<Key>f: ForwardProc() \n \
964 :<Key>B: ToStartProc() \n \
965 :<Key>b: BackwardProc() \n \
966 :<Key>p: PauseProc() \n \
967 :<Key>d: DrawProc() \n \
968 :<Key>t: CallFlagProc() \n \
969 :<Key>i: Iconify() \n \
970 :<Key>c: Iconify() \n \
971 :<Key>v: FlipViewProc() \n \
972 <KeyDown>Control_L: BackwardProc() \n \
973 <KeyUp>Control_L: ForwardProc() \n \
974 <KeyDown>Control_R: BackwardProc() \n \
975 <KeyUp>Control_R: ForwardProc() \n \
976 Shift<Key>1: AskQuestionProc(\"Direct command\",\
977 \"Send to chess program:\",,1) \n \
978 Shift<Key>2: AskQuestionProc(\"Direct command\",\
979 \"Send to second chess program:\",,2) \n";
981 char boardTranslations[] =
982 "<Btn1Down>: HandleUserMove() \n \
983 <Btn1Up>: HandleUserMove() \n \
984 <Btn1Motion>: AnimateUserMove() \n \
985 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
986 PieceMenuPopup(menuB) \n \
987 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
988 PieceMenuPopup(menuW) \n \
989 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuW) \n \
991 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuB) \n";
994 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
995 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
997 char ICSInputTranslations[] =
998 "<Key>Return: EnterKeyProc() \n";
1000 String xboardResources[] = {
1001 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1002 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1003 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1008 /* Max possible square size */
1009 #define MAXSQSIZE 256
1011 static int xpm_avail[MAXSQSIZE];
1013 #ifdef HAVE_DIR_STRUCT
1015 /* Extract piece size from filename */
1017 xpm_getsize(name, len, ext)
1028 if ((p=strchr(name, '.')) == NULL ||
1029 StrCaseCmp(p+1, ext) != 0)
1035 while (*p && isdigit(*p))
1042 /* Setup xpm_avail */
1044 xpm_getavail(dirname, ext)
1052 for (i=0; i<MAXSQSIZE; ++i)
1055 if (appData.debugMode)
1056 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1058 dir = opendir(dirname);
1061 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1062 programName, dirname);
1066 while ((ent=readdir(dir)) != NULL) {
1067 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1068 if (i > 0 && i < MAXSQSIZE)
1078 xpm_print_avail(fp, ext)
1084 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1085 for (i=1; i<MAXSQSIZE; ++i) {
1091 /* Return XPM piecesize closest to size */
1093 xpm_closest_to(dirname, size, ext)
1099 int sm_diff = MAXSQSIZE;
1103 xpm_getavail(dirname, ext);
1105 if (appData.debugMode)
1106 xpm_print_avail(stderr, ext);
1108 for (i=1; i<MAXSQSIZE; ++i) {
1111 diff = (diff<0) ? -diff : diff;
1112 if (diff < sm_diff) {
1120 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1126 #else /* !HAVE_DIR_STRUCT */
1127 /* If we are on a system without a DIR struct, we can't
1128 read the directory, so we can't collect a list of
1129 filenames, etc., so we can't do any size-fitting. */
1131 xpm_closest_to(dirname, size, ext)
1136 fprintf(stderr, _("\
1137 Warning: No DIR structure found on this system --\n\
1138 Unable to autosize for XPM/XIM pieces.\n\
1139 Please report this error to frankm@hiwaay.net.\n\
1140 Include system type & operating system in message.\n"));
1143 #endif /* HAVE_DIR_STRUCT */
1145 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1146 "magenta", "cyan", "white" };
1150 TextColors textColors[(int)NColorClasses];
1152 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1154 parse_color(str, which)
1158 char *p, buf[100], *d;
1161 if (strlen(str) > 99) /* watch bounds on buf */
1166 for (i=0; i<which; ++i) {
1173 /* Could be looking at something like:
1175 .. in which case we want to stop on a comma also */
1176 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1180 return -1; /* Use default for empty field */
1183 if (which == 2 || isdigit(*p))
1186 while (*p && isalpha(*p))
1191 for (i=0; i<8; ++i) {
1192 if (!StrCaseCmp(buf, cnames[i]))
1193 return which? (i+40) : (i+30);
1195 if (!StrCaseCmp(buf, "default")) return -1;
1197 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1202 parse_cpair(cc, str)
1206 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1207 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1212 /* bg and attr are optional */
1213 textColors[(int)cc].bg = parse_color(str, 1);
1214 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1215 textColors[(int)cc].attr = 0;
1221 /* Arrange to catch delete-window events */
1222 Atom wm_delete_window;
1224 CatchDeleteWindow(Widget w, String procname)
1227 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1228 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1229 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1236 XtSetArg(args[0], XtNiconic, False);
1237 XtSetValues(shellWidget, args, 1);
1239 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1242 //---------------------------------------------------------------------------------------------------------
1243 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1246 #define CW_USEDEFAULT (1<<31)
1247 #define ICS_TEXT_MENU_SIZE 90
1248 #define SetCurrentDirectory chdir
1249 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1251 // these two must some day move to frontend.h, when they are implemented
1252 Boolean EvalGraphIsUp();
1253 Boolean MoveHistoryIsUp();
1254 Boolean GameListIsUp();
1256 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1259 // front-end part of option handling
1261 // [HGM] This platform-dependent table provides the location for storing the color info
1264 &appData.whitePieceColor,
1265 &appData.blackPieceColor,
1266 &appData.lightSquareColor,
1267 &appData.darkSquareColor,
1268 &appData.highlightSquareColor,
1269 &appData.premoveHighlightColor,
1282 ParseFont(char *name, int number)
1283 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1285 case 0: // CLOCK_FONT
1286 appData.clockFont = strdup(name);
1288 case 1: // MESSAGE_FONT
1289 appData.font = strdup(name);
1291 case 2: // COORD_FONT
1292 appData.coordFont = strdup(name);
1301 { // only 2 fonts currently
1302 appData.clockFont = CLOCK_FONT_NAME;
1303 appData.coordFont = COORD_FONT_NAME;
1304 appData.font = DEFAULT_FONT_NAME;
1309 { // no-op, until we identify the code for this already in XBoard and move it here
1313 ParseColor(int n, char *name)
1314 { // in XBoard, just copy the color-name string
1315 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1319 ParseTextAttribs(ColorClass cc, char *s)
1321 (&appData.colorShout)[cc] = strdup(s);
1325 ParseBoardSize(void *addr, char *name)
1327 appData.boardSize = strdup(name);
1332 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1336 SetCommPortDefaults()
1337 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1340 // [HGM] args: these three cases taken out to stay in front-end
1342 SaveFontArg(FILE *f, ArgDescriptor *ad)
1345 switch((int)ad->argLoc) {
1346 case 0: // CLOCK_FONT
1347 name = appData.clockFont;
1349 case 1: // MESSAGE_FONT
1350 name = appData.font;
1352 case 2: // COORD_FONT
1353 name = appData.coordFont;
1358 fprintf(f, "/%s=%s\n", ad->argName, name);
1363 { // nothing to do, as the sounds are at all times represented by their text-string names already
1367 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1368 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1369 fprintf(f, "/%s=%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1373 SaveColor(FILE *f, ArgDescriptor *ad)
1374 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1375 if(colorVariable[(int)ad->argLoc])
1376 fprintf(f, "/%s=%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1380 SaveBoardSize(FILE *f, char *name, void *addr)
1381 { // wrapper to shield back-end from BoardSize & sizeInfo
1382 fprintf(f, "/%s=%s\n", name, appData.boardSize);
1386 ParseCommPortSettings(char *s)
1387 { // no such option in XBoard (yet)
1390 extern Widget engineOutputShell;
1391 extern Widget tagsShell, editTagsShell;
1393 GetActualPlacement(Widget wg, WindowPlacement *wp)
1403 XtSetArg(args[i], XtNx, &x); i++;
1404 XtSetArg(args[i], XtNy, &y); i++;
1405 XtSetArg(args[i], XtNwidth, &w); i++;
1406 XtSetArg(args[i], XtNheight, &h); i++;
1407 XtGetValues(wg, args, i);
1416 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1417 // In XBoard this will have to wait until awareness of window parameters is implemented
1418 GetActualPlacement(shellWidget, &wpMain);
1419 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1420 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1421 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1422 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1423 else GetActualPlacement(editShell, &wpComment);
1424 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1425 else GetActualPlacement(editTagsShell, &wpTags);
1427 GetActualPlacement(hwndConsole, &wpConsole);
1428 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
1433 PrintCommPortSettings(FILE *f, char *name)
1434 { // This option does not exist in XBoard
1438 MySearchPath(char *installDir, char *name, char *fullname)
1439 { // just append installDir and name. Perhaps ExpandPath should be used here?
1440 name = ExpandPathName(name);
1441 if(name && name[0] == '/') strcpy(fullname, name); else {
1442 sprintf(fullname, "%s%c%s", installDir, '/', name);
1448 MyGetFullPathName(char *name, char *fullname)
1449 { // should use ExpandPath?
1450 name = ExpandPathName(name);
1451 strcpy(fullname, name);
1456 EnsureOnScreen(int *x, int *y, int minX, int minY)
1469 { // [HGM] args: allows testing if main window is realized from back-end
1470 return xBoardWindow != 0;
1474 PopUpStartupDialog()
1475 { // start menu not implemented in XBoard
1478 ConvertToLine(int argc, char **argv)
1480 static char line[128*1024], buf[1024];
1484 for(i=1; i<argc; i++) {
1485 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1486 && argv[i][0] != '{' )
1487 sprintf(buf, "{%s} ", argv[i]);
1488 else sprintf(buf, "%s ", argv[i]);
1491 line[strlen(line)-1] = NULLCHAR;
1495 //--------------------------------------------------------------------------------------------
1498 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1500 #define BoardSize int
1501 void InitDrawingSizes(BoardSize boardSize, int flags)
1502 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1503 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1505 XtGeometryResult gres;
1508 if(!formWidget) return;
1511 * Enable shell resizing.
1513 shellArgs[0].value = (XtArgVal) &w;
1514 shellArgs[1].value = (XtArgVal) &h;
1515 XtGetValues(shellWidget, shellArgs, 2);
1517 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1518 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1519 XtSetValues(shellWidget, &shellArgs[2], 4);
1521 XtSetArg(args[0], XtNdefaultDistance, &sep);
1522 XtGetValues(formWidget, args, 1);
1524 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1525 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1528 XtSetArg(args[0], XtNwidth, boardWidth);
1529 XtSetArg(args[1], XtNheight, boardHeight);
1530 XtSetValues(boardWidget, args, 2);
1532 timerWidth = (boardWidth - sep) / 2;
1533 XtSetArg(args[0], XtNwidth, timerWidth);
1534 XtSetValues(whiteTimerWidget, args, 1);
1535 XtSetValues(blackTimerWidget, args, 1);
1537 XawFormDoLayout(formWidget, False);
1539 if (appData.titleInWindow) {
1541 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1542 XtSetArg(args[i], XtNheight, &h); i++;
1543 XtGetValues(titleWidget, args, i);
1545 w = boardWidth - 2*bor;
1547 XtSetArg(args[0], XtNwidth, &w);
1548 XtGetValues(menuBarWidget, args, 1);
1549 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1552 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1553 if (gres != XtGeometryYes && appData.debugMode) {
1555 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1556 programName, gres, w, h, wr, hr);
1560 XawFormDoLayout(formWidget, True);
1563 * Inhibit shell resizing.
1565 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1566 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1567 shellArgs[4].value = shellArgs[2].value = w;
1568 shellArgs[5].value = shellArgs[3].value = h;
1569 XtSetValues(shellWidget, &shellArgs[0], 6);
1571 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1574 for(i=0; i<4; i++) {
1576 for(p=0; p<=(int)WhiteKing; p++)
1577 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1578 if(gameInfo.variant == VariantShogi) {
1579 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1580 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1581 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1582 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1583 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1586 if(gameInfo.variant == VariantGothic) {
1587 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1591 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1592 for(p=0; p<=(int)WhiteKing; p++)
1593 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1594 if(gameInfo.variant == VariantShogi) {
1595 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1596 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1597 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1598 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1599 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1602 if(gameInfo.variant == VariantGothic) {
1603 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1609 for(i=0; i<2; i++) {
1611 for(p=0; p<=(int)WhiteKing; p++)
1612 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1613 if(gameInfo.variant == VariantShogi) {
1614 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1615 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1616 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1617 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1618 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1621 if(gameInfo.variant == VariantGothic) {
1622 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1633 void EscapeExpand(char *p, char *q)
1634 { // [HGM] initstring: routine to shape up string arguments
1635 while(*p++ = *q++) if(p[-1] == '\\')
1637 case 'n': p[-1] = '\n'; break;
1638 case 'r': p[-1] = '\r'; break;
1639 case 't': p[-1] = '\t'; break;
1640 case '\\': p[-1] = '\\'; break;
1641 case 0: *p = 0; return;
1642 default: p[-1] = q[-1]; break;
1651 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1652 XSetWindowAttributes window_attributes;
1654 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1655 XrmValue vFrom, vTo;
1656 XtGeometryResult gres;
1659 int forceMono = False;
1660 //define INDIRECTION
1662 // [HGM] before anything else, expand any indirection files amongst options
1663 char *argvCopy[1000]; // 1000 seems enough
1664 char newArgs[10000]; // holds actual characters
1667 srandom(time(0)); // [HGM] book: make random truly random
1670 for(i=0; i<argc; i++) {
1671 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1672 //fprintf(stderr, "arg %s\n", argv[i]);
1673 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1675 FILE *f = fopen(argv[i]+1, "rb");
1676 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1677 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1678 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1680 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1681 newArgs[k++] = 0; // terminate current arg
1682 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1683 argvCopy[j++] = newArgs + k; // get ready for next
1685 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1699 setbuf(stdout, NULL);
1700 setbuf(stderr, NULL);
1703 programName = strrchr(argv[0], '/');
1704 if (programName == NULL)
1705 programName = argv[0];
1710 XtSetLanguageProc(NULL, NULL, NULL);
1711 bindtextdomain(PACKAGE, LOCALEDIR);
1712 textdomain(PACKAGE);
1716 XtAppInitialize(&appContext, "XBoard", shellOptions,
1717 XtNumber(shellOptions),
1718 &argc, argv, xboardResources, NULL, 0);
1719 appData.boardSize = "";
1720 InitAppData(ConvertToLine(argc, argv));
1722 if (p == NULL) p = "/tmp";
1723 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1724 gameCopyFilename = (char*) malloc(i);
1725 gamePasteFilename = (char*) malloc(i);
1726 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1727 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1729 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1730 clientResources, XtNumber(clientResources),
1733 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1734 static char buf[MSG_SIZ];
1735 EscapeExpand(buf, appData.initString);
1736 appData.initString = strdup(buf);
1737 EscapeExpand(buf, appData.secondInitString);
1738 appData.secondInitString = strdup(buf);
1739 EscapeExpand(buf, appData.firstComputerString);
1740 appData.firstComputerString = strdup(buf);
1741 EscapeExpand(buf, appData.secondComputerString);
1742 appData.secondComputerString = strdup(buf);
1745 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1748 if (chdir(chessDir) != 0) {
1749 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1755 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1756 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1757 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1758 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1761 setbuf(debugFP, NULL);
1764 /* [HGM,HR] make sure board size is acceptable */
1765 if(appData.NrFiles > BOARD_FILES ||
1766 appData.NrRanks > BOARD_RANKS )
1767 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1770 /* This feature does not work; animation needs a rewrite */
1771 appData.highlightDragging = FALSE;
1775 xDisplay = XtDisplay(shellWidget);
1776 xScreen = DefaultScreen(xDisplay);
1777 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1779 gameInfo.variant = StringToVariant(appData.variant);
1780 InitPosition(FALSE);
1783 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1785 if (isdigit(appData.boardSize[0])) {
1786 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1787 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1788 &fontPxlSize, &smallLayout, &tinyLayout);
1790 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1791 programName, appData.boardSize);
1795 /* Find some defaults; use the nearest known size */
1796 SizeDefaults *szd, *nearest;
1797 int distance = 99999;
1798 nearest = szd = sizeDefaults;
1799 while (szd->name != NULL) {
1800 if (abs(szd->squareSize - squareSize) < distance) {
1802 distance = abs(szd->squareSize - squareSize);
1803 if (distance == 0) break;
1807 if (i < 2) lineGap = nearest->lineGap;
1808 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1809 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1810 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1811 if (i < 6) smallLayout = nearest->smallLayout;
1812 if (i < 7) tinyLayout = nearest->tinyLayout;
1815 SizeDefaults *szd = sizeDefaults;
1816 if (*appData.boardSize == NULLCHAR) {
1817 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1818 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1821 if (szd->name == NULL) szd--;
1822 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1824 while (szd->name != NULL &&
1825 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1826 if (szd->name == NULL) {
1827 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1828 programName, appData.boardSize);
1832 squareSize = szd->squareSize;
1833 lineGap = szd->lineGap;
1834 clockFontPxlSize = szd->clockFontPxlSize;
1835 coordFontPxlSize = szd->coordFontPxlSize;
1836 fontPxlSize = szd->fontPxlSize;
1837 smallLayout = szd->smallLayout;
1838 tinyLayout = szd->tinyLayout;
1841 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1842 if (strlen(appData.pixmapDirectory) > 0) {
1843 p = ExpandPathName(appData.pixmapDirectory);
1845 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1846 appData.pixmapDirectory);
1849 if (appData.debugMode) {
1850 fprintf(stderr, _("\
1851 XBoard square size (hint): %d\n\
1852 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1854 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1855 if (appData.debugMode) {
1856 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1860 /* [HR] height treated separately (hacked) */
1861 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1862 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1863 if (appData.showJail == 1) {
1864 /* Jail on top and bottom */
1865 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1866 XtSetArg(boardArgs[2], XtNheight,
1867 boardHeight + 2*(lineGap + squareSize));
1868 } else if (appData.showJail == 2) {
1870 XtSetArg(boardArgs[1], XtNwidth,
1871 boardWidth + 2*(lineGap + squareSize));
1872 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1875 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1876 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1880 * Determine what fonts to use.
1882 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1883 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1884 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1885 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1886 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1887 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1888 appData.font = FindFont(appData.font, fontPxlSize);
1889 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1890 countFontStruct = XQueryFont(xDisplay, countFontID);
1891 // appData.font = FindFont(appData.font, fontPxlSize);
1893 xdb = XtDatabase(xDisplay);
1894 XrmPutStringResource(&xdb, "*font", appData.font);
1897 * Detect if there are not enough colors available and adapt.
1899 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1900 appData.monoMode = True;
1903 if (!appData.monoMode) {
1904 vFrom.addr = (caddr_t) appData.lightSquareColor;
1905 vFrom.size = strlen(appData.lightSquareColor);
1906 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1907 if (vTo.addr == NULL) {
1908 appData.monoMode = True;
1911 lightSquareColor = *(Pixel *) vTo.addr;
1914 if (!appData.monoMode) {
1915 vFrom.addr = (caddr_t) appData.darkSquareColor;
1916 vFrom.size = strlen(appData.darkSquareColor);
1917 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918 if (vTo.addr == NULL) {
1919 appData.monoMode = True;
1922 darkSquareColor = *(Pixel *) vTo.addr;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.whitePieceColor;
1927 vFrom.size = strlen(appData.whitePieceColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 whitePieceColor = *(Pixel *) vTo.addr;
1936 if (!appData.monoMode) {
1937 vFrom.addr = (caddr_t) appData.blackPieceColor;
1938 vFrom.size = strlen(appData.blackPieceColor);
1939 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1940 if (vTo.addr == NULL) {
1941 appData.monoMode = True;
1944 blackPieceColor = *(Pixel *) vTo.addr;
1948 if (!appData.monoMode) {
1949 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1950 vFrom.size = strlen(appData.highlightSquareColor);
1951 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1952 if (vTo.addr == NULL) {
1953 appData.monoMode = True;
1956 highlightSquareColor = *(Pixel *) vTo.addr;
1960 if (!appData.monoMode) {
1961 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1962 vFrom.size = strlen(appData.premoveHighlightColor);
1963 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1964 if (vTo.addr == NULL) {
1965 appData.monoMode = True;
1968 premoveHighlightColor = *(Pixel *) vTo.addr;
1973 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1976 if (appData.bitmapDirectory == NULL ||
1977 appData.bitmapDirectory[0] == NULLCHAR)
1978 appData.bitmapDirectory = DEF_BITMAP_DIR;
1981 if (appData.lowTimeWarning && !appData.monoMode) {
1982 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1983 vFrom.size = strlen(appData.lowTimeWarningColor);
1984 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1985 if (vTo.addr == NULL)
1986 appData.monoMode = True;
1988 lowTimeWarningColor = *(Pixel *) vTo.addr;
1991 if (appData.monoMode && appData.debugMode) {
1992 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1993 (unsigned long) XWhitePixel(xDisplay, xScreen),
1994 (unsigned long) XBlackPixel(xDisplay, xScreen));
1997 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1998 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1999 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2000 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2001 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2002 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2003 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2004 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2005 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2006 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2008 if (appData.colorize) {
2010 _("%s: can't parse color names; disabling colorization\n"),
2013 appData.colorize = FALSE;
2015 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2016 textColors[ColorNone].attr = 0;
2018 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2024 layoutName = "tinyLayout";
2025 } else if (smallLayout) {
2026 layoutName = "smallLayout";
2028 layoutName = "normalLayout";
2030 /* Outer layoutWidget is there only to provide a name for use in
2031 resources that depend on the layout style */
2033 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2034 layoutArgs, XtNumber(layoutArgs));
2036 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2037 formArgs, XtNumber(formArgs));
2038 XtSetArg(args[0], XtNdefaultDistance, &sep);
2039 XtGetValues(formWidget, args, 1);
2042 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2043 XtSetArg(args[0], XtNtop, XtChainTop);
2044 XtSetArg(args[1], XtNbottom, XtChainTop);
2045 XtSetArg(args[2], XtNright, XtChainLeft);
2046 XtSetValues(menuBarWidget, args, 3);
2048 widgetList[j++] = whiteTimerWidget =
2049 XtCreateWidget("whiteTime", labelWidgetClass,
2050 formWidget, timerArgs, XtNumber(timerArgs));
2051 XtSetArg(args[0], XtNfont, clockFontStruct);
2052 XtSetArg(args[1], XtNtop, XtChainTop);
2053 XtSetArg(args[2], XtNbottom, XtChainTop);
2054 XtSetValues(whiteTimerWidget, args, 3);
2056 widgetList[j++] = blackTimerWidget =
2057 XtCreateWidget("blackTime", labelWidgetClass,
2058 formWidget, timerArgs, XtNumber(timerArgs));
2059 XtSetArg(args[0], XtNfont, clockFontStruct);
2060 XtSetArg(args[1], XtNtop, XtChainTop);
2061 XtSetArg(args[2], XtNbottom, XtChainTop);
2062 XtSetValues(blackTimerWidget, args, 3);
2064 if (appData.titleInWindow) {
2065 widgetList[j++] = titleWidget =
2066 XtCreateWidget("title", labelWidgetClass, formWidget,
2067 titleArgs, XtNumber(titleArgs));
2068 XtSetArg(args[0], XtNtop, XtChainTop);
2069 XtSetArg(args[1], XtNbottom, XtChainTop);
2070 XtSetValues(titleWidget, args, 2);
2073 if (appData.showButtonBar) {
2074 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2075 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2076 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2077 XtSetArg(args[2], XtNtop, XtChainTop);
2078 XtSetArg(args[3], XtNbottom, XtChainTop);
2079 XtSetValues(buttonBarWidget, args, 4);
2082 widgetList[j++] = messageWidget =
2083 XtCreateWidget("message", labelWidgetClass, formWidget,
2084 messageArgs, XtNumber(messageArgs));
2085 XtSetArg(args[0], XtNtop, XtChainTop);
2086 XtSetArg(args[1], XtNbottom, XtChainTop);
2087 XtSetValues(messageWidget, args, 2);
2089 widgetList[j++] = boardWidget =
2090 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2091 XtNumber(boardArgs));
2093 XtManageChildren(widgetList, j);
2095 timerWidth = (boardWidth - sep) / 2;
2096 XtSetArg(args[0], XtNwidth, timerWidth);
2097 XtSetValues(whiteTimerWidget, args, 1);
2098 XtSetValues(blackTimerWidget, args, 1);
2100 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2101 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2102 XtGetValues(whiteTimerWidget, args, 2);
2104 if (appData.showButtonBar) {
2105 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2106 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2107 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2111 * formWidget uses these constraints but they are stored
2115 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2116 XtSetValues(menuBarWidget, args, i);
2117 if (appData.titleInWindow) {
2120 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2121 XtSetValues(whiteTimerWidget, args, i);
2123 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2124 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2125 XtSetValues(blackTimerWidget, args, i);
2127 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2128 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2129 XtSetValues(titleWidget, args, i);
2131 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2132 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2133 XtSetValues(messageWidget, args, i);
2134 if (appData.showButtonBar) {
2136 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2137 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2138 XtSetValues(buttonBarWidget, args, i);
2142 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2143 XtSetValues(whiteTimerWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2146 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2147 XtSetValues(blackTimerWidget, args, i);
2149 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2150 XtSetValues(titleWidget, args, i);
2152 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2153 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2154 XtSetValues(messageWidget, args, i);
2155 if (appData.showButtonBar) {
2157 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2158 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2159 XtSetValues(buttonBarWidget, args, i);
2164 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2165 XtSetValues(whiteTimerWidget, args, i);
2167 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2168 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2169 XtSetValues(blackTimerWidget, args, i);
2171 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2172 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2173 XtSetValues(messageWidget, args, i);
2174 if (appData.showButtonBar) {
2176 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2177 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2178 XtSetValues(buttonBarWidget, args, i);
2182 XtSetArg(args[0], XtNfromVert, messageWidget);
2183 XtSetArg(args[1], XtNtop, XtChainTop);
2184 XtSetArg(args[2], XtNbottom, XtChainBottom);
2185 XtSetArg(args[3], XtNleft, XtChainLeft);
2186 XtSetArg(args[4], XtNright, XtChainRight);
2187 XtSetValues(boardWidget, args, 5);
2189 XtRealizeWidget(shellWidget);
2192 XtSetArg(args[0], XtNx, wpMain.x);
2193 XtSetArg(args[1], XtNy, wpMain.y);
2194 XtSetValues(shellWidget, args, 2);
2198 * Correct the width of the message and title widgets.
2199 * It is not known why some systems need the extra fudge term.
2200 * The value "2" is probably larger than needed.
2202 XawFormDoLayout(formWidget, False);
2204 #define WIDTH_FUDGE 2
2206 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2207 XtSetArg(args[i], XtNheight, &h); i++;
2208 XtGetValues(messageWidget, args, i);
2209 if (appData.showButtonBar) {
2211 XtSetArg(args[i], XtNwidth, &w); i++;
2212 XtGetValues(buttonBarWidget, args, i);
2213 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2215 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2218 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2219 if (gres != XtGeometryYes && appData.debugMode) {
2220 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2221 programName, gres, w, h, wr, hr);
2224 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2225 /* The size used for the child widget in layout lags one resize behind
2226 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2228 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2229 if (gres != XtGeometryYes && appData.debugMode) {
2230 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2231 programName, gres, w, h, wr, hr);
2234 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2235 XtSetArg(args[1], XtNright, XtChainRight);
2236 XtSetValues(messageWidget, args, 2);
2238 if (appData.titleInWindow) {
2240 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2241 XtSetArg(args[i], XtNheight, &h); i++;
2242 XtGetValues(titleWidget, args, i);
2244 w = boardWidth - 2*bor;
2246 XtSetArg(args[0], XtNwidth, &w);
2247 XtGetValues(menuBarWidget, args, 1);
2248 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2251 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2252 if (gres != XtGeometryYes && appData.debugMode) {
2254 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2255 programName, gres, w, h, wr, hr);
2258 XawFormDoLayout(formWidget, True);
2260 xBoardWindow = XtWindow(boardWidget);
2262 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2263 // not need to go into InitDrawingSizes().
2267 * Create X checkmark bitmap and initialize option menu checks.
2269 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2270 checkmark_bits, checkmark_width, checkmark_height);
2271 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2272 if (appData.alwaysPromoteToQueen) {
2273 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2276 if (appData.animateDragging) {
2277 XtSetValues(XtNameToWidget(menuBarWidget,
2278 "menuOptions.Animate Dragging"),
2281 if (appData.animate) {
2282 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2285 if (appData.autoComment) {
2286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2289 if (appData.autoCallFlag) {
2290 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2293 if (appData.autoFlipView) {
2294 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2297 if (appData.autoObserve) {
2298 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2301 if (appData.autoRaiseBoard) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Auto Raise Board"), args, 1);
2305 if (appData.autoSaveGames) {
2306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2309 if (appData.saveGameFile[0] != NULLCHAR) {
2310 /* Can't turn this off from menu */
2311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2313 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2317 if (appData.blindfold) {
2318 XtSetValues(XtNameToWidget(menuBarWidget,
2319 "menuOptions.Blindfold"), args, 1);
2321 if (appData.flashCount > 0) {
2322 XtSetValues(XtNameToWidget(menuBarWidget,
2323 "menuOptions.Flash Moves"),
2326 if (appData.getMoveList) {
2327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2331 if (appData.highlightDragging) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Highlight Dragging"),
2337 if (appData.highlightLastMove) {
2338 XtSetValues(XtNameToWidget(menuBarWidget,
2339 "menuOptions.Highlight Last Move"),
2342 if (appData.icsAlarm) {
2343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2346 if (appData.ringBellAfterMoves) {
2347 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2350 if (appData.oldSaveStyle) {
2351 XtSetValues(XtNameToWidget(menuBarWidget,
2352 "menuOptions.Old Save Style"), args, 1);
2354 if (appData.periodicUpdates) {
2355 XtSetValues(XtNameToWidget(menuBarWidget,
2356 "menuOptions.Periodic Updates"), args, 1);
2358 if (appData.ponderNextMove) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,
2360 "menuOptions.Ponder Next Move"), args, 1);
2362 if (appData.popupExitMessage) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,
2364 "menuOptions.Popup Exit Message"), args, 1);
2366 if (appData.popupMoveErrors) {
2367 XtSetValues(XtNameToWidget(menuBarWidget,
2368 "menuOptions.Popup Move Errors"), args, 1);
2370 if (appData.premove) {
2371 XtSetValues(XtNameToWidget(menuBarWidget,
2372 "menuOptions.Premove"), args, 1);
2374 if (appData.quietPlay) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,
2376 "menuOptions.Quiet Play"), args, 1);
2378 if (appData.showCoords) {
2379 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2382 if (appData.hideThinkingFromHuman) {
2383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2386 if (appData.testLegality) {
2387 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2390 if (saveSettingsOnExit) {
2391 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2398 ReadBitmap(&wIconPixmap, "icon_white.bm",
2399 icon_white_bits, icon_white_width, icon_white_height);
2400 ReadBitmap(&bIconPixmap, "icon_black.bm",
2401 icon_black_bits, icon_black_width, icon_black_height);
2402 iconPixmap = wIconPixmap;
2404 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2405 XtSetValues(shellWidget, args, i);
2408 * Create a cursor for the board widget.
2410 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2411 XChangeWindowAttributes(xDisplay, xBoardWindow,
2412 CWCursor, &window_attributes);
2415 * Inhibit shell resizing.
2417 shellArgs[0].value = (XtArgVal) &w;
2418 shellArgs[1].value = (XtArgVal) &h;
2419 XtGetValues(shellWidget, shellArgs, 2);
2420 shellArgs[4].value = shellArgs[2].value = w;
2421 shellArgs[5].value = shellArgs[3].value = h;
2422 XtSetValues(shellWidget, &shellArgs[2], 4);
2423 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2424 marginH = h - boardHeight;
2426 CatchDeleteWindow(shellWidget, "QuitProc");
2431 if (appData.bitmapDirectory[0] != NULLCHAR) {
2438 /* Create regular pieces */
2439 if (!useImages) CreatePieces();
2444 if (appData.animate || appData.animateDragging)
2447 XtAugmentTranslations(formWidget,
2448 XtParseTranslationTable(globalTranslations));
2449 XtAugmentTranslations(boardWidget,
2450 XtParseTranslationTable(boardTranslations));
2451 XtAugmentTranslations(whiteTimerWidget,
2452 XtParseTranslationTable(whiteTranslations));
2453 XtAugmentTranslations(blackTimerWidget,
2454 XtParseTranslationTable(blackTranslations));
2456 /* Why is the following needed on some versions of X instead
2457 * of a translation? */
2458 XtAddEventHandler(boardWidget, ExposureMask, False,
2459 (XtEventHandler) EventProc, NULL);
2464 if (errorExitStatus == -1) {
2465 if (appData.icsActive) {
2466 /* We now wait until we see "login:" from the ICS before
2467 sending the logon script (problems with timestamp otherwise) */
2468 /*ICSInitScript();*/
2469 if (appData.icsInputBox) ICSInputBoxPopUp();
2473 signal(SIGWINCH, TermSizeSigHandler);
2475 signal(SIGINT, IntSigHandler);
2476 signal(SIGTERM, IntSigHandler);
2477 if (*appData.cmailGameName != NULLCHAR) {
2478 signal(SIGUSR1, CmailSigHandler);
2481 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2484 XtAppMainLoop(appContext);
2485 if (appData.debugMode) fclose(debugFP); // [DM] debug
2492 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2493 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2495 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2496 unlink(gameCopyFilename);
2497 unlink(gamePasteFilename);
2500 RETSIGTYPE TermSizeSigHandler(int sig)
2513 CmailSigHandler(sig)
2519 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2521 /* Activate call-back function CmailSigHandlerCallBack() */
2522 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2524 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2528 CmailSigHandlerCallBack(isr, closure, message, count, error)
2536 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2538 /**** end signal code ****/
2548 f = fopen(appData.icsLogon, "r");
2554 strcat(buf, appData.icsLogon);
2555 f = fopen(buf, "r");
2559 ProcessICSInitScript(f);
2566 EditCommentPopDown();
2581 if (!menuBarWidget) return;
2582 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2584 DisplayError("menuStep.Revert", 0);
2586 XtSetSensitive(w, !grey);
2591 SetMenuEnables(enab)
2595 if (!menuBarWidget) return;
2596 while (enab->name != NULL) {
2597 w = XtNameToWidget(menuBarWidget, enab->name);
2599 DisplayError(enab->name, 0);
2601 XtSetSensitive(w, enab->value);
2607 Enables icsEnables[] = {
2608 { "menuFile.Mail Move", False },
2609 { "menuFile.Reload CMail Message", False },
2610 { "menuMode.Machine Black", False },
2611 { "menuMode.Machine White", False },
2612 { "menuMode.Analysis Mode", False },
2613 { "menuMode.Analyze File", False },
2614 { "menuMode.Two Machines", False },
2616 { "menuHelp.Hint", False },
2617 { "menuHelp.Book", False },
2618 { "menuStep.Move Now", False },
2619 { "menuOptions.Periodic Updates", False },
2620 { "menuOptions.Hide Thinking", False },
2621 { "menuOptions.Ponder Next Move", False },
2626 Enables ncpEnables[] = {
2627 { "menuFile.Mail Move", False },
2628 { "menuFile.Reload CMail Message", False },
2629 { "menuMode.Machine White", False },
2630 { "menuMode.Machine Black", False },
2631 { "menuMode.Analysis Mode", False },
2632 { "menuMode.Analyze File", False },
2633 { "menuMode.Two Machines", False },
2634 { "menuMode.ICS Client", False },
2635 { "menuMode.ICS Input Box", False },
2636 { "Action", False },
2637 { "menuStep.Revert", False },
2638 { "menuStep.Move Now", False },
2639 { "menuStep.Retract Move", False },
2640 { "menuOptions.Auto Comment", False },
2641 { "menuOptions.Auto Flag", False },
2642 { "menuOptions.Auto Flip View", False },
2643 { "menuOptions.Auto Observe", False },
2644 { "menuOptions.Auto Raise Board", False },
2645 { "menuOptions.Get Move List", False },
2646 { "menuOptions.ICS Alarm", False },
2647 { "menuOptions.Move Sound", False },
2648 { "menuOptions.Quiet Play", False },
2649 { "menuOptions.Hide Thinking", False },
2650 { "menuOptions.Periodic Updates", False },
2651 { "menuOptions.Ponder Next Move", False },
2652 { "menuHelp.Hint", False },
2653 { "menuHelp.Book", False },
2657 Enables gnuEnables[] = {
2658 { "menuMode.ICS Client", False },
2659 { "menuMode.ICS Input Box", False },
2660 { "menuAction.Accept", False },
2661 { "menuAction.Decline", False },
2662 { "menuAction.Rematch", False },
2663 { "menuAction.Adjourn", False },
2664 { "menuAction.Stop Examining", False },
2665 { "menuAction.Stop Observing", False },
2666 { "menuStep.Revert", False },
2667 { "menuOptions.Auto Comment", False },
2668 { "menuOptions.Auto Observe", False },
2669 { "menuOptions.Auto Raise Board", False },
2670 { "menuOptions.Get Move List", False },
2671 { "menuOptions.Premove", False },
2672 { "menuOptions.Quiet Play", False },
2674 /* The next two options rely on SetCmailMode being called *after* */
2675 /* SetGNUMode so that when GNU is being used to give hints these */
2676 /* menu options are still available */
2678 { "menuFile.Mail Move", False },
2679 { "menuFile.Reload CMail Message", False },
2683 Enables cmailEnables[] = {
2685 { "menuAction.Call Flag", False },
2686 { "menuAction.Draw", True },
2687 { "menuAction.Adjourn", False },
2688 { "menuAction.Abort", False },
2689 { "menuAction.Stop Observing", False },
2690 { "menuAction.Stop Examining", False },
2691 { "menuFile.Mail Move", True },
2692 { "menuFile.Reload CMail Message", True },
2696 Enables trainingOnEnables[] = {
2697 { "menuMode.Edit Comment", False },
2698 { "menuMode.Pause", False },
2699 { "menuStep.Forward", False },
2700 { "menuStep.Backward", False },
2701 { "menuStep.Forward to End", False },
2702 { "menuStep.Back to Start", False },
2703 { "menuStep.Move Now", False },
2704 { "menuStep.Truncate Game", False },
2708 Enables trainingOffEnables[] = {
2709 { "menuMode.Edit Comment", True },
2710 { "menuMode.Pause", True },
2711 { "menuStep.Forward", True },
2712 { "menuStep.Backward", True },
2713 { "menuStep.Forward to End", True },
2714 { "menuStep.Back to Start", True },
2715 { "menuStep.Move Now", True },
2716 { "menuStep.Truncate Game", True },
2720 Enables machineThinkingEnables[] = {
2721 { "menuFile.Load Game", False },
2722 { "menuFile.Load Next Game", False },
2723 { "menuFile.Load Previous Game", False },
2724 { "menuFile.Reload Same Game", False },
2725 { "menuFile.Paste Game", False },
2726 { "menuFile.Load Position", False },
2727 { "menuFile.Load Next Position", False },
2728 { "menuFile.Load Previous Position", False },
2729 { "menuFile.Reload Same Position", False },
2730 { "menuFile.Paste Position", False },
2731 { "menuMode.Machine White", False },
2732 { "menuMode.Machine Black", False },
2733 { "menuMode.Two Machines", False },
2734 { "menuStep.Retract Move", False },
2738 Enables userThinkingEnables[] = {
2739 { "menuFile.Load Game", True },
2740 { "menuFile.Load Next Game", True },
2741 { "menuFile.Load Previous Game", True },
2742 { "menuFile.Reload Same Game", True },
2743 { "menuFile.Paste Game", True },
2744 { "menuFile.Load Position", True },
2745 { "menuFile.Load Next Position", True },
2746 { "menuFile.Load Previous Position", True },
2747 { "menuFile.Reload Same Position", True },
2748 { "menuFile.Paste Position", True },
2749 { "menuMode.Machine White", True },
2750 { "menuMode.Machine Black", True },
2751 { "menuMode.Two Machines", True },
2752 { "menuStep.Retract Move", True },
2758 SetMenuEnables(icsEnables);
2761 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2762 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2769 SetMenuEnables(ncpEnables);
2775 SetMenuEnables(gnuEnables);
2781 SetMenuEnables(cmailEnables);
2787 SetMenuEnables(trainingOnEnables);
2788 if (appData.showButtonBar) {
2789 XtSetSensitive(buttonBarWidget, False);
2795 SetTrainingModeOff()
2797 SetMenuEnables(trainingOffEnables);
2798 if (appData.showButtonBar) {
2799 XtSetSensitive(buttonBarWidget, True);
2804 SetUserThinkingEnables()
2806 if (appData.noChessProgram) return;
2807 SetMenuEnables(userThinkingEnables);
2811 SetMachineThinkingEnables()
2813 if (appData.noChessProgram) return;
2814 SetMenuEnables(machineThinkingEnables);
2816 case MachinePlaysBlack:
2817 case MachinePlaysWhite:
2818 case TwoMachinesPlay:
2819 XtSetSensitive(XtNameToWidget(menuBarWidget,
2820 ModeToWidgetName(gameMode)), True);
2827 #define Abs(n) ((n)<0 ? -(n) : (n))
2830 * Find a font that matches "pattern" that is as close as
2831 * possible to the targetPxlSize. Prefer fonts that are k
2832 * pixels smaller to fonts that are k pixels larger. The
2833 * pattern must be in the X Consortium standard format,
2834 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2835 * The return value should be freed with XtFree when no
2838 char *FindFont(pattern, targetPxlSize)
2842 char **fonts, *p, *best, *scalable, *scalableTail;
2843 int i, j, nfonts, minerr, err, pxlSize;
2846 char **missing_list;
2848 char *def_string, *base_fnt_lst, strInt[3];
2850 XFontStruct **fnt_list;
2852 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2853 sprintf(strInt, "%d", targetPxlSize);
2854 p = strstr(pattern, "--");
2855 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2856 strcat(base_fnt_lst, strInt);
2857 strcat(base_fnt_lst, strchr(p + 2, '-'));
2859 if ((fntSet = XCreateFontSet(xDisplay,
2863 &def_string)) == NULL) {
2865 fprintf(stderr, _("Unable to create font set.\n"));
2869 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2871 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2873 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2874 programName, pattern);
2882 for (i=0; i<nfonts; i++) {
2885 if (*p != '-') continue;
2887 if (*p == NULLCHAR) break;
2888 if (*p++ == '-') j++;
2890 if (j < 7) continue;
2893 scalable = fonts[i];
2896 err = pxlSize - targetPxlSize;
2897 if (Abs(err) < Abs(minerr) ||
2898 (minerr > 0 && err < 0 && -err == minerr)) {
2904 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2905 /* If the error is too big and there is a scalable font,
2906 use the scalable font. */
2907 int headlen = scalableTail - scalable;
2908 p = (char *) XtMalloc(strlen(scalable) + 10);
2909 while (isdigit(*scalableTail)) scalableTail++;
2910 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2912 p = (char *) XtMalloc(strlen(best) + 1);
2915 if (appData.debugMode) {
2916 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2917 pattern, targetPxlSize, p);
2920 if (missing_count > 0)
2921 XFreeStringList(missing_list);
2922 XFreeFontSet(xDisplay, fntSet);
2924 XFreeFontNames(fonts);
2931 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2932 | GCBackground | GCFunction | GCPlaneMask;
2933 XGCValues gc_values;
2936 gc_values.plane_mask = AllPlanes;
2937 gc_values.line_width = lineGap;
2938 gc_values.line_style = LineSolid;
2939 gc_values.function = GXcopy;
2941 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2942 gc_values.background = XBlackPixel(xDisplay, xScreen);
2943 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2945 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2946 gc_values.background = XWhitePixel(xDisplay, xScreen);
2947 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2948 XSetFont(xDisplay, coordGC, coordFontID);
2950 // [HGM] make font for holdings counts (white on black0
2951 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2952 gc_values.background = XBlackPixel(xDisplay, xScreen);
2953 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2954 XSetFont(xDisplay, countGC, countFontID);
2956 if (appData.monoMode) {
2957 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2958 gc_values.background = XWhitePixel(xDisplay, xScreen);
2959 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2961 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2962 gc_values.background = XBlackPixel(xDisplay, xScreen);
2963 lightSquareGC = wbPieceGC
2964 = XtGetGC(shellWidget, value_mask, &gc_values);
2966 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2967 gc_values.background = XWhitePixel(xDisplay, xScreen);
2968 darkSquareGC = bwPieceGC
2969 = XtGetGC(shellWidget, value_mask, &gc_values);
2971 if (DefaultDepth(xDisplay, xScreen) == 1) {
2972 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2973 gc_values.function = GXcopyInverted;
2974 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2975 gc_values.function = GXcopy;
2976 if (XBlackPixel(xDisplay, xScreen) == 1) {
2977 bwPieceGC = darkSquareGC;
2978 wbPieceGC = copyInvertedGC;
2980 bwPieceGC = copyInvertedGC;
2981 wbPieceGC = lightSquareGC;
2985 gc_values.foreground = highlightSquareColor;
2986 gc_values.background = highlightSquareColor;
2987 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.foreground = premoveHighlightColor;
2990 gc_values.background = premoveHighlightColor;
2991 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2993 gc_values.foreground = lightSquareColor;
2994 gc_values.background = darkSquareColor;
2995 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2997 gc_values.foreground = darkSquareColor;
2998 gc_values.background = lightSquareColor;
2999 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3001 gc_values.foreground = jailSquareColor;
3002 gc_values.background = jailSquareColor;
3003 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3005 gc_values.foreground = whitePieceColor;
3006 gc_values.background = darkSquareColor;
3007 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3009 gc_values.foreground = whitePieceColor;
3010 gc_values.background = lightSquareColor;
3011 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3013 gc_values.foreground = whitePieceColor;
3014 gc_values.background = jailSquareColor;
3015 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 gc_values.foreground = blackPieceColor;
3018 gc_values.background = darkSquareColor;
3019 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3021 gc_values.foreground = blackPieceColor;
3022 gc_values.background = lightSquareColor;
3023 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 gc_values.foreground = blackPieceColor;
3026 gc_values.background = jailSquareColor;
3027 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3031 void loadXIM(xim, xmask, filename, dest, mask)
3044 fp = fopen(filename, "rb");
3046 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3053 for (y=0; y<h; ++y) {
3054 for (x=0; x<h; ++x) {
3059 XPutPixel(xim, x, y, blackPieceColor);
3061 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3064 XPutPixel(xim, x, y, darkSquareColor);
3066 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3069 XPutPixel(xim, x, y, whitePieceColor);
3071 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3074 XPutPixel(xim, x, y, lightSquareColor);
3076 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3082 /* create Pixmap of piece */
3083 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3085 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3088 /* create Pixmap of clipmask
3089 Note: We assume the white/black pieces have the same
3090 outline, so we make only 6 masks. This is okay
3091 since the XPM clipmask routines do the same. */
3093 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3095 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3098 /* now create the 1-bit version */
3099 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3102 values.foreground = 1;
3103 values.background = 0;
3105 /* Don't use XtGetGC, not read only */
3106 maskGC = XCreateGC(xDisplay, *mask,
3107 GCForeground | GCBackground, &values);
3108 XCopyPlane(xDisplay, temp, *mask, maskGC,
3109 0, 0, squareSize, squareSize, 0, 0, 1);
3110 XFreePixmap(xDisplay, temp);
3115 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3117 void CreateXIMPieces()
3122 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3127 /* The XSynchronize calls were copied from CreatePieces.
3128 Not sure if needed, but can't hurt */
3129 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3132 /* temp needed by loadXIM() */
3133 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3134 0, 0, ss, ss, AllPlanes, XYPixmap);
3136 if (strlen(appData.pixmapDirectory) == 0) {
3140 if (appData.monoMode) {
3141 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3145 fprintf(stderr, _("\nLoading XIMs...\n"));
3147 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3148 fprintf(stderr, "%d", piece+1);
3149 for (kind=0; kind<4; kind++) {
3150 fprintf(stderr, ".");
3151 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3152 ExpandPathName(appData.pixmapDirectory),
3153 piece <= (int) WhiteKing ? "" : "w",
3154 pieceBitmapNames[piece],
3156 ximPieceBitmap[kind][piece] =
3157 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3158 0, 0, ss, ss, AllPlanes, XYPixmap);
3159 if (appData.debugMode)
3160 fprintf(stderr, _("(File:%s:) "), buf);
3161 loadXIM(ximPieceBitmap[kind][piece],
3163 &(xpmPieceBitmap2[kind][piece]),
3164 &(ximMaskPm2[piece]));
3165 if(piece <= (int)WhiteKing)
3166 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3168 fprintf(stderr," ");
3170 /* Load light and dark squares */
3171 /* If the LSQ and DSQ pieces don't exist, we will
3172 draw them with solid squares. */
3173 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3174 if (access(buf, 0) != 0) {
3178 fprintf(stderr, _("light square "));
3180 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3181 0, 0, ss, ss, AllPlanes, XYPixmap);
3182 if (appData.debugMode)
3183 fprintf(stderr, _("(File:%s:) "), buf);
3185 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3186 fprintf(stderr, _("dark square "));
3187 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3188 ExpandPathName(appData.pixmapDirectory), ss);
3189 if (appData.debugMode)
3190 fprintf(stderr, _("(File:%s:) "), buf);
3192 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3193 0, 0, ss, ss, AllPlanes, XYPixmap);
3194 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3195 xpmJailSquare = xpmLightSquare;
3197 fprintf(stderr, _("Done.\n"));
3199 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3203 void CreateXPMPieces()
3207 u_int ss = squareSize;
3209 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3210 XpmColorSymbol symbols[4];
3212 /* The XSynchronize calls were copied from CreatePieces.
3213 Not sure if needed, but can't hurt */
3214 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3216 /* Setup translations so piece colors match square colors */
3217 symbols[0].name = "light_piece";
3218 symbols[0].value = appData.whitePieceColor;
3219 symbols[1].name = "dark_piece";
3220 symbols[1].value = appData.blackPieceColor;
3221 symbols[2].name = "light_square";
3222 symbols[2].value = appData.lightSquareColor;
3223 symbols[3].name = "dark_square";
3224 symbols[3].value = appData.darkSquareColor;
3226 attr.valuemask = XpmColorSymbols;
3227 attr.colorsymbols = symbols;
3228 attr.numsymbols = 4;
3230 if (appData.monoMode) {
3231 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3235 if (strlen(appData.pixmapDirectory) == 0) {
3236 XpmPieces* pieces = builtInXpms;
3239 while (pieces->size != squareSize && pieces->size) pieces++;
3240 if (!pieces->size) {
3241 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3244 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3245 for (kind=0; kind<4; kind++) {
3247 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3248 pieces->xpm[piece][kind],
3249 &(xpmPieceBitmap2[kind][piece]),
3250 NULL, &attr)) != 0) {
3251 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3255 if(piece <= (int) WhiteKing)
3256 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3260 xpmJailSquare = xpmLightSquare;
3264 fprintf(stderr, _("\nLoading XPMs...\n"));
3267 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3268 fprintf(stderr, "%d ", piece+1);
3269 for (kind=0; kind<4; kind++) {
3270 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3271 ExpandPathName(appData.pixmapDirectory),
3272 piece > (int) WhiteKing ? "w" : "",
3273 pieceBitmapNames[piece],
3275 if (appData.debugMode) {
3276 fprintf(stderr, _("(File:%s:) "), buf);
3278 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3279 &(xpmPieceBitmap2[kind][piece]),
3280 NULL, &attr)) != 0) {
3281 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3282 // [HGM] missing: read of unorthodox piece failed; substitute King.
3283 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3284 ExpandPathName(appData.pixmapDirectory),
3286 if (appData.debugMode) {
3287 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3289 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3290 &(xpmPieceBitmap2[kind][piece]),
3294 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3299 if(piece <= (int) WhiteKing)
3300 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3303 /* Load light and dark squares */
3304 /* If the LSQ and DSQ pieces don't exist, we will
3305 draw them with solid squares. */
3306 fprintf(stderr, _("light square "));
3307 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3308 if (access(buf, 0) != 0) {
3312 if (appData.debugMode)
3313 fprintf(stderr, _("(File:%s:) "), buf);
3315 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3316 &xpmLightSquare, NULL, &attr)) != 0) {
3317 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3320 fprintf(stderr, _("dark square "));
3321 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3322 ExpandPathName(appData.pixmapDirectory), ss);
3323 if (appData.debugMode) {
3324 fprintf(stderr, _("(File:%s:) "), buf);
3326 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3327 &xpmDarkSquare, NULL, &attr)) != 0) {
3328 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3332 xpmJailSquare = xpmLightSquare;
3333 fprintf(stderr, _("Done.\n"));
3335 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3338 #endif /* HAVE_LIBXPM */
3341 /* No built-in bitmaps */
3346 u_int ss = squareSize;
3348 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3351 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3352 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3353 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3354 pieceBitmapNames[piece],
3355 ss, kind == SOLID ? 's' : 'o');
3356 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3357 if(piece <= (int)WhiteKing)
3358 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3362 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3366 /* With built-in bitmaps */
3369 BuiltInBits* bib = builtInBits;
3372 u_int ss = squareSize;
3374 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3377 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3379 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3380 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3381 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3382 pieceBitmapNames[piece],
3383 ss, kind == SOLID ? 's' : 'o');
3384 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3385 bib->bits[kind][piece], ss, ss);
3386 if(piece <= (int)WhiteKing)
3387 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3391 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3396 void ReadBitmap(pm, name, bits, wreq, hreq)
3399 unsigned char bits[];
3405 char msg[MSG_SIZ], fullname[MSG_SIZ];
3407 if (*appData.bitmapDirectory != NULLCHAR) {
3408 strcpy(fullname, appData.bitmapDirectory);
3409 strcat(fullname, "/");
3410 strcat(fullname, name);
3411 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3412 &w, &h, pm, &x_hot, &y_hot);
3413 fprintf(stderr, "load %s\n", name);
3414 if (errcode != BitmapSuccess) {
3416 case BitmapOpenFailed:
3417 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3419 case BitmapFileInvalid:
3420 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3422 case BitmapNoMemory:
3423 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3427 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3431 fprintf(stderr, _("%s: %s...using built-in\n"),
3433 } else if (w != wreq || h != hreq) {
3435 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3436 programName, fullname, w, h, wreq, hreq);
3442 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3451 if (lineGap == 0) return;
3453 /* [HR] Split this into 2 loops for non-square boards. */
3455 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3456 gridSegments[i].x1 = 0;
3457 gridSegments[i].x2 =
3458 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3459 gridSegments[i].y1 = gridSegments[i].y2
3460 = lineGap / 2 + (i * (squareSize + lineGap));
3463 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3464 gridSegments[j + i].y1 = 0;
3465 gridSegments[j + i].y2 =
3466 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3467 gridSegments[j + i].x1 = gridSegments[j + i].x2
3468 = lineGap / 2 + (j * (squareSize + lineGap));
3472 static void MenuBarSelect(w, addr, index)
3477 XtActionProc proc = (XtActionProc) addr;
3479 (proc)(NULL, NULL, NULL, NULL);
3482 void CreateMenuBarPopup(parent, name, mb)
3492 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3495 XtSetArg(args[j], XtNleftMargin, 20); j++;
3496 XtSetArg(args[j], XtNrightMargin, 20); j++;
3498 while (mi->string != NULL) {
3499 if (strcmp(mi->string, "----") == 0) {
3500 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3503 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3504 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3506 XtAddCallback(entry, XtNcallback,
3507 (XtCallbackProc) MenuBarSelect,
3508 (caddr_t) mi->proc);
3514 Widget CreateMenuBar(mb)
3518 Widget anchor, menuBar;
3520 char menuName[MSG_SIZ];
3523 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3524 XtSetArg(args[j], XtNvSpace, 0); j++;
3525 XtSetArg(args[j], XtNborderWidth, 0); j++;
3526 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3527 formWidget, args, j);
3529 while (mb->name != NULL) {
3530 strcpy(menuName, "menu");
3531 strcat(menuName, mb->name);
3533 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3536 shortName[0] = _(mb->name)[0];
3537 shortName[1] = NULLCHAR;
3538 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3541 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3544 XtSetArg(args[j], XtNborderWidth, 0); j++;
3545 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3547 CreateMenuBarPopup(menuBar, menuName, mb);
3553 Widget CreateButtonBar(mi)
3557 Widget button, buttonBar;
3561 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3563 XtSetArg(args[j], XtNhSpace, 0); j++;
3565 XtSetArg(args[j], XtNborderWidth, 0); j++;
3566 XtSetArg(args[j], XtNvSpace, 0); j++;
3567 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3568 formWidget, args, j);
3570 while (mi->string != NULL) {
3573 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3574 XtSetArg(args[j], XtNborderWidth, 0); j++;
3576 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3577 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3578 buttonBar, args, j);
3579 XtAddCallback(button, XtNcallback,
3580 (XtCallbackProc) MenuBarSelect,
3581 (caddr_t) mi->proc);
3588 CreatePieceMenu(name, color)
3595 ChessSquare selection;
3597 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3598 boardWidget, args, 0);
3600 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3601 String item = pieceMenuStrings[color][i];
3603 if (strcmp(item, "----") == 0) {
3604 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3607 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3608 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3610 selection = pieceMenuTranslation[color][i];
3611 XtAddCallback(entry, XtNcallback,
3612 (XtCallbackProc) PieceMenuSelect,
3613 (caddr_t) selection);
3614 if (selection == WhitePawn || selection == BlackPawn) {
3615 XtSetArg(args[0], XtNpopupOnEntry, entry);
3616 XtSetValues(menu, args, 1);
3629 ChessSquare selection;
3631 whitePieceMenu = CreatePieceMenu("menuW", 0);
3632 blackPieceMenu = CreatePieceMenu("menuB", 1);
3634 XtRegisterGrabAction(PieceMenuPopup, True,
3635 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3636 GrabModeAsync, GrabModeAsync);
3638 XtSetArg(args[0], XtNlabel, _("Drop"));
3639 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3640 boardWidget, args, 1);
3641 for (i = 0; i < DROP_MENU_SIZE; i++) {
3642 String item = dropMenuStrings[i];
3644 if (strcmp(item, "----") == 0) {
3645 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3648 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3649 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3651 selection = dropMenuTranslation[i];
3652 XtAddCallback(entry, XtNcallback,
3653 (XtCallbackProc) DropMenuSelect,
3654 (caddr_t) selection);
3659 void SetupDropMenu()
3667 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3668 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3669 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3670 dmEnables[i].piece);
3671 XtSetSensitive(entry, p != NULL || !appData.testLegality
3672 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3673 && !appData.icsActive));
3675 while (p && *p++ == dmEnables[i].piece) count++;
3676 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3678 XtSetArg(args[j], XtNlabel, label); j++;
3679 XtSetValues(entry, args, j);
3683 void PieceMenuPopup(w, event, params, num_params)
3687 Cardinal *num_params;
3690 if (event->type != ButtonPress) return;
3691 if (errorUp) ErrorPopDown();
3695 whichMenu = params[0];
3697 case IcsPlayingWhite:
3698 case IcsPlayingBlack:
3700 case MachinePlaysWhite:
3701 case MachinePlaysBlack:
3702 if (appData.testLegality &&
3703 gameInfo.variant != VariantBughouse &&
3704 gameInfo.variant != VariantCrazyhouse) return;
3706 whichMenu = "menuD";
3712 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3713 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3714 pmFromX = pmFromY = -1;
3718 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3720 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3722 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3725 static void PieceMenuSelect(w, piece, junk)
3730 if (pmFromX < 0 || pmFromY < 0) return;
3731 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3734 static void DropMenuSelect(w, piece, junk)
3739 if (pmFromX < 0 || pmFromY < 0) return;
3740 DropMenuEvent(piece, pmFromX, pmFromY);
3743 void WhiteClock(w, event, prms, nprms)
3749 if (gameMode == EditPosition || gameMode == IcsExamining) {
3750 SetWhiteToPlayEvent();
3751 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3756 void BlackClock(w, event, prms, nprms)
3762 if (gameMode == EditPosition || gameMode == IcsExamining) {
3763 SetBlackToPlayEvent();
3764 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3771 * If the user selects on a border boundary, return -1; if off the board,
3772 * return -2. Otherwise map the event coordinate to the square.
3774 int EventToSquare(x, limit)
3782 if ((x % (squareSize + lineGap)) >= squareSize)
3784 x /= (squareSize + lineGap);
3790 static void do_flash_delay(msec)
3796 static void drawHighlight(file, rank, gc)
3802 if (lineGap == 0 || appData.blindfold) return;
3805 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3806 (squareSize + lineGap);
3807 y = lineGap/2 + rank * (squareSize + lineGap);
3809 x = lineGap/2 + file * (squareSize + lineGap);
3810 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3811 (squareSize + lineGap);
3814 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3815 squareSize+lineGap, squareSize+lineGap);
3818 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3819 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3822 SetHighlights(fromX, fromY, toX, toY)
3823 int fromX, fromY, toX, toY;
3825 if (hi1X != fromX || hi1Y != fromY) {
3826 if (hi1X >= 0 && hi1Y >= 0) {
3827 drawHighlight(hi1X, hi1Y, lineGC);
3829 if (fromX >= 0 && fromY >= 0) {
3830 drawHighlight(fromX, fromY, highlineGC);
3833 if (hi2X != toX || hi2Y != toY) {
3834 if (hi2X >= 0 && hi2Y >= 0) {
3835 drawHighlight(hi2X, hi2Y, lineGC);
3837 if (toX >= 0 && toY >= 0) {
3838 drawHighlight(toX, toY, highlineGC);
3850 SetHighlights(-1, -1, -1, -1);
3855 SetPremoveHighlights(fromX, fromY, toX, toY)
3856 int fromX, fromY, toX, toY;
3858 if (pm1X != fromX || pm1Y != fromY) {
3859 if (pm1X >= 0 && pm1Y >= 0) {
3860 drawHighlight(pm1X, pm1Y, lineGC);
3862 if (fromX >= 0 && fromY >= 0) {
3863 drawHighlight(fromX, fromY, prelineGC);
3866 if (pm2X != toX || pm2Y != toY) {
3867 if (pm2X >= 0 && pm2Y >= 0) {
3868 drawHighlight(pm2X, pm2Y, lineGC);
3870 if (toX >= 0 && toY >= 0) {
3871 drawHighlight(toX, toY, prelineGC);
3881 ClearPremoveHighlights()
3883 SetPremoveHighlights(-1, -1, -1, -1);
3886 static void BlankSquare(x, y, color, piece, dest)
3891 if (useImages && useImageSqs) {
3895 pm = xpmLightSquare;
3900 case 2: /* neutral */
3905 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3906 squareSize, squareSize, x, y);
3916 case 2: /* neutral */
3921 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3926 I split out the routines to draw a piece so that I could
3927 make a generic flash routine.
3929 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3931 int square_color, x, y;
3934 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3935 switch (square_color) {
3937 case 2: /* neutral */
3939 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3940 ? *pieceToOutline(piece)
3941 : *pieceToSolid(piece),
3942 dest, bwPieceGC, 0, 0,
3943 squareSize, squareSize, x, y);
3946 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3947 ? *pieceToSolid(piece)
3948 : *pieceToOutline(piece),
3949 dest, wbPieceGC, 0, 0,
3950 squareSize, squareSize, x, y);
3955 static void monoDrawPiece(piece, square_color, x, y, dest)
3957 int square_color, x, y;
3960 switch (square_color) {
3962 case 2: /* neutral */
3964 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3965 ? *pieceToOutline(piece)
3966 : *pieceToSolid(piece),
3967 dest, bwPieceGC, 0, 0,
3968 squareSize, squareSize, x, y, 1);
3971 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3972 ? *pieceToSolid(piece)
3973 : *pieceToOutline(piece),
3974 dest, wbPieceGC, 0, 0,
3975 squareSize, squareSize, x, y, 1);
3980 static void colorDrawPiece(piece, square_color, x, y, dest)
3982 int square_color, x, y;
3985 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3986 switch (square_color) {
3988 XCopyPlane(xDisplay, *pieceToSolid(piece),
3989 dest, (int) piece < (int) BlackPawn
3990 ? wlPieceGC : blPieceGC, 0, 0,
3991 squareSize, squareSize, x, y, 1);
3994 XCopyPlane(xDisplay, *pieceToSolid(piece),
3995 dest, (int) piece < (int) BlackPawn
3996 ? wdPieceGC : bdPieceGC, 0, 0,
3997 squareSize, squareSize, x, y, 1);
3999 case 2: /* neutral */
4001 XCopyPlane(xDisplay, *pieceToSolid(piece),
4002 dest, (int) piece < (int) BlackPawn
4003 ? wjPieceGC : bjPieceGC, 0, 0,
4004 squareSize, squareSize, x, y, 1);
4009 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4011 int square_color, x, y;
4016 switch (square_color) {
4018 case 2: /* neutral */
4020 if ((int)piece < (int) BlackPawn) {
4028 if ((int)piece < (int) BlackPawn) {
4036 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4037 dest, wlPieceGC, 0, 0,
4038 squareSize, squareSize, x, y);
4041 typedef void (*DrawFunc)();
4043 DrawFunc ChooseDrawFunc()
4045 if (appData.monoMode) {
4046 if (DefaultDepth(xDisplay, xScreen) == 1) {
4047 return monoDrawPiece_1bit;
4049 return monoDrawPiece;
4053 return colorDrawPieceImage;
4055 return colorDrawPiece;
4059 /* [HR] determine square color depending on chess variant. */
4060 static int SquareColor(row, column)
4065 if (gameInfo.variant == VariantXiangqi) {
4066 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4068 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4070 } else if (row <= 4) {
4076 square_color = ((column + row) % 2) == 1;
4079 /* [hgm] holdings: next line makes all holdings squares light */
4080 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4082 return square_color;
4085 void DrawSquare(row, column, piece, do_flash)
4086 int row, column, do_flash;
4089 int square_color, x, y, direction, font_ascent, font_descent;
4092 XCharStruct overall;
4096 /* Calculate delay in milliseconds (2-delays per complete flash) */
4097 flash_delay = 500 / appData.flashRate;
4100 x = lineGap + ((BOARD_WIDTH-1)-column) *
4101 (squareSize + lineGap);
4102 y = lineGap + row * (squareSize + lineGap);
4104 x = lineGap + column * (squareSize + lineGap);
4105 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4106 (squareSize + lineGap);
4109 square_color = SquareColor(row, column);
4111 if ( // [HGM] holdings: blank out area between board and holdings
4112 column == BOARD_LEFT-1 || column == BOARD_RGHT
4113 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4114 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4115 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4117 // [HGM] print piece counts next to holdings
4118 string[1] = NULLCHAR;
4119 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4120 string[0] = '0' + piece;
4121 XTextExtents(countFontStruct, string, 1, &direction,
4122 &font_ascent, &font_descent, &overall);
4123 if (appData.monoMode) {
4124 XDrawImageString(xDisplay, xBoardWindow, countGC,
4125 x + squareSize - overall.width - 2,
4126 y + font_ascent + 1, string, 1);
4128 XDrawString(xDisplay, xBoardWindow, countGC,
4129 x + squareSize - overall.width - 2,
4130 y + font_ascent + 1, string, 1);
4133 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4134 string[0] = '0' + piece;
4135 XTextExtents(countFontStruct, string, 1, &direction,
4136 &font_ascent, &font_descent, &overall);
4137 if (appData.monoMode) {
4138 XDrawImageString(xDisplay, xBoardWindow, countGC,
4139 x + 2, y + font_ascent + 1, string, 1);
4141 XDrawString(xDisplay, xBoardWindow, countGC,
4142 x + 2, y + font_ascent + 1, string, 1);
4146 if (piece == EmptySquare || appData.blindfold) {
4147 BlankSquare(x, y, square_color, piece, xBoardWindow);
4149 drawfunc = ChooseDrawFunc();
4150 if (do_flash && appData.flashCount > 0) {
4151 for (i=0; i<appData.flashCount; ++i) {
4153 drawfunc(piece, square_color, x, y, xBoardWindow);
4154 XSync(xDisplay, False);
4155 do_flash_delay(flash_delay);
4157 BlankSquare(x, y, square_color, piece, xBoardWindow);
4158 XSync(xDisplay, False);
4159 do_flash_delay(flash_delay);
4162 drawfunc(piece, square_color, x, y, xBoardWindow);
4166 string[1] = NULLCHAR;
4167 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4168 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4169 string[0] = 'a' + column - BOARD_LEFT;
4170 XTextExtents(coordFontStruct, string, 1, &direction,
4171 &font_ascent, &font_descent, &overall);
4172 if (appData.monoMode) {
4173 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4174 x + squareSize - overall.width - 2,
4175 y + squareSize - font_descent - 1, string, 1);
4177 XDrawString(xDisplay, xBoardWindow, coordGC,
4178 x + squareSize - overall.width - 2,
4179 y + squareSize - font_descent - 1, string, 1);
4182 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4183 string[0] = ONE + row;
4184 XTextExtents(coordFontStruct, string, 1, &direction,
4185 &font_ascent, &font_descent, &overall);
4186 if (appData.monoMode) {
4187 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4188 x + 2, y + font_ascent + 1, string, 1);
4190 XDrawString(xDisplay, xBoardWindow, coordGC,
4191 x + 2, y + font_ascent + 1, string, 1);
4197 /* Why is this needed on some versions of X? */
4198 void EventProc(widget, unused, event)
4203 if (!XtIsRealized(widget))
4206 switch (event->type) {
4208 if (event->xexpose.count > 0) return; /* no clipping is done */
4209 XDrawPosition(widget, True, NULL);
4217 void DrawPosition(fullRedraw, board)
4218 /*Boolean*/int fullRedraw;
4221 XDrawPosition(boardWidget, fullRedraw, board);
4224 /* Returns 1 if there are "too many" differences between b1 and b2
4225 (i.e. more than 1 move was made) */
4226 static int too_many_diffs(b1, b2)
4232 for (i=0; i<BOARD_HEIGHT; ++i) {
4233 for (j=0; j<BOARD_WIDTH; ++j) {
4234 if (b1[i][j] != b2[i][j]) {
4235 if (++c > 4) /* Castling causes 4 diffs */
4244 /* Matrix describing castling maneuvers */
4245 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4246 static int castling_matrix[4][5] = {
4247 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4248 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4249 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4250 { 7, 7, 4, 5, 6 } /* 0-0, black */
4253 /* Checks whether castling occurred. If it did, *rrow and *rcol
4254 are set to the destination (row,col) of the rook that moved.
4256 Returns 1 if castling occurred, 0 if not.
4258 Note: Only handles a max of 1 castling move, so be sure
4259 to call too_many_diffs() first.
4261 static int check_castle_draw(newb, oldb, rrow, rcol)
4268 /* For each type of castling... */
4269 for (i=0; i<4; ++i) {
4270 r = castling_matrix[i];
4272 /* Check the 4 squares involved in the castling move */
4274 for (j=1; j<=4; ++j) {
4275 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4282 /* All 4 changed, so it must be a castling move */
4291 static int damage[BOARD_RANKS][BOARD_FILES];
4294 * event handler for redrawing the board
4296 void XDrawPosition(w, repaint, board)
4298 /*Boolean*/int repaint;
4302 static int lastFlipView = 0;
4303 static int lastBoardValid = 0;
4304 static Board lastBoard;
4308 if (board == NULL) {
4309 if (!lastBoardValid) return;
4312 if (!lastBoardValid || lastFlipView != flipView) {
4313 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4314 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4319 * It would be simpler to clear the window with XClearWindow()
4320 * but this causes a very distracting flicker.
4323 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4325 /* If too much changes (begin observing new game, etc.), don't
4327 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4329 /* Special check for castling so we don't flash both the king
4330 and the rook (just flash the king). */
4332 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4333 /* Draw rook with NO flashing. King will be drawn flashing later */
4334 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4335 lastBoard[rrow][rcol] = board[rrow][rcol];
4339 /* First pass -- Draw (newly) empty squares and repair damage.
4340 This prevents you from having a piece show up twice while it
4341 is flashing on its new square */
4342 for (i = 0; i < BOARD_HEIGHT; i++)
4343 for (j = 0; j < BOARD_WIDTH; j++)
4344 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4346 DrawSquare(i, j, board[i][j], 0);
4347 damage[i][j] = False;
4350 /* Second pass -- Draw piece(s) in new position and flash them */
4351 for (i = 0; i < BOARD_HEIGHT; i++)
4352 for (j = 0; j < BOARD_WIDTH; j++)
4353 if (board[i][j] != lastBoard[i][j]) {
4354 DrawSquare(i, j, board[i][j], do_flash);
4358 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4359 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4361 for (i = 0; i < BOARD_HEIGHT; i++)
4362 for (j = 0; j < BOARD_WIDTH; j++) {
4363 DrawSquare(i, j, board[i][j], 0);
4364 damage[i][j] = False;
4368 CopyBoard(lastBoard, board);
4370 lastFlipView = flipView;
4372 /* Draw highlights */
4373 if (pm1X >= 0 && pm1Y >= 0) {
4374 drawHighlight(pm1X, pm1Y, prelineGC);
4376 if (pm2X >= 0 && pm2Y >= 0) {
4377 drawHighlight(pm2X, pm2Y, prelineGC);
4379 if (hi1X >= 0 && hi1Y >= 0) {
4380 drawHighlight(hi1X, hi1Y, highlineGC);
4382 if (hi2X >= 0 && hi2Y >= 0) {
4383 drawHighlight(hi2X, hi2Y, highlineGC);
4386 /* If piece being dragged around board, must redraw that too */
4389 XSync(xDisplay, False);
4394 * event handler for redrawing the board
4396 void DrawPositionProc(w, event, prms, nprms)
4402 XDrawPosition(w, True, NULL);
4407 * event handler for parsing user moves
4409 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4410 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4411 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4412 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4413 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4414 // and at the end FinishMove() to perform the move after optional promotion popups.
4415 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4416 void HandleUserMove(w, event, prms, nprms)
4422 if (w != boardWidget || errorExitStatus != -1) return;
4425 if (event->type == ButtonPress) {
4426 XtPopdown(promotionShell);
4427 XtDestroyWidget(promotionShell);
4428 promotionUp = False;
4436 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4437 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4438 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4441 void AnimateUserMove (Widget w, XEvent * event,
4442 String * params, Cardinal * nParams)
4444 DragPieceMove(event->xmotion.x, event->xmotion.y);
4447 Widget CommentCreate(name, text, mutable, callback, lines)
4449 int /*Boolean*/ mutable;
4450 XtCallbackProc callback;
4454 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4459 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4460 XtGetValues(boardWidget, args, j);
4463 XtSetArg(args[j], XtNresizable, True); j++;
4466 XtCreatePopupShell(name, topLevelShellWidgetClass,
4467 shellWidget, args, j);
4470 XtCreatePopupShell(name, transientShellWidgetClass,
4471 shellWidget, args, j);
4474 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4475 layoutArgs, XtNumber(layoutArgs));
4477 XtCreateManagedWidget("form", formWidgetClass, layout,
4478 formArgs, XtNumber(formArgs));
4482 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4483 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4485 XtSetArg(args[j], XtNstring, text); j++;
4486 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4487 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4488 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4489 XtSetArg(args[j], XtNright, XtChainRight); j++;
4490 XtSetArg(args[j], XtNresizable, True); j++;
4491 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4492 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4493 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4494 XtSetArg(args[j], XtNautoFill, True); j++;
4495 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4497 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4501 XtSetArg(args[j], XtNfromVert, edit); j++;
4502 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4503 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4504 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4505 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4507 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4508 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4511 XtSetArg(args[j], XtNfromVert, edit); j++;
4512 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4513 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4514 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4515 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4516 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4518 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4519 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4522 XtSetArg(args[j], XtNfromVert, edit); j++;
4523 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4524 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4525 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4526 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4527 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4529 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4530 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4533 XtSetArg(args[j], XtNfromVert, edit); j++;
4534 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4535 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4536 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4537 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4539 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4540 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4543 XtSetArg(args[j], XtNfromVert, edit); j++;
4544 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4545 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4546 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4547 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4548 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4550 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4551 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4554 XtRealizeWidget(shell);
4556 if (commentX == -1) {
4559 Dimension pw_height;
4560 Dimension ew_height;
4563 XtSetArg(args[j], XtNheight, &ew_height); j++;
4564 XtGetValues(edit, args, j);
4567 XtSetArg(args[j], XtNheight, &pw_height); j++;
4568 XtGetValues(shell, args, j);
4569 commentH = pw_height + (lines - 1) * ew_height;
4570 commentW = bw_width - 16;
4572 XSync(xDisplay, False);
4574 /* This code seems to tickle an X bug if it is executed too soon
4575 after xboard starts up. The coordinates get transformed as if
4576 the main window was positioned at (0, 0).
4578 XtTranslateCoords(shellWidget,
4579 (bw_width - commentW) / 2, 0 - commentH / 2,
4580 &commentX, &commentY);
4582 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4583 RootWindowOfScreen(XtScreen(shellWidget)),
4584 (bw_width - commentW) / 2, 0 - commentH / 2,
4589 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4592 if(wpComment.width > 0) {
4593 commentX = wpComment.x;
4594 commentY = wpComment.y;
4595 commentW = wpComment.width;
4596 commentH = wpComment.height;
4600 XtSetArg(args[j], XtNheight, commentH); j++;
4601 XtSetArg(args[j], XtNwidth, commentW); j++;
4602 XtSetArg(args[j], XtNx, commentX); j++;
4603 XtSetArg(args[j], XtNy, commentY); j++;
4604 XtSetValues(shell, args, j);
4605 XtSetKeyboardFocus(shell, edit);
4610 /* Used for analysis window and ICS input window */
4611 Widget MiscCreate(name, text, mutable, callback, lines)
4613 int /*Boolean*/ mutable;
4614 XtCallbackProc callback;
4618 Widget shell, layout, form, edit;
4620 Dimension bw_width, pw_height, ew_height, w, h;
4626 XtSetArg(args[j], XtNresizable, True); j++;
4629 XtCreatePopupShell(name, topLevelShellWidgetClass,
4630 shellWidget, args, j);
4633 XtCreatePopupShell(name, transientShellWidgetClass,
4634 shellWidget, args, j);
4637 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4638 layoutArgs, XtNumber(layoutArgs));
4640 XtCreateManagedWidget("form", formWidgetClass, layout,
4641 formArgs, XtNumber(formArgs));
4645 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4646 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4648 XtSetArg(args[j], XtNstring, text); j++;
4649 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4650 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4651 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4652 XtSetArg(args[j], XtNright, XtChainRight); j++;
4653 XtSetArg(args[j], XtNresizable, True); j++;
4654 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4655 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4656 XtSetArg(args[j], XtNautoFill, True); j++;
4657 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4659 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4661 XtRealizeWidget(shell);
4664 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4665 XtGetValues(boardWidget, args, j);
4668 XtSetArg(args[j], XtNheight, &ew_height); j++;
4669 XtGetValues(edit, args, j);
4672 XtSetArg(args[j], XtNheight, &pw_height); j++;
4673 XtGetValues(shell, args, j);
4674 h = pw_height + (lines - 1) * ew_height;
4677 XSync(xDisplay, False);
4679 /* This code seems to tickle an X bug if it is executed too soon
4680 after xboard starts up. The coordinates get transformed as if
4681 the main window was positioned at (0, 0).
4683 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4685 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4686 RootWindowOfScreen(XtScreen(shellWidget)),
4687 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4691 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4694 XtSetArg(args[j], XtNheight, h); j++;
4695 XtSetArg(args[j], XtNwidth, w); j++;
4696 XtSetArg(args[j], XtNx, x); j++;
4697 XtSetArg(args[j], XtNy, y); j++;
4698 XtSetValues(shell, args, j);
4704 static int savedIndex; /* gross that this is global */
4706 void EditCommentPopUp(index, title, text)
4715 if (text == NULL) text = "";
4717 if (editShell == NULL) {
4719 CommentCreate(title, text, True, EditCommentCallback, 4);
4720 XtRealizeWidget(editShell);
4721 CatchDeleteWindow(editShell, "EditCommentPopDown");
4723 edit = XtNameToWidget(editShell, "*form.text");
4725 XtSetArg(args[j], XtNstring, text); j++;
4726 XtSetValues(edit, args, j);
4728 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4729 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4730 XtSetValues(editShell, args, j);
4733 XtPopup(editShell, XtGrabNone);
4737 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4738 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4742 void EditCommentCallback(w, client_data, call_data)
4744 XtPointer client_data, call_data;
4752 XtSetArg(args[j], XtNlabel, &name); j++;
4753 XtGetValues(w, args, j);
4755 if (strcmp(name, _("ok")) == 0) {
4756 edit = XtNameToWidget(editShell, "*form.text");
4758 XtSetArg(args[j], XtNstring, &val); j++;
4759 XtGetValues(edit, args, j);
4760 ReplaceComment(savedIndex, val);
4761 EditCommentPopDown();
4762 } else if (strcmp(name, _("cancel")) == 0) {
4763 EditCommentPopDown();
4764 } else if (strcmp(name, _("clear")) == 0) {
4765 edit = XtNameToWidget(editShell, "*form.text");
4766 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4767 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4771 void EditCommentPopDown()
4776 if (!editUp) return;
4778 XtSetArg(args[j], XtNx, &commentX); j++;
4779 XtSetArg(args[j], XtNy, &commentY); j++;
4780 XtSetArg(args[j], XtNheight, &commentH); j++;
4781 XtSetArg(args[j], XtNwidth, &commentW); j++;
4782 XtGetValues(editShell, args, j);
4783 XtPopdown(editShell);
4786 XtSetArg(args[j], XtNleftBitmap, None); j++;
4787 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4791 void ICSInputBoxPopUp()
4796 char *title = _("ICS Input");
4799 if (ICSInputShell == NULL) {
4800 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4801 tr = XtParseTranslationTable(ICSInputTranslations);
4802 edit = XtNameToWidget(ICSInputShell, "*form.text");
4803 XtOverrideTranslations(edit, tr);
4804 XtRealizeWidget(ICSInputShell);
4805 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4808 edit = XtNameToWidget(ICSInputShell, "*form.text");
4810 XtSetArg(args[j], XtNstring, ""); j++;
4811 XtSetValues(edit, args, j);
4813 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4814 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4815 XtSetValues(ICSInputShell, args, j);
4818 XtPopup(ICSInputShell, XtGrabNone);
4819 XtSetKeyboardFocus(ICSInputShell, edit);
4821 ICSInputBoxUp = True;
4823 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4824 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4828 void ICSInputSendText()
4835 edit = XtNameToWidget(ICSInputShell, "*form.text");
4837 XtSetArg(args[j], XtNstring, &val); j++;
4838 XtGetValues(edit, args, j);
4839 SendMultiLineToICS(val);
4840 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4841 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4844 void ICSInputBoxPopDown()
4849 if (!ICSInputBoxUp) return;
4851 XtPopdown(ICSInputShell);
4852 ICSInputBoxUp = False;
4854 XtSetArg(args[j], XtNleftBitmap, None); j++;
4855 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4859 void CommentPopUp(title, text)
4866 if (commentShell == NULL) {
4868 CommentCreate(title, text, False, CommentCallback, 4);
4869 XtRealizeWidget(commentShell);
4870 CatchDeleteWindow(commentShell, "CommentPopDown");
4872 edit = XtNameToWidget(commentShell, "*form.text");
4874 XtSetArg(args[j], XtNstring, text); j++;
4875 XtSetValues(edit, args, j);
4877 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4878 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4879 XtSetValues(commentShell, args, j);
4882 XtPopup(commentShell, XtGrabNone);
4883 XSync(xDisplay, False);
4888 void CommentCallback(w, client_data, call_data)
4890 XtPointer client_data, call_data;
4897 XtSetArg(args[j], XtNlabel, &name); j++;
4898 XtGetValues(w, args, j);
4900 if (strcmp(name, _("close")) == 0) {
4902 } else if (strcmp(name, _("edit")) == 0) {
4909 void CommentPopDown()
4914 if (!commentUp) return;
4916 XtSetArg(args[j], XtNx, &commentX); j++;
4917 XtSetArg(args[j], XtNy, &commentY); j++;
4918 XtSetArg(args[j], XtNwidth, &commentW); j++;
4919 XtSetArg(args[j], XtNheight, &commentH); j++;
4920 XtGetValues(commentShell, args, j);
4921 XtPopdown(commentShell);
4922 XSync(xDisplay, False);
4926 void FileNamePopUp(label, def, proc, openMode)
4933 Widget popup, layout, dialog, edit;
4939 fileProc = proc; /* I can't see a way not */
4940 fileOpenMode = openMode; /* to use globals here */
4943 XtSetArg(args[i], XtNresizable, True); i++;
4944 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4945 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4946 fileNameShell = popup =
4947 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4948 shellWidget, args, i);
4951 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4952 layoutArgs, XtNumber(layoutArgs));
4955 XtSetArg(args[i], XtNlabel, label); i++;
4956 XtSetArg(args[i], XtNvalue, def); i++;
4957 XtSetArg(args[i], XtNborderWidth, 0); i++;
4958 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4961 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4962 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4963 (XtPointer) dialog);
4965 XtRealizeWidget(popup);
4966 CatchDeleteWindow(popup, "FileNamePopDown");
4968 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4969 &x, &y, &win_x, &win_y, &mask);
4971 XtSetArg(args[0], XtNx, x - 10);
4972 XtSetArg(args[1], XtNy, y - 30);
4973 XtSetValues(popup, args, 2);
4975 XtPopup(popup, XtGrabExclusive);
4978 edit = XtNameToWidget(dialog, "*value");
4979 XtSetKeyboardFocus(popup, edit);
4982 void FileNamePopDown()
4984 if (!filenameUp) return;
4985 XtPopdown(fileNameShell);
4986 XtDestroyWidget(fileNameShell);
4991 void FileNameCallback(w, client_data, call_data)
4993 XtPointer client_data, call_data;
4998 XtSetArg(args[0], XtNlabel, &name);
4999 XtGetValues(w, args, 1);
5001 if (strcmp(name, _("cancel")) == 0) {
5006 FileNameAction(w, NULL, NULL, NULL);
5009 void FileNameAction(w, event, prms, nprms)
5021 name = XawDialogGetValueString(w = XtParent(w));
5023 if ((name != NULL) && (*name != NULLCHAR)) {
5025 XtPopdown(w = XtParent(XtParent(w)));
5029 p = strrchr(buf, ' ');
5036 fullname = ExpandPathName(buf);
5038 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5041 f = fopen(fullname, fileOpenMode);
5043 DisplayError(_("Failed to open file"), errno);
5045 (void) (*fileProc)(f, index, buf);
5052 XtPopdown(w = XtParent(XtParent(w)));
5058 void PromotionPopUp()
5061 Widget dialog, layout;
5063 Dimension bw_width, pw_width;
5067 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5068 XtGetValues(boardWidget, args, j);
5071 XtSetArg(args[j], XtNresizable, True); j++;
5072 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5074 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5075 shellWidget, args, j);
5077 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5078 layoutArgs, XtNumber(layoutArgs));
5081 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5082 XtSetArg(args[j], XtNborderWidth, 0); j++;
5083 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5086 if(gameInfo.variant != VariantShogi) {
5087 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5088 (XtPointer) dialog);
5089 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5090 (XtPointer) dialog);
5091 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5092 (XtPointer) dialog);
5093 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5094 (XtPointer) dialog);
5095 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5096 gameInfo.variant == VariantGiveaway) {
5097 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5098 (XtPointer) dialog);
5100 if(gameInfo.variant == VariantCapablanca ||
5101 gameInfo.variant == VariantGothic ||
5102 gameInfo.variant == VariantCapaRandom) {
5103 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5104 (XtPointer) dialog);
5105 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5106 (XtPointer) dialog);
5108 } else // [HGM] shogi
5110 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5111 (XtPointer) dialog);
5112 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5113 (XtPointer) dialog);
5115 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5116 (XtPointer) dialog);
5118 XtRealizeWidget(promotionShell);
5119 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5122 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5123 XtGetValues(promotionShell, args, j);
5125 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5126 lineGap + squareSize/3 +
5127 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5128 0 : 6*(squareSize + lineGap)), &x, &y);
5131 XtSetArg(args[j], XtNx, x); j++;
5132 XtSetArg(args[j], XtNy, y); j++;
5133 XtSetValues(promotionShell, args, j);
5135 XtPopup(promotionShell, XtGrabNone);
5140 void PromotionPopDown()
5142 if (!promotionUp) return;
5143 XtPopdown(promotionShell);
5144 XtDestroyWidget(promotionShell);
5145 promotionUp = False;
5148 void PromotionCallback(w, client_data, call_data)
5150 XtPointer client_data, call_data;
5156 XtSetArg(args[0], XtNlabel, &name);
5157 XtGetValues(w, args, 1);
5161 if (fromX == -1) return;
5163 if (strcmp(name, _("cancel")) == 0) {
5167 } else if (strcmp(name, _("Knight")) == 0) {
5169 } else if (strcmp(name, _("Promote")) == 0) {
5171 } else if (strcmp(name, _("Defer")) == 0) {
5174 promoChar = ToLower(name[0]);
5177 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5179 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5180 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5185 void ErrorCallback(w, client_data, call_data)
5187 XtPointer client_data, call_data;
5190 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5192 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5198 if (!errorUp) return;
5200 XtPopdown(errorShell);
5201 XtDestroyWidget(errorShell);
5202 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5205 void ErrorPopUp(title, label, modal)
5206 char *title, *label;
5210 Widget dialog, layout;
5214 Dimension bw_width, pw_width;
5215 Dimension pw_height;
5219 XtSetArg(args[i], XtNresizable, True); i++;
5220 XtSetArg(args[i], XtNtitle, title); i++;
5222 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5223 shellWidget, args, i);
5225 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5226 layoutArgs, XtNumber(layoutArgs));
5229 XtSetArg(args[i], XtNlabel, label); i++;
5230 XtSetArg(args[i], XtNborderWidth, 0); i++;
5231 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5234 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5236 XtRealizeWidget(errorShell);
5237 CatchDeleteWindow(errorShell, "ErrorPopDown");
5240 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5241 XtGetValues(boardWidget, args, i);
5243 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5244 XtSetArg(args[i], XtNheight, &pw_height); i++;
5245 XtGetValues(errorShell, args, i);
5248 /* This code seems to tickle an X bug if it is executed too soon
5249 after xboard starts up. The coordinates get transformed as if
5250 the main window was positioned at (0, 0).
5252 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5253 0 - pw_height + squareSize / 3, &x, &y);
5255 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5256 RootWindowOfScreen(XtScreen(boardWidget)),
5257 (bw_width - pw_width) / 2,
5258 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5262 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5265 XtSetArg(args[i], XtNx, x); i++;
5266 XtSetArg(args[i], XtNy, y); i++;
5267 XtSetValues(errorShell, args, i);
5270 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5273 /* Disable all user input other than deleting the window */
5274 static int frozen = 0;
5278 /* Grab by a widget that doesn't accept input */
5279 XtAddGrab(messageWidget, TRUE, FALSE);
5283 /* Undo a FreezeUI */
5286 if (!frozen) return;
5287 XtRemoveGrab(messageWidget);
5291 char *ModeToWidgetName(mode)
5295 case BeginningOfGame:
5296 if (appData.icsActive)
5297 return "menuMode.ICS Client";
5298 else if (appData.noChessProgram ||
5299 *appData.cmailGameName != NULLCHAR)
5300 return "menuMode.Edit Game";
5302 return "menuMode.Machine Black";
5303 case MachinePlaysBlack:
5304 return "menuMode.Machine Black";
5305 case MachinePlaysWhite:
5306 return "menuMode.Machine White";
5308 return "menuMode.Analysis Mode";
5310 return "menuMode.Analyze File";
5311 case TwoMachinesPlay:
5312 return "menuMode.Two Machines";
5314 return "menuMode.Edit Game";
5315 case PlayFromGameFile:
5316 return "menuFile.Load Game";
5318 return "menuMode.Edit Position";
5320 return "menuMode.Training";
5321 case IcsPlayingWhite:
5322 case IcsPlayingBlack:
5326 return "menuMode.ICS Client";
5333 void ModeHighlight()
5336 static int oldPausing = FALSE;
5337 static GameMode oldmode = (GameMode) -1;
5340 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5342 if (pausing != oldPausing) {
5343 oldPausing = pausing;
5345 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5347 XtSetArg(args[0], XtNleftBitmap, None);
5349 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5352 if (appData.showButtonBar) {
5353 /* Always toggle, don't set. Previous code messes up when
5354 invoked while the button is pressed, as releasing it
5355 toggles the state again. */
5358 XtSetArg(args[0], XtNbackground, &oldbg);
5359 XtSetArg(args[1], XtNforeground, &oldfg);
5360 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5362 XtSetArg(args[0], XtNbackground, oldfg);
5363 XtSetArg(args[1], XtNforeground, oldbg);
5365 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5369 wname = ModeToWidgetName(oldmode);
5370 if (wname != NULL) {
5371 XtSetArg(args[0], XtNleftBitmap, None);
5372 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5374 wname = ModeToWidgetName(gameMode);
5375 if (wname != NULL) {
5376 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5377 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5381 /* Maybe all the enables should be handled here, not just this one */
5382 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5383 gameMode == Training || gameMode == PlayFromGameFile);
5388 * Button/menu procedures
5390 void ResetProc(w, event, prms, nprms)
5399 int LoadGamePopUp(f, gameNumber, title)
5404 cmailMsgLoaded = FALSE;
5405 if (gameNumber == 0) {
5406 int error = GameListBuild(f);
5408 DisplayError(_("Cannot build game list"), error);
5409 } else if (!ListEmpty(&gameList) &&
5410 ((ListGame *) gameList.tailPred)->number > 1) {
5411 GameListPopUp(f, title);
5417 return LoadGame(f, gameNumber, title, FALSE);
5420 void LoadGameProc(w, event, prms, nprms)
5426 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5429 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5432 void LoadNextGameProc(w, event, prms, nprms)
5441 void LoadPrevGameProc(w, event, prms, nprms)
5450 void ReloadGameProc(w, event, prms, nprms)
5459 void LoadNextPositionProc(w, event, prms, nprms)
5468 void LoadPrevPositionProc(w, event, prms, nprms)
5477 void ReloadPositionProc(w, event, prms, nprms)
5486 void LoadPositionProc(w, event, prms, nprms)
5492 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5495 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5498 void SaveGameProc(w, event, prms, nprms)
5504 FileNamePopUp(_("Save game file name?"),
5505 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5509 void SavePositionProc(w, event, prms, nprms)
5515 FileNamePopUp(_("Save position file name?"),
5516 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5520 void ReloadCmailMsgProc(w, event, prms, nprms)
5526 ReloadCmailMsgEvent(FALSE);
5529 void MailMoveProc(w, event, prms, nprms)
5538 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5539 static char *selected_fen_position=NULL;
5542 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5543 Atom *type_return, XtPointer *value_return,
5544 unsigned long *length_return, int *format_return)
5546 char *selection_tmp;
5548 if (!selected_fen_position) return False; /* should never happen */
5549 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5550 /* note: since no XtSelectionDoneProc was registered, Xt will
5551 * automatically call XtFree on the value returned. So have to
5552 * make a copy of it allocated with XtMalloc */
5553 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5554 strcpy(selection_tmp, selected_fen_position);
5556 *value_return=selection_tmp;
5557 *length_return=strlen(selection_tmp);
5558 *type_return=*target;
5559 *format_return = 8; /* bits per byte */
5561 } else if (*target == XA_TARGETS(xDisplay)) {
5562 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5563 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5564 targets_tmp[1] = XA_STRING;
5565 *value_return = targets_tmp;
5566 *type_return = XA_ATOM;
5568 *format_return = 8 * sizeof(Atom);
5569 if (*format_return > 32) {
5570 *length_return *= *format_return / 32;
5571 *format_return = 32;
5579 /* note: when called from menu all parameters are NULL, so no clue what the
5580 * Widget which was clicked on was, or what the click event was
5582 void CopyPositionProc(w, event, prms, nprms)
5589 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5590 * have a notion of a position that is selected but not copied.
5591 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5593 if (selected_fen_position) free(selected_fen_position);
5594 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5595 if (!selected_fen_position) return;
5596 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5598 SendPositionSelection,
5599 NULL/* lose_ownership_proc */ ,
5600 NULL/* transfer_done_proc */);
5601 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5603 SendPositionSelection,
5604 NULL/* lose_ownership_proc */ ,
5605 NULL/* transfer_done_proc */);
5608 /* function called when the data to Paste is ready */
5610 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5611 Atom *type, XtPointer value, unsigned long *len, int *format)
5614 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5615 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5616 EditPositionPasteFEN(fenstr);
5620 /* called when Paste Position button is pressed,
5621 * all parameters will be NULL */
5622 void PastePositionProc(w, event, prms, nprms)
5628 XtGetSelectionValue(menuBarWidget,
5629 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5630 /* (XtSelectionCallbackProc) */ PastePositionCB,
5631 NULL, /* client_data passed to PastePositionCB */
5633 /* better to use the time field from the event that triggered the
5634 * call to this function, but that isn't trivial to get
5642 SendGameSelection(Widget w, Atom *selection, Atom *target,
5643 Atom *type_return, XtPointer *value_return,
5644 unsigned long *length_return, int *format_return)
5646 char *selection_tmp;
5648 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5649 FILE* f = fopen(gameCopyFilename, "r");
5652 if (f == NULL) return False;
5656 selection_tmp = XtMalloc(len + 1);
5657 count = fread(selection_tmp, 1, len, f);
5659 XtFree(selection_tmp);
5662 selection_tmp[len] = NULLCHAR;
5663 *value_return = selection_tmp;
5664 *length_return = len;
5665 *type_return = *target;
5666 *format_return = 8; /* bits per byte */
5668 } else if (*target == XA_TARGETS(xDisplay)) {
5669 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5670 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5671 targets_tmp[1] = XA_STRING;
5672 *value_return = targets_tmp;
5673 *type_return = XA_ATOM;
5675 *format_return = 8 * sizeof(Atom);
5676 if (*format_return > 32) {
5677 *length_return *= *format_return / 32;
5678 *format_return = 32;
5686 /* note: when called from menu all parameters are NULL, so no clue what the
5687 * Widget which was clicked on was, or what the click event was
5689 void CopyGameProc(w, event, prms, nprms)
5697 ret = SaveGameToFile(gameCopyFilename, FALSE);
5701 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5702 * have a notion of a game that is selected but not copied.
5703 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5705 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5708 NULL/* lose_ownership_proc */ ,
5709 NULL/* transfer_done_proc */);
5710 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5713 NULL/* lose_ownership_proc */ ,
5714 NULL/* transfer_done_proc */);
5717 /* function called when the data to Paste is ready */
5719 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5720 Atom *type, XtPointer value, unsigned long *len, int *format)
5723 if (value == NULL || *len == 0) {
5724 return; /* nothing had been selected to copy */
5726 f = fopen(gamePasteFilename, "w");
5728 DisplayError(_("Can't open temp file"), errno);
5731 fwrite(value, 1, *len, f);
5734 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5737 /* called when Paste Game button is pressed,
5738 * all parameters will be NULL */
5739 void PasteGameProc(w, event, prms, nprms)
5745 XtGetSelectionValue(menuBarWidget,
5746 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5747 /* (XtSelectionCallbackProc) */ PasteGameCB,
5748 NULL, /* client_data passed to PasteGameCB */
5750 /* better to use the time field from the event that triggered the
5751 * call to this function, but that isn't trivial to get
5761 SaveGameProc(NULL, NULL, NULL, NULL);
5765 void QuitProc(w, event, prms, nprms)
5774 void PauseProc(w, event, prms, nprms)
5784 void MachineBlackProc(w, event, prms, nprms)
5790 MachineBlackEvent();
5793 void MachineWhiteProc(w, event, prms, nprms)
5799 MachineWhiteEvent();
5802 void AnalyzeModeProc(w, event, prms, nprms)
5810 if (!first.analysisSupport) {
5811 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5812 DisplayError(buf, 0);
5815 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5816 if (appData.icsActive) {
5817 if (gameMode != IcsObserving) {
5818 sprintf(buf,_("You are not observing a game"));
5819 DisplayError(buf, 0);
5821 if (appData.icsEngineAnalyze) {
5822 if (appData.debugMode)
5823 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5829 /* if enable, use want disable icsEngineAnalyze */
5830 if (appData.icsEngineAnalyze) {
5835 appData.icsEngineAnalyze = TRUE;
5836 if (appData.debugMode)
5837 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5839 if (!appData.showThinking)
5840 ShowThinkingProc(w,event,prms,nprms);
5845 void AnalyzeFileProc(w, event, prms, nprms)
5851 if (!first.analysisSupport) {
5853 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5854 DisplayError(buf, 0);
5859 if (!appData.showThinking)
5860 ShowThinkingProc(w,event,prms,nprms);
5863 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5864 AnalysisPeriodicEvent(1);
5867 void TwoMachinesProc(w, event, prms, nprms)
5876 void IcsClientProc(w, event, prms, nprms)
5885 void EditGameProc(w, event, prms, nprms)
5894 void EditPositionProc(w, event, prms, nprms)
5900 EditPositionEvent();
5903 void TrainingProc(w, event, prms, nprms)
5912 void EditCommentProc(w, event, prms, nprms)
5919 EditCommentPopDown();
5925 void IcsInputBoxProc(w, event, prms, nprms)
5931 if (ICSInputBoxUp) {
5932 ICSInputBoxPopDown();
5938 void AcceptProc(w, event, prms, nprms)
5947 void DeclineProc(w, event, prms, nprms)
5956 void RematchProc(w, event, prms, nprms)
5965 void CallFlagProc(w, event, prms, nprms)
5974 void DrawProc(w, event, prms, nprms)
5983 void AbortProc(w, event, prms, nprms)
5992 void AdjournProc(w, event, prms, nprms)
6001 void ResignProc(w, event, prms, nprms)
6010 void AdjuWhiteProc(w, event, prms, nprms)
6016 UserAdjudicationEvent(+1);
6019 void AdjuBlackProc(w, event, prms, nprms)
6025 UserAdjudicationEvent(-1);
6028 void AdjuDrawProc(w, event, prms, nprms)
6034 UserAdjudicationEvent(0);
6037 void EnterKeyProc(w, event, prms, nprms)
6043 if (ICSInputBoxUp == True)
6047 void StopObservingProc(w, event, prms, nprms)
6053 StopObservingEvent();
6056 void StopExaminingProc(w, event, prms, nprms)
6062 StopExaminingEvent();
6066 void ForwardProc(w, event, prms, nprms)
6076 void BackwardProc(w, event, prms, nprms)
6085 void ToStartProc(w, event, prms, nprms)
6094 void ToEndProc(w, event, prms, nprms)
6103 void RevertProc(w, event, prms, nprms)
6112 void TruncateGameProc(w, event, prms, nprms)
6118 TruncateGameEvent();
6120 void RetractMoveProc(w, event, prms, nprms)
6129 void MoveNowProc(w, event, prms, nprms)
6139 void AlwaysQueenProc(w, event, prms, nprms)
6147 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6149 if (appData.alwaysPromoteToQueen) {
6150 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6152 XtSetArg(args[0], XtNleftBitmap, None);
6154 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6158 void AnimateDraggingProc(w, event, prms, nprms)
6166 appData.animateDragging = !appData.animateDragging;
6168 if (appData.animateDragging) {
6169 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6172 XtSetArg(args[0], XtNleftBitmap, None);
6174 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6178 void AnimateMovingProc(w, event, prms, nprms)
6186 appData.animate = !appData.animate;
6188 if (appData.animate) {
6189 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6192 XtSetArg(args[0], XtNleftBitmap, None);
6194 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6198 void AutocommProc(w, event, prms, nprms)
6206 appData.autoComment = !appData.autoComment;
6208 if (appData.autoComment) {
6209 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6211 XtSetArg(args[0], XtNleftBitmap, None);
6213 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6218 void AutoflagProc(w, event, prms, nprms)
6226 appData.autoCallFlag = !appData.autoCallFlag;
6228 if (appData.autoCallFlag) {
6229 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6231 XtSetArg(args[0], XtNleftBitmap, None);
6233 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6237 void AutoflipProc(w, event, prms, nprms)
6245 appData.autoFlipView = !appData.autoFlipView;
6247 if (appData.autoFlipView) {
6248 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6250 XtSetArg(args[0], XtNleftBitmap, None);
6252 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6256 void AutobsProc(w, event, prms, nprms)
6264 appData.autoObserve = !appData.autoObserve;
6266 if (appData.autoObserve) {
6267 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6269 XtSetArg(args[0], XtNleftBitmap, None);
6271 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6275 void AutoraiseProc(w, event, prms, nprms)
6283 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6285 if (appData.autoRaiseBoard) {
6286 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6288 XtSetArg(args[0], XtNleftBitmap, None);
6290 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6294 void AutosaveProc(w, event, prms, nprms)
6302 appData.autoSaveGames = !appData.autoSaveGames;
6304 if (appData.autoSaveGames) {
6305 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6307 XtSetArg(args[0], XtNleftBitmap, None);
6309 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6313 void BlindfoldProc(w, event, prms, nprms)
6321 appData.blindfold = !appData.blindfold;
6323 if (appData.blindfold) {
6324 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6326 XtSetArg(args[0], XtNleftBitmap, None);
6328 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6331 DrawPosition(True, NULL);
6334 void TestLegalityProc(w, event, prms, nprms)
6342 appData.testLegality = !appData.testLegality;
6344 if (appData.testLegality) {
6345 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6347 XtSetArg(args[0], XtNleftBitmap, None);
6349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6354 void FlashMovesProc(w, event, prms, nprms)
6362 if (appData.flashCount == 0) {
6363 appData.flashCount = 3;
6365 appData.flashCount = -appData.flashCount;
6368 if (appData.flashCount > 0) {
6369 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6371 XtSetArg(args[0], XtNleftBitmap, None);
6373 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6377 void FlipViewProc(w, event, prms, nprms)
6383 flipView = !flipView;
6384 DrawPosition(True, NULL);
6387 void GetMoveListProc(w, event, prms, nprms)
6395 appData.getMoveList = !appData.getMoveList;
6397 if (appData.getMoveList) {
6398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6401 XtSetArg(args[0], XtNleftBitmap, None);
6403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6408 void HighlightDraggingProc(w, event, prms, nprms)
6416 appData.highlightDragging = !appData.highlightDragging;
6418 if (appData.highlightDragging) {
6419 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6421 XtSetArg(args[0], XtNleftBitmap, None);
6423 XtSetValues(XtNameToWidget(menuBarWidget,
6424 "menuOptions.Highlight Dragging"), args, 1);
6428 void HighlightLastMoveProc(w, event, prms, nprms)
6436 appData.highlightLastMove = !appData.highlightLastMove;
6438 if (appData.highlightLastMove) {
6439 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6441 XtSetArg(args[0], XtNleftBitmap, None);
6443 XtSetValues(XtNameToWidget(menuBarWidget,
6444 "menuOptions.Highlight Last Move"), args, 1);
6447 void IcsAlarmProc(w, event, prms, nprms)
6455 appData.icsAlarm = !appData.icsAlarm;
6457 if (appData.icsAlarm) {
6458 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6460 XtSetArg(args[0], XtNleftBitmap, None);
6462 XtSetValues(XtNameToWidget(menuBarWidget,
6463 "menuOptions.ICS Alarm"), args, 1);
6466 void MoveSoundProc(w, event, prms, nprms)
6474 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6476 if (appData.ringBellAfterMoves) {
6477 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6479 XtSetArg(args[0], XtNleftBitmap, None);
6481 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6486 void OldSaveStyleProc(w, event, prms, nprms)
6494 appData.oldSaveStyle = !appData.oldSaveStyle;
6496 if (appData.oldSaveStyle) {
6497 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6499 XtSetArg(args[0], XtNleftBitmap, None);
6501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6505 void PeriodicUpdatesProc(w, event, prms, nprms)
6513 PeriodicUpdatesEvent(!appData.periodicUpdates);
6515 if (appData.periodicUpdates) {
6516 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6518 XtSetArg(args[0], XtNleftBitmap, None);
6520 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6524 void PonderNextMoveProc(w, event, prms, nprms)
6532 PonderNextMoveEvent(!appData.ponderNextMove);
6534 if (appData.ponderNextMove) {
6535 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6537 XtSetArg(args[0], XtNleftBitmap, None);
6539 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6543 void PopupExitMessageProc(w, event, prms, nprms)
6551 appData.popupExitMessage = !appData.popupExitMessage;
6553 if (appData.popupExitMessage) {
6554 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6556 XtSetArg(args[0], XtNleftBitmap, None);
6558 XtSetValues(XtNameToWidget(menuBarWidget,
6559 "menuOptions.Popup Exit Message"), args, 1);
6562 void PopupMoveErrorsProc(w, event, prms, nprms)
6570 appData.popupMoveErrors = !appData.popupMoveErrors;
6572 if (appData.popupMoveErrors) {
6573 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6575 XtSetArg(args[0], XtNleftBitmap, None);
6577 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6581 void PremoveProc(w, event, prms, nprms)
6589 appData.premove = !appData.premove;
6591 if (appData.premove) {
6592 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6594 XtSetArg(args[0], XtNleftBitmap, None);
6596 XtSetValues(XtNameToWidget(menuBarWidget,
6597 "menuOptions.Premove"), args, 1);
6600 void QuietPlayProc(w, event, prms, nprms)
6608 appData.quietPlay = !appData.quietPlay;
6610 if (appData.quietPlay) {
6611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6613 XtSetArg(args[0], XtNleftBitmap, None);
6615 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6619 void ShowCoordsProc(w, event, prms, nprms)
6627 appData.showCoords = !appData.showCoords;
6629 if (appData.showCoords) {
6630 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6632 XtSetArg(args[0], XtNleftBitmap, None);
6634 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6637 DrawPosition(True, NULL);
6640 void ShowThinkingProc(w, event, prms, nprms)
6646 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6647 ShowThinkingEvent();
6650 void HideThinkingProc(w, event, prms, nprms)
6658 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6659 ShowThinkingEvent();
6661 if (appData.hideThinkingFromHuman) {
6662 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6664 XtSetArg(args[0], XtNleftBitmap, None);
6666 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6670 void SaveOnExitProc(w, event, prms, nprms)
6678 saveSettingsOnExit = !saveSettingsOnExit;
6680 if (saveSettingsOnExit) {
6681 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6683 XtSetArg(args[0], XtNleftBitmap, None);
6685 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6689 void SaveSettingsProc(w, event, prms, nprms)
6695 SaveSettings(settingsFileName);
6698 void InfoProc(w, event, prms, nprms)
6705 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6710 void ManProc(w, event, prms, nprms)
6718 if (nprms && *nprms > 0)
6722 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6726 void HintProc(w, event, prms, nprms)
6735 void BookProc(w, event, prms, nprms)
6744 void AboutProc(w, event, prms, nprms)
6752 char *zippy = " (with Zippy code)";
6756 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6757 programVersion, zippy,
6758 "Copyright 1991 Digital Equipment Corporation",
6759 "Enhancements Copyright 1992-2009 Free Software Foundation",
6760 "Enhancements Copyright 2005 Alessandro Scotti",
6761 PACKAGE, " is free software and carries NO WARRANTY;",
6762 "see the file COPYING for more information.");
6763 ErrorPopUp(_("About XBoard"), buf, FALSE);
6766 void DebugProc(w, event, prms, nprms)
6772 appData.debugMode = !appData.debugMode;
6775 void AboutGameProc(w, event, prms, nprms)
6784 void NothingProc(w, event, prms, nprms)
6793 void Iconify(w, event, prms, nprms)
6802 XtSetArg(args[0], XtNiconic, True);
6803 XtSetValues(shellWidget, args, 1);
6806 void DisplayMessage(message, extMessage)
6807 char *message, *extMessage;
6809 /* display a message in the message widget */
6818 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6823 message = extMessage;
6827 /* need to test if messageWidget already exists, since this function
6828 can also be called during the startup, if for example a Xresource
6829 is not set up correctly */
6832 XtSetArg(arg, XtNlabel, message);
6833 XtSetValues(messageWidget, &arg, 1);
6839 void DisplayTitle(text)
6844 char title[MSG_SIZ];
6847 if (text == NULL) text = "";
6849 if (appData.titleInWindow) {
6851 XtSetArg(args[i], XtNlabel, text); i++;
6852 XtSetValues(titleWidget, args, i);
6855 if (*text != NULLCHAR) {
6857 strcpy(title, text);
6858 } else if (appData.icsActive) {
6859 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6860 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6861 } else if (appData.cmailGameName[0] != NULLCHAR) {
6862 snprintf(icon, sizeof(icon), "%s", "CMail");
6863 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6865 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6866 } else if (gameInfo.variant == VariantGothic) {
6867 strcpy(icon, programName);
6868 strcpy(title, GOTHIC);
6871 } else if (gameInfo.variant == VariantFalcon) {
6872 strcpy(icon, programName);
6873 strcpy(title, FALCON);
6875 } else if (appData.noChessProgram) {
6876 strcpy(icon, programName);
6877 strcpy(title, programName);
6879 strcpy(icon, first.tidy);
6880 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6883 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6884 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6885 XtSetValues(shellWidget, args, i);
6889 void DisplayError(message, error)
6896 if (appData.debugMode || appData.matchMode) {
6897 fprintf(stderr, "%s: %s\n", programName, message);
6900 if (appData.debugMode || appData.matchMode) {
6901 fprintf(stderr, "%s: %s: %s\n",
6902 programName, message, strerror(error));
6904 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6907 ErrorPopUp(_("Error"), message, FALSE);
6911 void DisplayMoveError(message)
6916 DrawPosition(FALSE, NULL);
6917 if (appData.debugMode || appData.matchMode) {
6918 fprintf(stderr, "%s: %s\n", programName, message);
6920 if (appData.popupMoveErrors) {
6921 ErrorPopUp(_("Error"), message, FALSE);
6923 DisplayMessage(message, "");
6928 void DisplayFatalError(message, error, status)
6934 errorExitStatus = status;
6936 fprintf(stderr, "%s: %s\n", programName, message);
6938 fprintf(stderr, "%s: %s: %s\n",
6939 programName, message, strerror(error));
6940 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6943 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6944 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6950 void DisplayInformation(message)
6954 ErrorPopUp(_("Information"), message, TRUE);
6957 void DisplayNote(message)
6961 ErrorPopUp(_("Note"), message, FALSE);
6965 NullXErrorCheck(dpy, error_event)
6967 XErrorEvent *error_event;
6972 void DisplayIcsInteractionTitle(message)
6975 if (oldICSInteractionTitle == NULL) {
6976 /* Magic to find the old window title, adapted from vim */
6977 char *wina = getenv("WINDOWID");
6979 Window win = (Window) atoi(wina);
6980 Window root, parent, *children;
6981 unsigned int nchildren;
6982 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6984 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6985 if (!XQueryTree(xDisplay, win, &root, &parent,
6986 &children, &nchildren)) break;
6987 if (children) XFree((void *)children);
6988 if (parent == root || parent == 0) break;
6991 XSetErrorHandler(oldHandler);
6993 if (oldICSInteractionTitle == NULL) {
6994 oldICSInteractionTitle = "xterm";
6997 printf("\033]0;%s\007", message);
7001 char pendingReplyPrefix[MSG_SIZ];
7002 ProcRef pendingReplyPR;
7004 void AskQuestionProc(w, event, prms, nprms)
7011 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7015 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7018 void AskQuestionPopDown()
7020 if (!askQuestionUp) return;
7021 XtPopdown(askQuestionShell);
7022 XtDestroyWidget(askQuestionShell);
7023 askQuestionUp = False;
7026 void AskQuestionReplyAction(w, event, prms, nprms)
7036 reply = XawDialogGetValueString(w = XtParent(w));
7037 strcpy(buf, pendingReplyPrefix);
7038 if (*buf) strcat(buf, " ");
7041 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7042 AskQuestionPopDown();
7044 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7047 void AskQuestionCallback(w, client_data, call_data)
7049 XtPointer client_data, call_data;
7054 XtSetArg(args[0], XtNlabel, &name);
7055 XtGetValues(w, args, 1);
7057 if (strcmp(name, _("cancel")) == 0) {
7058 AskQuestionPopDown();
7060 AskQuestionReplyAction(w, NULL, NULL, NULL);
7064 void AskQuestion(title, question, replyPrefix, pr)
7065 char *title, *question, *replyPrefix;
7069 Widget popup, layout, dialog, edit;
7075 strcpy(pendingReplyPrefix, replyPrefix);
7076 pendingReplyPR = pr;
7079 XtSetArg(args[i], XtNresizable, True); i++;
7080 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7081 askQuestionShell = popup =
7082 XtCreatePopupShell(title, transientShellWidgetClass,
7083 shellWidget, args, i);
7086 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7087 layoutArgs, XtNumber(layoutArgs));
7090 XtSetArg(args[i], XtNlabel, question); i++;
7091 XtSetArg(args[i], XtNvalue, ""); i++;
7092 XtSetArg(args[i], XtNborderWidth, 0); i++;
7093 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7096 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7097 (XtPointer) dialog);
7098 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7099 (XtPointer) dialog);
7101 XtRealizeWidget(popup);
7102 CatchDeleteWindow(popup, "AskQuestionPopDown");
7104 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7105 &x, &y, &win_x, &win_y, &mask);
7107 XtSetArg(args[0], XtNx, x - 10);
7108 XtSetArg(args[1], XtNy, y - 30);
7109 XtSetValues(popup, args, 2);
7111 XtPopup(popup, XtGrabExclusive);
7112 askQuestionUp = True;
7114 edit = XtNameToWidget(dialog, "*value");
7115 XtSetKeyboardFocus(popup, edit);
7123 if (*name == NULLCHAR) {
7125 } else if (strcmp(name, "$") == 0) {
7126 putc(BELLCHAR, stderr);
7129 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7137 PlaySound(appData.soundMove);
7143 PlaySound(appData.soundIcsWin);
7149 PlaySound(appData.soundIcsLoss);
7155 PlaySound(appData.soundIcsDraw);
7159 PlayIcsUnfinishedSound()
7161 PlaySound(appData.soundIcsUnfinished);
7167 PlaySound(appData.soundIcsAlarm);
7173 system("stty echo");
7179 system("stty -echo");
7183 Colorize(cc, continuation)
7188 int count, outCount, error;
7190 if (textColors[(int)cc].bg > 0) {
7191 if (textColors[(int)cc].fg > 0) {
7192 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7193 textColors[(int)cc].fg, textColors[(int)cc].bg);
7195 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7196 textColors[(int)cc].bg);
7199 if (textColors[(int)cc].fg > 0) {
7200 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7201 textColors[(int)cc].fg);
7203 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7206 count = strlen(buf);
7207 outCount = OutputToProcess(NoProc, buf, count, &error);
7208 if (outCount < count) {
7209 DisplayFatalError(_("Error writing to display"), error, 1);
7212 if (continuation) return;
7215 PlaySound(appData.soundShout);
7218 PlaySound(appData.soundSShout);
7221 PlaySound(appData.soundChannel1);
7224 PlaySound(appData.soundChannel);
7227 PlaySound(appData.soundKibitz);
7230 PlaySound(appData.soundTell);
7232 case ColorChallenge:
7233 PlaySound(appData.soundChallenge);
7236 PlaySound(appData.soundRequest);
7239 PlaySound(appData.soundSeek);
7250 return getpwuid(getuid())->pw_name;
7253 static char *ExpandPathName(path)
7256 static char static_buf[2000];
7257 char *d, *s, buf[2000];
7263 while (*s && isspace(*s))
7272 if (*(s+1) == '/') {
7273 strcpy(d, getpwuid(getuid())->pw_dir);
7278 *strchr(buf, '/') = 0;
7279 pwd = getpwnam(buf);
7282 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7286 strcpy(d, pwd->pw_dir);
7287 strcat(d, strchr(s+1, '/'));
7298 static char host_name[MSG_SIZ];
7300 #if HAVE_GETHOSTNAME
7301 gethostname(host_name, MSG_SIZ);
7303 #else /* not HAVE_GETHOSTNAME */
7304 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7305 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7307 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7309 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7310 #endif /* not HAVE_GETHOSTNAME */
7313 XtIntervalId delayedEventTimerXID = 0;
7314 DelayedEventCallback delayedEventCallback = 0;
7319 delayedEventTimerXID = 0;
7320 delayedEventCallback();
7324 ScheduleDelayedEvent(cb, millisec)
7325 DelayedEventCallback cb; long millisec;
7327 if(delayedEventTimerXID && delayedEventCallback == cb)
7328 // [HGM] alive: replace, rather than add or flush identical event
7329 XtRemoveTimeOut(delayedEventTimerXID);
7330 delayedEventCallback = cb;
7331 delayedEventTimerXID =
7332 XtAppAddTimeOut(appContext, millisec,
7333 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7336 DelayedEventCallback
7339 if (delayedEventTimerXID) {
7340 return delayedEventCallback;
7347 CancelDelayedEvent()
7349 if (delayedEventTimerXID) {
7350 XtRemoveTimeOut(delayedEventTimerXID);
7351 delayedEventTimerXID = 0;
7355 XtIntervalId loadGameTimerXID = 0;
7357 int LoadGameTimerRunning()
7359 return loadGameTimerXID != 0;
7362 int StopLoadGameTimer()
7364 if (loadGameTimerXID != 0) {
7365 XtRemoveTimeOut(loadGameTimerXID);
7366 loadGameTimerXID = 0;
7374 LoadGameTimerCallback(arg, id)
7378 loadGameTimerXID = 0;
7383 StartLoadGameTimer(millisec)
7387 XtAppAddTimeOut(appContext, millisec,
7388 (XtTimerCallbackProc) LoadGameTimerCallback,
7392 XtIntervalId analysisClockXID = 0;
7395 AnalysisClockCallback(arg, id)
7399 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7400 || appData.icsEngineAnalyze) { // [DM]
7401 AnalysisPeriodicEvent(0);
7402 StartAnalysisClock();
7407 StartAnalysisClock()
7410 XtAppAddTimeOut(appContext, 2000,
7411 (XtTimerCallbackProc) AnalysisClockCallback,
7415 XtIntervalId clockTimerXID = 0;
7417 int ClockTimerRunning()
7419 return clockTimerXID != 0;
7422 int StopClockTimer()
7424 if (clockTimerXID != 0) {
7425 XtRemoveTimeOut(clockTimerXID);
7434 ClockTimerCallback(arg, id)
7443 StartClockTimer(millisec)
7447 XtAppAddTimeOut(appContext, millisec,
7448 (XtTimerCallbackProc) ClockTimerCallback,
7453 DisplayTimerLabel(w, color, timer, highlight)
7462 /* check for low time warning */
7463 Pixel foregroundOrWarningColor = timerForegroundPixel;
7466 appData.lowTimeWarning &&
7467 (timer / 1000) < appData.icsAlarmTime)
7468 foregroundOrWarningColor = lowTimeWarningColor;
7470 if (appData.clockMode) {
7471 sprintf(buf, "%s: %s", color, TimeString(timer));
7472 XtSetArg(args[0], XtNlabel, buf);
7474 sprintf(buf, "%s ", color);
7475 XtSetArg(args[0], XtNlabel, buf);
7480 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7481 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7483 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7484 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7487 XtSetValues(w, args, 3);
7491 DisplayWhiteClock(timeRemaining, highlight)
7497 if(appData.noGUI) return;
7498 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7499 if (highlight && iconPixmap == bIconPixmap) {
7500 iconPixmap = wIconPixmap;
7501 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7502 XtSetValues(shellWidget, args, 1);
7507 DisplayBlackClock(timeRemaining, highlight)
7513 if(appData.noGUI) return;
7514 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7515 if (highlight && iconPixmap == wIconPixmap) {
7516 iconPixmap = bIconPixmap;
7517 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7518 XtSetValues(shellWidget, args, 1);
7536 int StartChildProcess(cmdLine, dir, pr)
7543 int to_prog[2], from_prog[2];
7547 if (appData.debugMode) {
7548 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7551 /* We do NOT feed the cmdLine to the shell; we just
7552 parse it into blank-separated arguments in the
7553 most simple-minded way possible.
7556 strcpy(buf, cmdLine);
7561 if (p == NULL) break;
7566 SetUpChildIO(to_prog, from_prog);
7568 if ((pid = fork()) == 0) {
7570 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7571 close(to_prog[1]); // first close the unused pipe ends
7572 close(from_prog[0]);
7573 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7574 dup2(from_prog[1], 1);
7575 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7576 close(from_prog[1]); // and closing again loses one of the pipes!
7577 if(fileno(stderr) >= 2) // better safe than sorry...
7578 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7580 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7585 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7587 execvp(argv[0], argv);
7589 /* If we get here, exec failed */
7594 /* Parent process */
7596 close(from_prog[1]);
7598 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7601 cp->fdFrom = from_prog[0];
7602 cp->fdTo = to_prog[1];
7607 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7608 static RETSIGTYPE AlarmCallBack(int n)
7614 DestroyChildProcess(pr, signalType)
7618 ChildProc *cp = (ChildProc *) pr;
7620 if (cp->kind != CPReal) return;
7622 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7623 signal(SIGALRM, AlarmCallBack);
7625 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7626 kill(cp->pid, SIGKILL); // kill it forcefully
7627 wait((int *) 0); // and wait again
7631 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7633 /* Process is exiting either because of the kill or because of
7634 a quit command sent by the backend; either way, wait for it to die.
7643 InterruptChildProcess(pr)
7646 ChildProc *cp = (ChildProc *) pr;
7648 if (cp->kind != CPReal) return;
7649 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7652 int OpenTelnet(host, port, pr)
7657 char cmdLine[MSG_SIZ];
7659 if (port[0] == NULLCHAR) {
7660 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7662 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7664 return StartChildProcess(cmdLine, "", pr);
7667 int OpenTCP(host, port, pr)
7673 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7674 #else /* !OMIT_SOCKETS */
7676 struct sockaddr_in sa;
7678 unsigned short uport;
7681 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7685 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7686 sa.sin_family = AF_INET;
7687 sa.sin_addr.s_addr = INADDR_ANY;
7688 uport = (unsigned short) 0;
7689 sa.sin_port = htons(uport);
7690 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7694 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7695 if (!(hp = gethostbyname(host))) {
7697 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7698 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7699 hp->h_addrtype = AF_INET;
7701 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7702 hp->h_addr_list[0] = (char *) malloc(4);
7703 hp->h_addr_list[0][0] = b0;
7704 hp->h_addr_list[0][1] = b1;
7705 hp->h_addr_list[0][2] = b2;
7706 hp->h_addr_list[0][3] = b3;
7711 sa.sin_family = hp->h_addrtype;
7712 uport = (unsigned short) atoi(port);
7713 sa.sin_port = htons(uport);
7714 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7716 if (connect(s, (struct sockaddr *) &sa,
7717 sizeof(struct sockaddr_in)) < 0) {
7721 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7728 #endif /* !OMIT_SOCKETS */
7733 int OpenCommPort(name, pr)
7740 fd = open(name, 2, 0);
7741 if (fd < 0) return errno;
7743 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7753 int OpenLoopback(pr)
7759 SetUpChildIO(to, from);
7761 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7764 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7771 int OpenRcmd(host, user, cmd, pr)
7772 char *host, *user, *cmd;
7775 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7779 #define INPUT_SOURCE_BUF_SIZE 8192
7788 char buf[INPUT_SOURCE_BUF_SIZE];
7793 DoInputCallback(closure, source, xid)
7798 InputSource *is = (InputSource *) closure;
7803 if (is->lineByLine) {
7804 count = read(is->fd, is->unused,
7805 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7807 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7810 is->unused += count;
7812 while (p < is->unused) {
7813 q = memchr(p, '\n', is->unused - p);
7814 if (q == NULL) break;
7816 (is->func)(is, is->closure, p, q - p, 0);
7820 while (p < is->unused) {
7825 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7830 (is->func)(is, is->closure, is->buf, count, error);
7834 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7841 ChildProc *cp = (ChildProc *) pr;
7843 is = (InputSource *) calloc(1, sizeof(InputSource));
7844 is->lineByLine = lineByLine;
7848 is->fd = fileno(stdin);
7850 is->kind = cp->kind;
7851 is->fd = cp->fdFrom;
7854 is->unused = is->buf;
7857 is->xid = XtAppAddInput(appContext, is->fd,
7858 (XtPointer) (XtInputReadMask),
7859 (XtInputCallbackProc) DoInputCallback,
7861 is->closure = closure;
7862 return (InputSourceRef) is;
7866 RemoveInputSource(isr)
7869 InputSource *is = (InputSource *) isr;
7871 if (is->xid == 0) return;
7872 XtRemoveInput(is->xid);
7876 int OutputToProcess(pr, message, count, outError)
7882 static int line = 0;
7883 ChildProc *cp = (ChildProc *) pr;
7888 if (appData.noJoin || !appData.useInternalWrap)
7889 outCount = fwrite(message, 1, count, stdout);
7892 int width = get_term_width();
7893 int len = wrap(NULL, message, count, width, &line);
7894 char *msg = malloc(len);
7898 outCount = fwrite(message, 1, count, stdout);
7901 dbgchk = wrap(msg, message, count, width, &line);
7902 if (dbgchk != len && appData.debugMode)
7903 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7904 outCount = fwrite(msg, 1, dbgchk, stdout);
7910 outCount = write(cp->fdTo, message, count);
7920 /* Output message to process, with "ms" milliseconds of delay
7921 between each character. This is needed when sending the logon
7922 script to ICC, which for some reason doesn't like the
7923 instantaneous send. */
7924 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7931 ChildProc *cp = (ChildProc *) pr;
7936 r = write(cp->fdTo, message++, 1);
7949 /**** Animation code by Hugh Fisher, DCS, ANU.
7951 Known problem: if a window overlapping the board is
7952 moved away while a piece is being animated underneath,
7953 the newly exposed area won't be updated properly.
7954 I can live with this.
7956 Known problem: if you look carefully at the animation
7957 of pieces in mono mode, they are being drawn as solid
7958 shapes without interior detail while moving. Fixing
7959 this would be a major complication for minimal return.
7962 /* Masks for XPM pieces. Black and white pieces can have
7963 different shapes, but in the interest of retaining my
7964 sanity pieces must have the same outline on both light
7965 and dark squares, and all pieces must use the same
7966 background square colors/images. */
7968 static int xpmDone = 0;
7971 CreateAnimMasks (pieceDepth)
7978 unsigned long plane;
7981 /* Need a bitmap just to get a GC with right depth */
7982 buf = XCreatePixmap(xDisplay, xBoardWindow,
7984 values.foreground = 1;
7985 values.background = 0;
7986 /* Don't use XtGetGC, not read only */
7987 maskGC = XCreateGC(xDisplay, buf,
7988 GCForeground | GCBackground, &values);
7989 XFreePixmap(xDisplay, buf);
7991 buf = XCreatePixmap(xDisplay, xBoardWindow,
7992 squareSize, squareSize, pieceDepth);
7993 values.foreground = XBlackPixel(xDisplay, xScreen);
7994 values.background = XWhitePixel(xDisplay, xScreen);
7995 bufGC = XCreateGC(xDisplay, buf,
7996 GCForeground | GCBackground, &values);
7998 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7999 /* Begin with empty mask */
8000 if(!xpmDone) // [HGM] pieces: keep using existing
8001 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8002 squareSize, squareSize, 1);
8003 XSetFunction(xDisplay, maskGC, GXclear);
8004 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8005 0, 0, squareSize, squareSize);
8007 /* Take a copy of the piece */
8012 XSetFunction(xDisplay, bufGC, GXcopy);
8013 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8015 0, 0, squareSize, squareSize, 0, 0);
8017 /* XOR the background (light) over the piece */
8018 XSetFunction(xDisplay, bufGC, GXxor);
8020 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8021 0, 0, squareSize, squareSize, 0, 0);
8023 XSetForeground(xDisplay, bufGC, lightSquareColor);
8024 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8027 /* We now have an inverted piece image with the background
8028 erased. Construct mask by just selecting all the non-zero
8029 pixels - no need to reconstruct the original image. */
8030 XSetFunction(xDisplay, maskGC, GXor);
8032 /* Might be quicker to download an XImage and create bitmap
8033 data from it rather than this N copies per piece, but it
8034 only takes a fraction of a second and there is a much
8035 longer delay for loading the pieces. */
8036 for (n = 0; n < pieceDepth; n ++) {
8037 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8038 0, 0, squareSize, squareSize,
8044 XFreePixmap(xDisplay, buf);
8045 XFreeGC(xDisplay, bufGC);
8046 XFreeGC(xDisplay, maskGC);
8050 InitAnimState (anim, info)
8052 XWindowAttributes * info;
8057 /* Each buffer is square size, same depth as window */
8058 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8059 squareSize, squareSize, info->depth);
8060 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8061 squareSize, squareSize, info->depth);
8063 /* Create a plain GC for blitting */
8064 mask = GCForeground | GCBackground | GCFunction |
8065 GCPlaneMask | GCGraphicsExposures;
8066 values.foreground = XBlackPixel(xDisplay, xScreen);
8067 values.background = XWhitePixel(xDisplay, xScreen);
8068 values.function = GXcopy;
8069 values.plane_mask = AllPlanes;
8070 values.graphics_exposures = False;
8071 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8073 /* Piece will be copied from an existing context at
8074 the start of each new animation/drag. */
8075 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8077 /* Outline will be a read-only copy of an existing */
8078 anim->outlineGC = None;
8084 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8085 XWindowAttributes info;
8087 if (xpmDone && gameInfo.variant == old) return;
8088 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8089 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8091 InitAnimState(&game, &info);
8092 InitAnimState(&player, &info);
8094 /* For XPM pieces, we need bitmaps to use as masks. */
8096 CreateAnimMasks(info.depth);
8102 static Boolean frameWaiting;
8104 static RETSIGTYPE FrameAlarm (sig)
8107 frameWaiting = False;
8108 /* In case System-V style signals. Needed?? */
8109 signal(SIGALRM, FrameAlarm);
8116 struct itimerval delay;
8118 XSync(xDisplay, False);
8121 frameWaiting = True;
8122 signal(SIGALRM, FrameAlarm);
8123 delay.it_interval.tv_sec =
8124 delay.it_value.tv_sec = time / 1000;
8125 delay.it_interval.tv_usec =
8126 delay.it_value.tv_usec = (time % 1000) * 1000;
8127 setitimer(ITIMER_REAL, &delay, NULL);
8128 while (frameWaiting) pause();
8129 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8130 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8131 setitimer(ITIMER_REAL, &delay, NULL);
8141 XSync(xDisplay, False);
8143 usleep(time * 1000);
8148 /* Convert board position to corner of screen rect and color */
8151 ScreenSquare(column, row, pt, color)
8152 int column; int row; XPoint * pt; int * color;
8155 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8156 pt->y = lineGap + row * (squareSize + lineGap);
8158 pt->x = lineGap + column * (squareSize + lineGap);
8159 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8161 *color = SquareColor(row, column);
8164 /* Convert window coords to square */
8167 BoardSquare(x, y, column, row)
8168 int x; int y; int * column; int * row;
8170 *column = EventToSquare(x, BOARD_WIDTH);
8171 if (flipView && *column >= 0)
8172 *column = BOARD_WIDTH - 1 - *column;
8173 *row = EventToSquare(y, BOARD_HEIGHT);
8174 if (!flipView && *row >= 0)
8175 *row = BOARD_HEIGHT - 1 - *row;
8180 #undef Max /* just in case */
8182 #define Max(a, b) ((a) > (b) ? (a) : (b))
8183 #define Min(a, b) ((a) < (b) ? (a) : (b))
8186 SetRect(rect, x, y, width, height)
8187 XRectangle * rect; int x; int y; int width; int height;
8191 rect->width = width;
8192 rect->height = height;
8195 /* Test if two frames overlap. If they do, return
8196 intersection rect within old and location of
8197 that rect within new. */
8200 Intersect(old, new, size, area, pt)
8201 XPoint * old; XPoint * new;
8202 int size; XRectangle * area; XPoint * pt;
8204 if (old->x > new->x + size || new->x > old->x + size ||
8205 old->y > new->y + size || new->y > old->y + size) {
8208 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8209 size - abs(old->x - new->x), size - abs(old->y - new->y));
8210 pt->x = Max(old->x - new->x, 0);
8211 pt->y = Max(old->y - new->y, 0);
8216 /* For two overlapping frames, return the rect(s)
8217 in the old that do not intersect with the new. */
8220 CalcUpdateRects(old, new, size, update, nUpdates)
8221 XPoint * old; XPoint * new; int size;
8222 XRectangle update[]; int * nUpdates;
8226 /* If old = new (shouldn't happen) then nothing to draw */
8227 if (old->x == new->x && old->y == new->y) {
8231 /* Work out what bits overlap. Since we know the rects
8232 are the same size we don't need a full intersect calc. */
8234 /* Top or bottom edge? */
8235 if (new->y > old->y) {
8236 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8238 } else if (old->y > new->y) {
8239 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8240 size, old->y - new->y);
8243 /* Left or right edge - don't overlap any update calculated above. */
8244 if (new->x > old->x) {
8245 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8246 new->x - old->x, size - abs(new->y - old->y));
8248 } else if (old->x > new->x) {
8249 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8250 old->x - new->x, size - abs(new->y - old->y));
8257 /* Generate a series of frame coords from start->mid->finish.
8258 The movement rate doubles until the half way point is
8259 reached, then halves back down to the final destination,
8260 which gives a nice slow in/out effect. The algorithmn
8261 may seem to generate too many intermediates for short
8262 moves, but remember that the purpose is to attract the
8263 viewers attention to the piece about to be moved and
8264 then to where it ends up. Too few frames would be less
8268 Tween(start, mid, finish, factor, frames, nFrames)
8269 XPoint * start; XPoint * mid;
8270 XPoint * finish; int factor;
8271 XPoint frames[]; int * nFrames;
8273 int fraction, n, count;
8277 /* Slow in, stepping 1/16th, then 1/8th, ... */
8279 for (n = 0; n < factor; n++)
8281 for (n = 0; n < factor; n++) {
8282 frames[count].x = start->x + (mid->x - start->x) / fraction;
8283 frames[count].y = start->y + (mid->y - start->y) / fraction;
8285 fraction = fraction / 2;
8289 frames[count] = *mid;
8292 /* Slow out, stepping 1/2, then 1/4, ... */
8294 for (n = 0; n < factor; n++) {
8295 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8296 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8298 fraction = fraction * 2;
8303 /* Draw a piece on the screen without disturbing what's there */
8306 SelectGCMask(piece, clip, outline, mask)
8307 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8311 /* Bitmap for piece being moved. */
8312 if (appData.monoMode) {
8313 *mask = *pieceToSolid(piece);
8314 } else if (useImages) {
8316 *mask = xpmMask[piece];
8318 *mask = ximMaskPm[piece];
8321 *mask = *pieceToSolid(piece);
8324 /* GC for piece being moved. Square color doesn't matter, but
8325 since it gets modified we make a copy of the original. */
8327 if (appData.monoMode)
8332 if (appData.monoMode)
8337 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8339 /* Outline only used in mono mode and is not modified */
8341 *outline = bwPieceGC;
8343 *outline = wbPieceGC;
8347 OverlayPiece(piece, clip, outline, dest)
8348 ChessSquare piece; GC clip; GC outline; Drawable dest;
8353 /* Draw solid rectangle which will be clipped to shape of piece */
8354 XFillRectangle(xDisplay, dest, clip,
8355 0, 0, squareSize, squareSize);
8356 if (appData.monoMode)
8357 /* Also draw outline in contrasting color for black
8358 on black / white on white cases */
8359 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8360 0, 0, squareSize, squareSize, 0, 0, 1);
8362 /* Copy the piece */
8367 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8369 0, 0, squareSize, squareSize,
8374 /* Animate the movement of a single piece */
8377 BeginAnimation(anim, piece, startColor, start)
8385 /* The old buffer is initialised with the start square (empty) */
8386 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8387 anim->prevFrame = *start;
8389 /* The piece will be drawn using its own bitmap as a matte */
8390 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8391 XSetClipMask(xDisplay, anim->pieceGC, mask);
8395 AnimationFrame(anim, frame, piece)
8400 XRectangle updates[4];
8405 /* Save what we are about to draw into the new buffer */
8406 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8407 frame->x, frame->y, squareSize, squareSize,
8410 /* Erase bits of the previous frame */
8411 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8412 /* Where the new frame overlapped the previous,
8413 the contents in newBuf are wrong. */
8414 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8415 overlap.x, overlap.y,
8416 overlap.width, overlap.height,
8418 /* Repaint the areas in the old that don't overlap new */
8419 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8420 for (i = 0; i < count; i++)
8421 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8422 updates[i].x - anim->prevFrame.x,
8423 updates[i].y - anim->prevFrame.y,
8424 updates[i].width, updates[i].height,
8425 updates[i].x, updates[i].y);
8427 /* Easy when no overlap */
8428 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8429 0, 0, squareSize, squareSize,
8430 anim->prevFrame.x, anim->prevFrame.y);
8433 /* Save this frame for next time round */
8434 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8435 0, 0, squareSize, squareSize,
8437 anim->prevFrame = *frame;
8439 /* Draw piece over original screen contents, not current,
8440 and copy entire rect. Wipes out overlapping piece images. */
8441 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8442 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8443 0, 0, squareSize, squareSize,
8444 frame->x, frame->y);
8448 EndAnimation (anim, finish)
8452 XRectangle updates[4];
8457 /* The main code will redraw the final square, so we
8458 only need to erase the bits that don't overlap. */
8459 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8460 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8461 for (i = 0; i < count; i++)
8462 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8463 updates[i].x - anim->prevFrame.x,
8464 updates[i].y - anim->prevFrame.y,
8465 updates[i].width, updates[i].height,
8466 updates[i].x, updates[i].y);
8468 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8469 0, 0, squareSize, squareSize,
8470 anim->prevFrame.x, anim->prevFrame.y);
8475 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8477 ChessSquare piece; int startColor;
8478 XPoint * start; XPoint * finish;
8479 XPoint frames[]; int nFrames;
8483 BeginAnimation(anim, piece, startColor, start);
8484 for (n = 0; n < nFrames; n++) {
8485 AnimationFrame(anim, &(frames[n]), piece);
8486 FrameDelay(appData.animSpeed);
8488 EndAnimation(anim, finish);
8491 /* Main control logic for deciding what to animate and how */
8494 AnimateMove(board, fromX, fromY, toX, toY)
8503 XPoint start, finish, mid;
8504 XPoint frames[kFactor * 2 + 1];
8505 int nFrames, startColor, endColor;
8507 /* Are we animating? */
8508 if (!appData.animate || appData.blindfold)
8511 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8512 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8513 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8515 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8516 piece = board[fromY][fromX];
8517 if (piece >= EmptySquare) return;
8522 hop = (piece == WhiteKnight || piece == BlackKnight);
8525 if (appData.debugMode) {
8526 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8527 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8528 piece, fromX, fromY, toX, toY); }
8530 ScreenSquare(fromX, fromY, &start, &startColor);
8531 ScreenSquare(toX, toY, &finish, &endColor);
8534 /* Knight: make diagonal movement then straight */
8535 if (abs(toY - fromY) < abs(toX - fromX)) {
8536 mid.x = start.x + (finish.x - start.x) / 2;
8540 mid.y = start.y + (finish.y - start.y) / 2;
8543 mid.x = start.x + (finish.x - start.x) / 2;
8544 mid.y = start.y + (finish.y - start.y) / 2;
8547 /* Don't use as many frames for very short moves */
8548 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8549 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8551 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8552 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8554 /* Be sure end square is redrawn */
8555 damage[toY][toX] = True;
8559 DragPieceBegin(x, y)
8562 int boardX, boardY, color;
8565 /* Are we animating? */
8566 if (!appData.animateDragging || appData.blindfold)
8569 /* Figure out which square we start in and the
8570 mouse position relative to top left corner. */
8571 BoardSquare(x, y, &boardX, &boardY);
8572 player.startBoardX = boardX;
8573 player.startBoardY = boardY;
8574 ScreenSquare(boardX, boardY, &corner, &color);
8575 player.startSquare = corner;
8576 player.startColor = color;
8577 /* As soon as we start dragging, the piece will jump slightly to
8578 be centered over the mouse pointer. */
8579 player.mouseDelta.x = squareSize/2;
8580 player.mouseDelta.y = squareSize/2;
8581 /* Initialise animation */
8582 player.dragPiece = PieceForSquare(boardX, boardY);
8584 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8585 player.dragActive = True;
8586 BeginAnimation(&player, player.dragPiece, color, &corner);
8587 /* Mark this square as needing to be redrawn. Note that
8588 we don't remove the piece though, since logically (ie
8589 as seen by opponent) the move hasn't been made yet. */
8590 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8591 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8592 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8593 corner.x, corner.y, squareSize, squareSize,
8594 0, 0); // [HGM] zh: unstack in stead of grab
8595 damage[boardY][boardX] = True;
8597 player.dragActive = False;
8607 /* Are we animating? */
8608 if (!appData.animateDragging || appData.blindfold)
8612 if (! player.dragActive)
8614 /* Move piece, maintaining same relative position
8615 of mouse within square */
8616 corner.x = x - player.mouseDelta.x;
8617 corner.y = y - player.mouseDelta.y;
8618 AnimationFrame(&player, &corner, player.dragPiece);
8620 if (appData.highlightDragging) {
8622 BoardSquare(x, y, &boardX, &boardY);
8623 SetHighlights(fromX, fromY, boardX, boardY);
8632 int boardX, boardY, color;
8635 /* Are we animating? */
8636 if (!appData.animateDragging || appData.blindfold)
8640 if (! player.dragActive)
8642 /* Last frame in sequence is square piece is
8643 placed on, which may not match mouse exactly. */
8644 BoardSquare(x, y, &boardX, &boardY);
8645 ScreenSquare(boardX, boardY, &corner, &color);
8646 EndAnimation(&player, &corner);
8648 /* Be sure end square is redrawn */
8649 damage[boardY][boardX] = True;
8651 /* This prevents weird things happening with fast successive
8652 clicks which on my Sun at least can cause motion events
8653 without corresponding press/release. */
8654 player.dragActive = False;
8657 /* Handle expose event while piece being dragged */
8662 if (!player.dragActive || appData.blindfold)
8665 /* What we're doing: logically, the move hasn't been made yet,
8666 so the piece is still in it's original square. But visually
8667 it's being dragged around the board. So we erase the square
8668 that the piece is on and draw it at the last known drag point. */
8669 BlankSquare(player.startSquare.x, player.startSquare.y,
8670 player.startColor, EmptySquare, xBoardWindow);
8671 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8672 damage[player.startBoardY][player.startBoardX] = TRUE;
8675 #include <sys/ioctl.h>
8676 int get_term_width()
8678 int fd, default_width;
8681 default_width = 79; // this is FICS default anyway...
8683 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8685 if (!ioctl(fd, TIOCGSIZE, &win))
8686 default_width = win.ts_cols;
8687 #elif defined(TIOCGWINSZ)
8689 if (!ioctl(fd, TIOCGWINSZ, &win))
8690 default_width = win.ws_col;
8692 return default_width;
8695 void update_ics_width()
8697 static int old_width = 0;
8698 int new_width = get_term_width();
8700 if (old_width != new_width)
8701 ics_printf("set width %d\n", new_width);
8702 old_width = new_width;
8705 void NotifyFrontendLogin()