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)
1253 // these two must some day move to frontend.h, when they are implemented
1254 Boolean EvalGraphIsUp();
1255 Boolean MoveHistoryIsUp();
1256 Boolean GameListIsUp();
1258 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1261 // front-end part of option handling
1263 // [HGM] This platform-dependent table provides the location for storing the color info
1266 &appData.whitePieceColor,
1267 &appData.blackPieceColor,
1268 &appData.lightSquareColor,
1269 &appData.darkSquareColor,
1270 &appData.highlightSquareColor,
1271 &appData.premoveHighlightColor,
1284 ParseFont(char *name, int number)
1285 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1287 case 0: // CLOCK_FONT
1288 appData.clockFont = strdup(name);
1290 case 1: // MESSAGE_FONT
1291 appData.font = strdup(name);
1293 case 2: // COORD_FONT
1294 appData.coordFont = strdup(name);
1303 { // only 2 fonts currently
1304 appData.clockFont = CLOCK_FONT_NAME;
1305 appData.coordFont = COORD_FONT_NAME;
1306 appData.font = DEFAULT_FONT_NAME;
1311 { // no-op, until we identify the code for this already in XBoard and move it here
1315 ParseColor(int n, char *name)
1316 { // in XBoard, just copy the color-name string
1317 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1321 ParseTextAttribs(ColorClass cc, char *s)
1323 (&appData.colorShout)[cc] = strdup(s);
1327 ParseBoardSize(void *addr, char *name)
1329 appData.boardSize = strdup(name);
1334 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1338 SetCommPortDefaults()
1339 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1342 // [HGM] args: these three cases taken out to stay in front-end
1344 SaveFontArg(FILE *f, ArgDescriptor *ad)
1347 switch((int)ad->argLoc) {
1348 case 0: // CLOCK_FONT
1349 name = appData.clockFont;
1351 case 1: // MESSAGE_FONT
1352 name = appData.font;
1354 case 2: // COORD_FONT
1355 name = appData.coordFont;
1360 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1365 { // nothing to do, as the sounds are at all times represented by their text-string names already
1369 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1370 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1371 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1375 SaveColor(FILE *f, ArgDescriptor *ad)
1376 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1377 if(colorVariable[(int)ad->argLoc])
1378 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1382 SaveBoardSize(FILE *f, char *name, void *addr)
1383 { // wrapper to shield back-end from BoardSize & sizeInfo
1384 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1388 ParseCommPortSettings(char *s)
1389 { // no such option in XBoard (yet)
1392 extern Widget engineOutputShell;
1393 extern Widget tagsShell, editTagsShell;
1395 GetActualPlacement(Widget wg, WindowPlacement *wp)
1405 XtSetArg(args[i], XtNx, &x); i++;
1406 XtSetArg(args[i], XtNy, &y); i++;
1407 XtSetArg(args[i], XtNwidth, &w); i++;
1408 XtSetArg(args[i], XtNheight, &h); i++;
1409 XtGetValues(wg, args, i);
1418 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1419 // In XBoard this will have to wait until awareness of window parameters is implemented
1420 GetActualPlacement(shellWidget, &wpMain);
1421 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1422 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1423 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1424 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1425 else GetActualPlacement(editShell, &wpComment);
1426 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1427 else GetActualPlacement(editTagsShell, &wpTags);
1429 GetActualPlacement(hwndConsole, &wpConsole);
1430 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
1435 PrintCommPortSettings(FILE *f, char *name)
1436 { // This option does not exist in XBoard
1440 MySearchPath(char *installDir, char *name, char *fullname)
1441 { // just append installDir and name. Perhaps ExpandPath should be used here?
1442 name = ExpandPathName(name);
1443 if(name && name[0] == '/') strcpy(fullname, name); else {
1444 sprintf(fullname, "%s%c%s", installDir, '/', name);
1450 MyGetFullPathName(char *name, char *fullname)
1451 { // should use ExpandPath?
1452 name = ExpandPathName(name);
1453 strcpy(fullname, name);
1458 EnsureOnScreen(int *x, int *y, int minX, int minY)
1471 { // [HGM] args: allows testing if main window is realized from back-end
1472 return xBoardWindow != 0;
1476 PopUpStartupDialog()
1477 { // start menu not implemented in XBoard
1480 ConvertToLine(int argc, char **argv)
1482 static char line[128*1024], buf[1024];
1486 for(i=1; i<argc; i++) {
1487 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1488 && argv[i][0] != '{' )
1489 sprintf(buf, "{%s} ", argv[i]);
1490 else sprintf(buf, "%s ", argv[i]);
1493 line[strlen(line)-1] = NULLCHAR;
1497 //--------------------------------------------------------------------------------------------
1500 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1502 #define BoardSize int
1503 void InitDrawingSizes(BoardSize boardSize, int flags)
1504 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1505 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1507 XtGeometryResult gres;
1510 if(!formWidget) return;
1513 * Enable shell resizing.
1515 shellArgs[0].value = (XtArgVal) &w;
1516 shellArgs[1].value = (XtArgVal) &h;
1517 XtGetValues(shellWidget, shellArgs, 2);
1519 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1520 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1521 XtSetValues(shellWidget, &shellArgs[2], 4);
1523 XtSetArg(args[0], XtNdefaultDistance, &sep);
1524 XtGetValues(formWidget, args, 1);
1526 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1527 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1530 XtSetArg(args[0], XtNwidth, boardWidth);
1531 XtSetArg(args[1], XtNheight, boardHeight);
1532 XtSetValues(boardWidget, args, 2);
1534 timerWidth = (boardWidth - sep) / 2;
1535 XtSetArg(args[0], XtNwidth, timerWidth);
1536 XtSetValues(whiteTimerWidget, args, 1);
1537 XtSetValues(blackTimerWidget, args, 1);
1539 XawFormDoLayout(formWidget, False);
1541 if (appData.titleInWindow) {
1543 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1544 XtSetArg(args[i], XtNheight, &h); i++;
1545 XtGetValues(titleWidget, args, i);
1547 w = boardWidth - 2*bor;
1549 XtSetArg(args[0], XtNwidth, &w);
1550 XtGetValues(menuBarWidget, args, 1);
1551 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1554 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1555 if (gres != XtGeometryYes && appData.debugMode) {
1557 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1558 programName, gres, w, h, wr, hr);
1562 XawFormDoLayout(formWidget, True);
1565 * Inhibit shell resizing.
1567 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1568 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1569 shellArgs[4].value = shellArgs[2].value = w;
1570 shellArgs[5].value = shellArgs[3].value = h;
1571 XtSetValues(shellWidget, &shellArgs[0], 6);
1573 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1576 for(i=0; i<4; i++) {
1578 for(p=0; p<=(int)WhiteKing; p++)
1579 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1580 if(gameInfo.variant == VariantShogi) {
1581 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1582 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1583 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1584 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1585 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1588 if(gameInfo.variant == VariantGothic) {
1589 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1593 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1594 for(p=0; p<=(int)WhiteKing; p++)
1595 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1596 if(gameInfo.variant == VariantShogi) {
1597 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1598 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1599 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1600 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1601 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1604 if(gameInfo.variant == VariantGothic) {
1605 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1611 for(i=0; i<2; i++) {
1613 for(p=0; p<=(int)WhiteKing; p++)
1614 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1615 if(gameInfo.variant == VariantShogi) {
1616 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1617 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1618 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1619 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1620 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1623 if(gameInfo.variant == VariantGothic) {
1624 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1635 void EscapeExpand(char *p, char *q)
1636 { // [HGM] initstring: routine to shape up string arguments
1637 while(*p++ = *q++) if(p[-1] == '\\')
1639 case 'n': p[-1] = '\n'; break;
1640 case 'r': p[-1] = '\r'; break;
1641 case 't': p[-1] = '\t'; break;
1642 case '\\': p[-1] = '\\'; break;
1643 case 0: *p = 0; return;
1644 default: p[-1] = q[-1]; break;
1653 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1654 XSetWindowAttributes window_attributes;
1656 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1657 XrmValue vFrom, vTo;
1658 XtGeometryResult gres;
1661 int forceMono = False;
1662 //define INDIRECTION
1664 // [HGM] before anything else, expand any indirection files amongst options
1665 char *argvCopy[1000]; // 1000 seems enough
1666 char newArgs[10000]; // holds actual characters
1669 srandom(time(0)); // [HGM] book: make random truly random
1672 for(i=0; i<argc; i++) {
1673 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1674 //fprintf(stderr, "arg %s\n", argv[i]);
1675 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1677 FILE *f = fopen(argv[i]+1, "rb");
1678 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1679 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1680 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1682 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1683 newArgs[k++] = 0; // terminate current arg
1684 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1685 argvCopy[j++] = newArgs + k; // get ready for next
1687 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1701 setbuf(stdout, NULL);
1702 setbuf(stderr, NULL);
1705 programName = strrchr(argv[0], '/');
1706 if (programName == NULL)
1707 programName = argv[0];
1712 XtSetLanguageProc(NULL, NULL, NULL);
1713 bindtextdomain(PACKAGE, LOCALEDIR);
1714 textdomain(PACKAGE);
1718 XtAppInitialize(&appContext, "XBoard", shellOptions,
1719 XtNumber(shellOptions),
1720 &argc, argv, xboardResources, NULL, 0);
1721 appData.boardSize = "";
1722 InitAppData(ConvertToLine(argc, argv));
1724 if (p == NULL) p = "/tmp";
1725 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1726 gameCopyFilename = (char*) malloc(i);
1727 gamePasteFilename = (char*) malloc(i);
1728 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1729 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1731 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1732 clientResources, XtNumber(clientResources),
1735 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1736 static char buf[MSG_SIZ];
1737 EscapeExpand(buf, appData.initString);
1738 appData.initString = strdup(buf);
1739 EscapeExpand(buf, appData.secondInitString);
1740 appData.secondInitString = strdup(buf);
1741 EscapeExpand(buf, appData.firstComputerString);
1742 appData.firstComputerString = strdup(buf);
1743 EscapeExpand(buf, appData.secondComputerString);
1744 appData.secondComputerString = strdup(buf);
1747 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1750 if (chdir(chessDir) != 0) {
1751 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1757 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1758 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1759 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1760 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1763 setbuf(debugFP, NULL);
1766 /* [HGM,HR] make sure board size is acceptable */
1767 if(appData.NrFiles > BOARD_FILES ||
1768 appData.NrRanks > BOARD_RANKS )
1769 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1772 /* This feature does not work; animation needs a rewrite */
1773 appData.highlightDragging = FALSE;
1777 xDisplay = XtDisplay(shellWidget);
1778 xScreen = DefaultScreen(xDisplay);
1779 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1781 gameInfo.variant = StringToVariant(appData.variant);
1782 InitPosition(FALSE);
1785 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1787 if (isdigit(appData.boardSize[0])) {
1788 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1789 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1790 &fontPxlSize, &smallLayout, &tinyLayout);
1792 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1793 programName, appData.boardSize);
1797 /* Find some defaults; use the nearest known size */
1798 SizeDefaults *szd, *nearest;
1799 int distance = 99999;
1800 nearest = szd = sizeDefaults;
1801 while (szd->name != NULL) {
1802 if (abs(szd->squareSize - squareSize) < distance) {
1804 distance = abs(szd->squareSize - squareSize);
1805 if (distance == 0) break;
1809 if (i < 2) lineGap = nearest->lineGap;
1810 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1811 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1812 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1813 if (i < 6) smallLayout = nearest->smallLayout;
1814 if (i < 7) tinyLayout = nearest->tinyLayout;
1817 SizeDefaults *szd = sizeDefaults;
1818 if (*appData.boardSize == NULLCHAR) {
1819 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1820 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1823 if (szd->name == NULL) szd--;
1824 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1826 while (szd->name != NULL &&
1827 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1828 if (szd->name == NULL) {
1829 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1830 programName, appData.boardSize);
1834 squareSize = szd->squareSize;
1835 lineGap = szd->lineGap;
1836 clockFontPxlSize = szd->clockFontPxlSize;
1837 coordFontPxlSize = szd->coordFontPxlSize;
1838 fontPxlSize = szd->fontPxlSize;
1839 smallLayout = szd->smallLayout;
1840 tinyLayout = szd->tinyLayout;
1843 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1844 if (strlen(appData.pixmapDirectory) > 0) {
1845 p = ExpandPathName(appData.pixmapDirectory);
1847 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1848 appData.pixmapDirectory);
1851 if (appData.debugMode) {
1852 fprintf(stderr, _("\
1853 XBoard square size (hint): %d\n\
1854 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1856 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1857 if (appData.debugMode) {
1858 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1862 /* [HR] height treated separately (hacked) */
1863 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1864 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1865 if (appData.showJail == 1) {
1866 /* Jail on top and bottom */
1867 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1868 XtSetArg(boardArgs[2], XtNheight,
1869 boardHeight + 2*(lineGap + squareSize));
1870 } else if (appData.showJail == 2) {
1872 XtSetArg(boardArgs[1], XtNwidth,
1873 boardWidth + 2*(lineGap + squareSize));
1874 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1877 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1878 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1882 * Determine what fonts to use.
1884 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1885 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1886 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1887 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1888 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1889 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1890 appData.font = FindFont(appData.font, fontPxlSize);
1891 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1892 countFontStruct = XQueryFont(xDisplay, countFontID);
1893 // appData.font = FindFont(appData.font, fontPxlSize);
1895 xdb = XtDatabase(xDisplay);
1896 XrmPutStringResource(&xdb, "*font", appData.font);
1899 * Detect if there are not enough colors available and adapt.
1901 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1902 appData.monoMode = True;
1905 if (!appData.monoMode) {
1906 vFrom.addr = (caddr_t) appData.lightSquareColor;
1907 vFrom.size = strlen(appData.lightSquareColor);
1908 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1909 if (vTo.addr == NULL) {
1910 appData.monoMode = True;
1913 lightSquareColor = *(Pixel *) vTo.addr;
1916 if (!appData.monoMode) {
1917 vFrom.addr = (caddr_t) appData.darkSquareColor;
1918 vFrom.size = strlen(appData.darkSquareColor);
1919 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1920 if (vTo.addr == NULL) {
1921 appData.monoMode = True;
1924 darkSquareColor = *(Pixel *) vTo.addr;
1927 if (!appData.monoMode) {
1928 vFrom.addr = (caddr_t) appData.whitePieceColor;
1929 vFrom.size = strlen(appData.whitePieceColor);
1930 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1931 if (vTo.addr == NULL) {
1932 appData.monoMode = True;
1935 whitePieceColor = *(Pixel *) vTo.addr;
1938 if (!appData.monoMode) {
1939 vFrom.addr = (caddr_t) appData.blackPieceColor;
1940 vFrom.size = strlen(appData.blackPieceColor);
1941 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1942 if (vTo.addr == NULL) {
1943 appData.monoMode = True;
1946 blackPieceColor = *(Pixel *) vTo.addr;
1950 if (!appData.monoMode) {
1951 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1952 vFrom.size = strlen(appData.highlightSquareColor);
1953 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1954 if (vTo.addr == NULL) {
1955 appData.monoMode = True;
1958 highlightSquareColor = *(Pixel *) vTo.addr;
1962 if (!appData.monoMode) {
1963 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1964 vFrom.size = strlen(appData.premoveHighlightColor);
1965 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1966 if (vTo.addr == NULL) {
1967 appData.monoMode = True;
1970 premoveHighlightColor = *(Pixel *) vTo.addr;
1975 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1978 if (appData.bitmapDirectory == NULL ||
1979 appData.bitmapDirectory[0] == NULLCHAR)
1980 appData.bitmapDirectory = DEF_BITMAP_DIR;
1983 if (appData.lowTimeWarning && !appData.monoMode) {
1984 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1985 vFrom.size = strlen(appData.lowTimeWarningColor);
1986 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1987 if (vTo.addr == NULL)
1988 appData.monoMode = True;
1990 lowTimeWarningColor = *(Pixel *) vTo.addr;
1993 if (appData.monoMode && appData.debugMode) {
1994 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1995 (unsigned long) XWhitePixel(xDisplay, xScreen),
1996 (unsigned long) XBlackPixel(xDisplay, xScreen));
1999 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2000 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2001 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2002 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2003 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2004 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2005 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2006 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2007 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2008 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2010 if (appData.colorize) {
2012 _("%s: can't parse color names; disabling colorization\n"),
2015 appData.colorize = FALSE;
2017 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2018 textColors[ColorNone].attr = 0;
2020 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2026 layoutName = "tinyLayout";
2027 } else if (smallLayout) {
2028 layoutName = "smallLayout";
2030 layoutName = "normalLayout";
2032 /* Outer layoutWidget is there only to provide a name for use in
2033 resources that depend on the layout style */
2035 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2036 layoutArgs, XtNumber(layoutArgs));
2038 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2039 formArgs, XtNumber(formArgs));
2040 XtSetArg(args[0], XtNdefaultDistance, &sep);
2041 XtGetValues(formWidget, args, 1);
2044 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2045 XtSetArg(args[0], XtNtop, XtChainTop);
2046 XtSetArg(args[1], XtNbottom, XtChainTop);
2047 XtSetArg(args[2], XtNright, XtChainLeft);
2048 XtSetValues(menuBarWidget, args, 3);
2050 widgetList[j++] = whiteTimerWidget =
2051 XtCreateWidget("whiteTime", labelWidgetClass,
2052 formWidget, timerArgs, XtNumber(timerArgs));
2053 XtSetArg(args[0], XtNfont, clockFontStruct);
2054 XtSetArg(args[1], XtNtop, XtChainTop);
2055 XtSetArg(args[2], XtNbottom, XtChainTop);
2056 XtSetValues(whiteTimerWidget, args, 3);
2058 widgetList[j++] = blackTimerWidget =
2059 XtCreateWidget("blackTime", labelWidgetClass,
2060 formWidget, timerArgs, XtNumber(timerArgs));
2061 XtSetArg(args[0], XtNfont, clockFontStruct);
2062 XtSetArg(args[1], XtNtop, XtChainTop);
2063 XtSetArg(args[2], XtNbottom, XtChainTop);
2064 XtSetValues(blackTimerWidget, args, 3);
2066 if (appData.titleInWindow) {
2067 widgetList[j++] = titleWidget =
2068 XtCreateWidget("title", labelWidgetClass, formWidget,
2069 titleArgs, XtNumber(titleArgs));
2070 XtSetArg(args[0], XtNtop, XtChainTop);
2071 XtSetArg(args[1], XtNbottom, XtChainTop);
2072 XtSetValues(titleWidget, args, 2);
2075 if (appData.showButtonBar) {
2076 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2077 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2078 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2079 XtSetArg(args[2], XtNtop, XtChainTop);
2080 XtSetArg(args[3], XtNbottom, XtChainTop);
2081 XtSetValues(buttonBarWidget, args, 4);
2084 widgetList[j++] = messageWidget =
2085 XtCreateWidget("message", labelWidgetClass, formWidget,
2086 messageArgs, XtNumber(messageArgs));
2087 XtSetArg(args[0], XtNtop, XtChainTop);
2088 XtSetArg(args[1], XtNbottom, XtChainTop);
2089 XtSetValues(messageWidget, args, 2);
2091 widgetList[j++] = boardWidget =
2092 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2093 XtNumber(boardArgs));
2095 XtManageChildren(widgetList, j);
2097 timerWidth = (boardWidth - sep) / 2;
2098 XtSetArg(args[0], XtNwidth, timerWidth);
2099 XtSetValues(whiteTimerWidget, args, 1);
2100 XtSetValues(blackTimerWidget, args, 1);
2102 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2103 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2104 XtGetValues(whiteTimerWidget, args, 2);
2106 if (appData.showButtonBar) {
2107 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2108 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2109 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2113 * formWidget uses these constraints but they are stored
2117 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2118 XtSetValues(menuBarWidget, args, i);
2119 if (appData.titleInWindow) {
2122 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2123 XtSetValues(whiteTimerWidget, args, i);
2125 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2126 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2127 XtSetValues(blackTimerWidget, args, i);
2129 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2130 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2131 XtSetValues(titleWidget, args, i);
2133 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2134 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2135 XtSetValues(messageWidget, args, i);
2136 if (appData.showButtonBar) {
2138 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2139 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2140 XtSetValues(buttonBarWidget, args, i);
2144 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2145 XtSetValues(whiteTimerWidget, args, i);
2147 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2148 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2149 XtSetValues(blackTimerWidget, args, i);
2151 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2152 XtSetValues(titleWidget, args, i);
2154 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2155 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2156 XtSetValues(messageWidget, args, i);
2157 if (appData.showButtonBar) {
2159 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2160 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2161 XtSetValues(buttonBarWidget, args, i);
2166 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2167 XtSetValues(whiteTimerWidget, args, i);
2169 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2170 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2171 XtSetValues(blackTimerWidget, args, i);
2173 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2174 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2175 XtSetValues(messageWidget, args, i);
2176 if (appData.showButtonBar) {
2178 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2179 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2180 XtSetValues(buttonBarWidget, args, i);
2184 XtSetArg(args[0], XtNfromVert, messageWidget);
2185 XtSetArg(args[1], XtNtop, XtChainTop);
2186 XtSetArg(args[2], XtNbottom, XtChainBottom);
2187 XtSetArg(args[3], XtNleft, XtChainLeft);
2188 XtSetArg(args[4], XtNright, XtChainRight);
2189 XtSetValues(boardWidget, args, 5);
2191 XtRealizeWidget(shellWidget);
2194 XtSetArg(args[0], XtNx, wpMain.x);
2195 XtSetArg(args[1], XtNy, wpMain.y);
2196 XtSetValues(shellWidget, args, 2);
2200 * Correct the width of the message and title widgets.
2201 * It is not known why some systems need the extra fudge term.
2202 * The value "2" is probably larger than needed.
2204 XawFormDoLayout(formWidget, False);
2206 #define WIDTH_FUDGE 2
2208 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2209 XtSetArg(args[i], XtNheight, &h); i++;
2210 XtGetValues(messageWidget, args, i);
2211 if (appData.showButtonBar) {
2213 XtSetArg(args[i], XtNwidth, &w); i++;
2214 XtGetValues(buttonBarWidget, args, i);
2215 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2217 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2220 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2221 if (gres != XtGeometryYes && appData.debugMode) {
2222 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2223 programName, gres, w, h, wr, hr);
2226 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2227 /* The size used for the child widget in layout lags one resize behind
2228 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2230 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2231 if (gres != XtGeometryYes && appData.debugMode) {
2232 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2233 programName, gres, w, h, wr, hr);
2236 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2237 XtSetArg(args[1], XtNright, XtChainRight);
2238 XtSetValues(messageWidget, args, 2);
2240 if (appData.titleInWindow) {
2242 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2243 XtSetArg(args[i], XtNheight, &h); i++;
2244 XtGetValues(titleWidget, args, i);
2246 w = boardWidth - 2*bor;
2248 XtSetArg(args[0], XtNwidth, &w);
2249 XtGetValues(menuBarWidget, args, 1);
2250 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2253 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2254 if (gres != XtGeometryYes && appData.debugMode) {
2256 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2257 programName, gres, w, h, wr, hr);
2260 XawFormDoLayout(formWidget, True);
2262 xBoardWindow = XtWindow(boardWidget);
2264 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2265 // not need to go into InitDrawingSizes().
2269 * Create X checkmark bitmap and initialize option menu checks.
2271 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2272 checkmark_bits, checkmark_width, checkmark_height);
2273 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2274 if (appData.alwaysPromoteToQueen) {
2275 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2278 if (appData.animateDragging) {
2279 XtSetValues(XtNameToWidget(menuBarWidget,
2280 "menuOptions.Animate Dragging"),
2283 if (appData.animate) {
2284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2287 if (appData.autoComment) {
2288 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2291 if (appData.autoCallFlag) {
2292 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2295 if (appData.autoFlipView) {
2296 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2299 if (appData.autoObserve) {
2300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2303 if (appData.autoRaiseBoard) {
2304 XtSetValues(XtNameToWidget(menuBarWidget,
2305 "menuOptions.Auto Raise Board"), args, 1);
2307 if (appData.autoSaveGames) {
2308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2311 if (appData.saveGameFile[0] != NULLCHAR) {
2312 /* Can't turn this off from menu */
2313 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2315 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2319 if (appData.blindfold) {
2320 XtSetValues(XtNameToWidget(menuBarWidget,
2321 "menuOptions.Blindfold"), args, 1);
2323 if (appData.flashCount > 0) {
2324 XtSetValues(XtNameToWidget(menuBarWidget,
2325 "menuOptions.Flash Moves"),
2328 if (appData.getMoveList) {
2329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2333 if (appData.highlightDragging) {
2334 XtSetValues(XtNameToWidget(menuBarWidget,
2335 "menuOptions.Highlight Dragging"),
2339 if (appData.highlightLastMove) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Highlight Last Move"),
2344 if (appData.icsAlarm) {
2345 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2348 if (appData.ringBellAfterMoves) {
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2352 if (appData.oldSaveStyle) {
2353 XtSetValues(XtNameToWidget(menuBarWidget,
2354 "menuOptions.Old Save Style"), args, 1);
2356 if (appData.periodicUpdates) {
2357 XtSetValues(XtNameToWidget(menuBarWidget,
2358 "menuOptions.Periodic Updates"), args, 1);
2360 if (appData.ponderNextMove) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,
2362 "menuOptions.Ponder Next Move"), args, 1);
2364 if (appData.popupExitMessage) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,
2366 "menuOptions.Popup Exit Message"), args, 1);
2368 if (appData.popupMoveErrors) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Popup Move Errors"), args, 1);
2372 if (appData.premove) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Premove"), args, 1);
2376 if (appData.quietPlay) {
2377 XtSetValues(XtNameToWidget(menuBarWidget,
2378 "menuOptions.Quiet Play"), args, 1);
2380 if (appData.showCoords) {
2381 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2384 if (appData.hideThinkingFromHuman) {
2385 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2388 if (appData.testLegality) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2392 if (saveSettingsOnExit) {
2393 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2400 ReadBitmap(&wIconPixmap, "icon_white.bm",
2401 icon_white_bits, icon_white_width, icon_white_height);
2402 ReadBitmap(&bIconPixmap, "icon_black.bm",
2403 icon_black_bits, icon_black_width, icon_black_height);
2404 iconPixmap = wIconPixmap;
2406 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2407 XtSetValues(shellWidget, args, i);
2410 * Create a cursor for the board widget.
2412 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2413 XChangeWindowAttributes(xDisplay, xBoardWindow,
2414 CWCursor, &window_attributes);
2417 * Inhibit shell resizing.
2419 shellArgs[0].value = (XtArgVal) &w;
2420 shellArgs[1].value = (XtArgVal) &h;
2421 XtGetValues(shellWidget, shellArgs, 2);
2422 shellArgs[4].value = shellArgs[2].value = w;
2423 shellArgs[5].value = shellArgs[3].value = h;
2424 XtSetValues(shellWidget, &shellArgs[2], 4);
2425 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2426 marginH = h - boardHeight;
2428 CatchDeleteWindow(shellWidget, "QuitProc");
2433 if (appData.bitmapDirectory[0] != NULLCHAR) {
2440 /* Create regular pieces */
2441 if (!useImages) CreatePieces();
2446 if (appData.animate || appData.animateDragging)
2449 XtAugmentTranslations(formWidget,
2450 XtParseTranslationTable(globalTranslations));
2451 XtAugmentTranslations(boardWidget,
2452 XtParseTranslationTable(boardTranslations));
2453 XtAugmentTranslations(whiteTimerWidget,
2454 XtParseTranslationTable(whiteTranslations));
2455 XtAugmentTranslations(blackTimerWidget,
2456 XtParseTranslationTable(blackTranslations));
2458 /* Why is the following needed on some versions of X instead
2459 * of a translation? */
2460 XtAddEventHandler(boardWidget, ExposureMask, False,
2461 (XtEventHandler) EventProc, NULL);
2464 /* [AS] Restore layout */
2465 if( wpMoveHistory.visible ) {
2469 // if( wpEvalGraph.visible ) {
2470 // EvalGraphPopUp();
2473 if( wpEngineOutput.visible ) {
2474 EngineOutputPopUp();
2479 if (errorExitStatus == -1) {
2480 if (appData.icsActive) {
2481 /* We now wait until we see "login:" from the ICS before
2482 sending the logon script (problems with timestamp otherwise) */
2483 /*ICSInitScript();*/
2484 if (appData.icsInputBox) ICSInputBoxPopUp();
2488 signal(SIGWINCH, TermSizeSigHandler);
2490 signal(SIGINT, IntSigHandler);
2491 signal(SIGTERM, IntSigHandler);
2492 if (*appData.cmailGameName != NULLCHAR) {
2493 signal(SIGUSR1, CmailSigHandler);
2496 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2499 XtAppMainLoop(appContext);
2500 if (appData.debugMode) fclose(debugFP); // [DM] debug
2507 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2508 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2510 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2511 unlink(gameCopyFilename);
2512 unlink(gamePasteFilename);
2515 RETSIGTYPE TermSizeSigHandler(int sig)
2528 CmailSigHandler(sig)
2534 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2536 /* Activate call-back function CmailSigHandlerCallBack() */
2537 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2539 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2543 CmailSigHandlerCallBack(isr, closure, message, count, error)
2551 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2553 /**** end signal code ****/
2563 f = fopen(appData.icsLogon, "r");
2569 strcat(buf, appData.icsLogon);
2570 f = fopen(buf, "r");
2574 ProcessICSInitScript(f);
2581 EditCommentPopDown();
2596 if (!menuBarWidget) return;
2597 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2599 DisplayError("menuStep.Revert", 0);
2601 XtSetSensitive(w, !grey);
2606 SetMenuEnables(enab)
2610 if (!menuBarWidget) return;
2611 while (enab->name != NULL) {
2612 w = XtNameToWidget(menuBarWidget, enab->name);
2614 DisplayError(enab->name, 0);
2616 XtSetSensitive(w, enab->value);
2622 Enables icsEnables[] = {
2623 { "menuFile.Mail Move", False },
2624 { "menuFile.Reload CMail Message", False },
2625 { "menuMode.Machine Black", False },
2626 { "menuMode.Machine White", False },
2627 { "menuMode.Analysis Mode", False },
2628 { "menuMode.Analyze File", False },
2629 { "menuMode.Two Machines", False },
2631 { "menuHelp.Hint", False },
2632 { "menuHelp.Book", False },
2633 { "menuStep.Move Now", False },
2634 { "menuOptions.Periodic Updates", False },
2635 { "menuOptions.Hide Thinking", False },
2636 { "menuOptions.Ponder Next Move", False },
2641 Enables ncpEnables[] = {
2642 { "menuFile.Mail Move", False },
2643 { "menuFile.Reload CMail Message", False },
2644 { "menuMode.Machine White", False },
2645 { "menuMode.Machine Black", False },
2646 { "menuMode.Analysis Mode", False },
2647 { "menuMode.Analyze File", False },
2648 { "menuMode.Two Machines", False },
2649 { "menuMode.ICS Client", False },
2650 { "menuMode.ICS Input Box", False },
2651 { "Action", False },
2652 { "menuStep.Revert", False },
2653 { "menuStep.Move Now", False },
2654 { "menuStep.Retract Move", False },
2655 { "menuOptions.Auto Comment", False },
2656 { "menuOptions.Auto Flag", False },
2657 { "menuOptions.Auto Flip View", False },
2658 { "menuOptions.Auto Observe", False },
2659 { "menuOptions.Auto Raise Board", False },
2660 { "menuOptions.Get Move List", False },
2661 { "menuOptions.ICS Alarm", False },
2662 { "menuOptions.Move Sound", False },
2663 { "menuOptions.Quiet Play", False },
2664 { "menuOptions.Hide Thinking", False },
2665 { "menuOptions.Periodic Updates", False },
2666 { "menuOptions.Ponder Next Move", False },
2667 { "menuHelp.Hint", False },
2668 { "menuHelp.Book", False },
2672 Enables gnuEnables[] = {
2673 { "menuMode.ICS Client", False },
2674 { "menuMode.ICS Input Box", False },
2675 { "menuAction.Accept", False },
2676 { "menuAction.Decline", False },
2677 { "menuAction.Rematch", False },
2678 { "menuAction.Adjourn", False },
2679 { "menuAction.Stop Examining", False },
2680 { "menuAction.Stop Observing", False },
2681 { "menuStep.Revert", False },
2682 { "menuOptions.Auto Comment", False },
2683 { "menuOptions.Auto Observe", False },
2684 { "menuOptions.Auto Raise Board", False },
2685 { "menuOptions.Get Move List", False },
2686 { "menuOptions.Premove", False },
2687 { "menuOptions.Quiet Play", False },
2689 /* The next two options rely on SetCmailMode being called *after* */
2690 /* SetGNUMode so that when GNU is being used to give hints these */
2691 /* menu options are still available */
2693 { "menuFile.Mail Move", False },
2694 { "menuFile.Reload CMail Message", False },
2698 Enables cmailEnables[] = {
2700 { "menuAction.Call Flag", False },
2701 { "menuAction.Draw", True },
2702 { "menuAction.Adjourn", False },
2703 { "menuAction.Abort", False },
2704 { "menuAction.Stop Observing", False },
2705 { "menuAction.Stop Examining", False },
2706 { "menuFile.Mail Move", True },
2707 { "menuFile.Reload CMail Message", True },
2711 Enables trainingOnEnables[] = {
2712 { "menuMode.Edit Comment", False },
2713 { "menuMode.Pause", False },
2714 { "menuStep.Forward", False },
2715 { "menuStep.Backward", False },
2716 { "menuStep.Forward to End", False },
2717 { "menuStep.Back to Start", False },
2718 { "menuStep.Move Now", False },
2719 { "menuStep.Truncate Game", False },
2723 Enables trainingOffEnables[] = {
2724 { "menuMode.Edit Comment", True },
2725 { "menuMode.Pause", True },
2726 { "menuStep.Forward", True },
2727 { "menuStep.Backward", True },
2728 { "menuStep.Forward to End", True },
2729 { "menuStep.Back to Start", True },
2730 { "menuStep.Move Now", True },
2731 { "menuStep.Truncate Game", True },
2735 Enables machineThinkingEnables[] = {
2736 { "menuFile.Load Game", False },
2737 { "menuFile.Load Next Game", False },
2738 { "menuFile.Load Previous Game", False },
2739 { "menuFile.Reload Same Game", False },
2740 { "menuFile.Paste Game", False },
2741 { "menuFile.Load Position", False },
2742 { "menuFile.Load Next Position", False },
2743 { "menuFile.Load Previous Position", False },
2744 { "menuFile.Reload Same Position", False },
2745 { "menuFile.Paste Position", False },
2746 { "menuMode.Machine White", False },
2747 { "menuMode.Machine Black", False },
2748 { "menuMode.Two Machines", False },
2749 { "menuStep.Retract Move", False },
2753 Enables userThinkingEnables[] = {
2754 { "menuFile.Load Game", True },
2755 { "menuFile.Load Next Game", True },
2756 { "menuFile.Load Previous Game", True },
2757 { "menuFile.Reload Same Game", True },
2758 { "menuFile.Paste Game", True },
2759 { "menuFile.Load Position", True },
2760 { "menuFile.Load Next Position", True },
2761 { "menuFile.Load Previous Position", True },
2762 { "menuFile.Reload Same Position", True },
2763 { "menuFile.Paste Position", True },
2764 { "menuMode.Machine White", True },
2765 { "menuMode.Machine Black", True },
2766 { "menuMode.Two Machines", True },
2767 { "menuStep.Retract Move", True },
2773 SetMenuEnables(icsEnables);
2776 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2777 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2784 SetMenuEnables(ncpEnables);
2790 SetMenuEnables(gnuEnables);
2796 SetMenuEnables(cmailEnables);
2802 SetMenuEnables(trainingOnEnables);
2803 if (appData.showButtonBar) {
2804 XtSetSensitive(buttonBarWidget, False);
2810 SetTrainingModeOff()
2812 SetMenuEnables(trainingOffEnables);
2813 if (appData.showButtonBar) {
2814 XtSetSensitive(buttonBarWidget, True);
2819 SetUserThinkingEnables()
2821 if (appData.noChessProgram) return;
2822 SetMenuEnables(userThinkingEnables);
2826 SetMachineThinkingEnables()
2828 if (appData.noChessProgram) return;
2829 SetMenuEnables(machineThinkingEnables);
2831 case MachinePlaysBlack:
2832 case MachinePlaysWhite:
2833 case TwoMachinesPlay:
2834 XtSetSensitive(XtNameToWidget(menuBarWidget,
2835 ModeToWidgetName(gameMode)), True);
2842 #define Abs(n) ((n)<0 ? -(n) : (n))
2845 * Find a font that matches "pattern" that is as close as
2846 * possible to the targetPxlSize. Prefer fonts that are k
2847 * pixels smaller to fonts that are k pixels larger. The
2848 * pattern must be in the X Consortium standard format,
2849 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2850 * The return value should be freed with XtFree when no
2853 char *FindFont(pattern, targetPxlSize)
2857 char **fonts, *p, *best, *scalable, *scalableTail;
2858 int i, j, nfonts, minerr, err, pxlSize;
2861 char **missing_list;
2863 char *def_string, *base_fnt_lst, strInt[3];
2865 XFontStruct **fnt_list;
2867 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2868 sprintf(strInt, "%d", targetPxlSize);
2869 p = strstr(pattern, "--");
2870 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2871 strcat(base_fnt_lst, strInt);
2872 strcat(base_fnt_lst, strchr(p + 2, '-'));
2874 if ((fntSet = XCreateFontSet(xDisplay,
2878 &def_string)) == NULL) {
2880 fprintf(stderr, _("Unable to create font set.\n"));
2884 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2886 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2888 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2889 programName, pattern);
2897 for (i=0; i<nfonts; i++) {
2900 if (*p != '-') continue;
2902 if (*p == NULLCHAR) break;
2903 if (*p++ == '-') j++;
2905 if (j < 7) continue;
2908 scalable = fonts[i];
2911 err = pxlSize - targetPxlSize;
2912 if (Abs(err) < Abs(minerr) ||
2913 (minerr > 0 && err < 0 && -err == minerr)) {
2919 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2920 /* If the error is too big and there is a scalable font,
2921 use the scalable font. */
2922 int headlen = scalableTail - scalable;
2923 p = (char *) XtMalloc(strlen(scalable) + 10);
2924 while (isdigit(*scalableTail)) scalableTail++;
2925 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2927 p = (char *) XtMalloc(strlen(best) + 1);
2930 if (appData.debugMode) {
2931 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2932 pattern, targetPxlSize, p);
2935 if (missing_count > 0)
2936 XFreeStringList(missing_list);
2937 XFreeFontSet(xDisplay, fntSet);
2939 XFreeFontNames(fonts);
2946 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2947 | GCBackground | GCFunction | GCPlaneMask;
2948 XGCValues gc_values;
2951 gc_values.plane_mask = AllPlanes;
2952 gc_values.line_width = lineGap;
2953 gc_values.line_style = LineSolid;
2954 gc_values.function = GXcopy;
2956 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2957 gc_values.background = XBlackPixel(xDisplay, xScreen);
2958 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2960 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2961 gc_values.background = XWhitePixel(xDisplay, xScreen);
2962 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2963 XSetFont(xDisplay, coordGC, coordFontID);
2965 // [HGM] make font for holdings counts (white on black0
2966 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2967 gc_values.background = XBlackPixel(xDisplay, xScreen);
2968 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2969 XSetFont(xDisplay, countGC, countFontID);
2971 if (appData.monoMode) {
2972 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2973 gc_values.background = XWhitePixel(xDisplay, xScreen);
2974 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2976 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2977 gc_values.background = XBlackPixel(xDisplay, xScreen);
2978 lightSquareGC = wbPieceGC
2979 = XtGetGC(shellWidget, value_mask, &gc_values);
2981 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2982 gc_values.background = XWhitePixel(xDisplay, xScreen);
2983 darkSquareGC = bwPieceGC
2984 = XtGetGC(shellWidget, value_mask, &gc_values);
2986 if (DefaultDepth(xDisplay, xScreen) == 1) {
2987 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2988 gc_values.function = GXcopyInverted;
2989 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2990 gc_values.function = GXcopy;
2991 if (XBlackPixel(xDisplay, xScreen) == 1) {
2992 bwPieceGC = darkSquareGC;
2993 wbPieceGC = copyInvertedGC;
2995 bwPieceGC = copyInvertedGC;
2996 wbPieceGC = lightSquareGC;
3000 gc_values.foreground = highlightSquareColor;
3001 gc_values.background = highlightSquareColor;
3002 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3004 gc_values.foreground = premoveHighlightColor;
3005 gc_values.background = premoveHighlightColor;
3006 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3008 gc_values.foreground = lightSquareColor;
3009 gc_values.background = darkSquareColor;
3010 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3012 gc_values.foreground = darkSquareColor;
3013 gc_values.background = lightSquareColor;
3014 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3016 gc_values.foreground = jailSquareColor;
3017 gc_values.background = jailSquareColor;
3018 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3020 gc_values.foreground = whitePieceColor;
3021 gc_values.background = darkSquareColor;
3022 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3024 gc_values.foreground = whitePieceColor;
3025 gc_values.background = lightSquareColor;
3026 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3028 gc_values.foreground = whitePieceColor;
3029 gc_values.background = jailSquareColor;
3030 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3032 gc_values.foreground = blackPieceColor;
3033 gc_values.background = darkSquareColor;
3034 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3036 gc_values.foreground = blackPieceColor;
3037 gc_values.background = lightSquareColor;
3038 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3040 gc_values.foreground = blackPieceColor;
3041 gc_values.background = jailSquareColor;
3042 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3046 void loadXIM(xim, xmask, filename, dest, mask)
3059 fp = fopen(filename, "rb");
3061 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3068 for (y=0; y<h; ++y) {
3069 for (x=0; x<h; ++x) {
3074 XPutPixel(xim, x, y, blackPieceColor);
3076 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3079 XPutPixel(xim, x, y, darkSquareColor);
3081 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3084 XPutPixel(xim, x, y, whitePieceColor);
3086 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3089 XPutPixel(xim, x, y, lightSquareColor);
3091 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3097 /* create Pixmap of piece */
3098 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3100 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3103 /* create Pixmap of clipmask
3104 Note: We assume the white/black pieces have the same
3105 outline, so we make only 6 masks. This is okay
3106 since the XPM clipmask routines do the same. */
3108 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3110 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3113 /* now create the 1-bit version */
3114 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3117 values.foreground = 1;
3118 values.background = 0;
3120 /* Don't use XtGetGC, not read only */
3121 maskGC = XCreateGC(xDisplay, *mask,
3122 GCForeground | GCBackground, &values);
3123 XCopyPlane(xDisplay, temp, *mask, maskGC,
3124 0, 0, squareSize, squareSize, 0, 0, 1);
3125 XFreePixmap(xDisplay, temp);
3130 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3132 void CreateXIMPieces()
3137 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3142 /* The XSynchronize calls were copied from CreatePieces.
3143 Not sure if needed, but can't hurt */
3144 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3147 /* temp needed by loadXIM() */
3148 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3149 0, 0, ss, ss, AllPlanes, XYPixmap);
3151 if (strlen(appData.pixmapDirectory) == 0) {
3155 if (appData.monoMode) {
3156 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3160 fprintf(stderr, _("\nLoading XIMs...\n"));
3162 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3163 fprintf(stderr, "%d", piece+1);
3164 for (kind=0; kind<4; kind++) {
3165 fprintf(stderr, ".");
3166 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3167 ExpandPathName(appData.pixmapDirectory),
3168 piece <= (int) WhiteKing ? "" : "w",
3169 pieceBitmapNames[piece],
3171 ximPieceBitmap[kind][piece] =
3172 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3173 0, 0, ss, ss, AllPlanes, XYPixmap);
3174 if (appData.debugMode)
3175 fprintf(stderr, _("(File:%s:) "), buf);
3176 loadXIM(ximPieceBitmap[kind][piece],
3178 &(xpmPieceBitmap2[kind][piece]),
3179 &(ximMaskPm2[piece]));
3180 if(piece <= (int)WhiteKing)
3181 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3183 fprintf(stderr," ");
3185 /* Load light and dark squares */
3186 /* If the LSQ and DSQ pieces don't exist, we will
3187 draw them with solid squares. */
3188 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3189 if (access(buf, 0) != 0) {
3193 fprintf(stderr, _("light square "));
3195 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3196 0, 0, ss, ss, AllPlanes, XYPixmap);
3197 if (appData.debugMode)
3198 fprintf(stderr, _("(File:%s:) "), buf);
3200 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3201 fprintf(stderr, _("dark square "));
3202 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3203 ExpandPathName(appData.pixmapDirectory), ss);
3204 if (appData.debugMode)
3205 fprintf(stderr, _("(File:%s:) "), buf);
3207 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3208 0, 0, ss, ss, AllPlanes, XYPixmap);
3209 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3210 xpmJailSquare = xpmLightSquare;
3212 fprintf(stderr, _("Done.\n"));
3214 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3218 void CreateXPMPieces()
3222 u_int ss = squareSize;
3224 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3225 XpmColorSymbol symbols[4];
3227 /* The XSynchronize calls were copied from CreatePieces.
3228 Not sure if needed, but can't hurt */
3229 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3231 /* Setup translations so piece colors match square colors */
3232 symbols[0].name = "light_piece";
3233 symbols[0].value = appData.whitePieceColor;
3234 symbols[1].name = "dark_piece";
3235 symbols[1].value = appData.blackPieceColor;
3236 symbols[2].name = "light_square";
3237 symbols[2].value = appData.lightSquareColor;
3238 symbols[3].name = "dark_square";
3239 symbols[3].value = appData.darkSquareColor;
3241 attr.valuemask = XpmColorSymbols;
3242 attr.colorsymbols = symbols;
3243 attr.numsymbols = 4;
3245 if (appData.monoMode) {
3246 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3250 if (strlen(appData.pixmapDirectory) == 0) {
3251 XpmPieces* pieces = builtInXpms;
3254 while (pieces->size != squareSize && pieces->size) pieces++;
3255 if (!pieces->size) {
3256 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3259 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3260 for (kind=0; kind<4; kind++) {
3262 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3263 pieces->xpm[piece][kind],
3264 &(xpmPieceBitmap2[kind][piece]),
3265 NULL, &attr)) != 0) {
3266 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3270 if(piece <= (int) WhiteKing)
3271 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3275 xpmJailSquare = xpmLightSquare;
3279 fprintf(stderr, _("\nLoading XPMs...\n"));
3282 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3283 fprintf(stderr, "%d ", piece+1);
3284 for (kind=0; kind<4; kind++) {
3285 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3286 ExpandPathName(appData.pixmapDirectory),
3287 piece > (int) WhiteKing ? "w" : "",
3288 pieceBitmapNames[piece],
3290 if (appData.debugMode) {
3291 fprintf(stderr, _("(File:%s:) "), buf);
3293 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3294 &(xpmPieceBitmap2[kind][piece]),
3295 NULL, &attr)) != 0) {
3296 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3297 // [HGM] missing: read of unorthodox piece failed; substitute King.
3298 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3299 ExpandPathName(appData.pixmapDirectory),
3301 if (appData.debugMode) {
3302 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3304 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3305 &(xpmPieceBitmap2[kind][piece]),
3309 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3314 if(piece <= (int) WhiteKing)
3315 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3318 /* Load light and dark squares */
3319 /* If the LSQ and DSQ pieces don't exist, we will
3320 draw them with solid squares. */
3321 fprintf(stderr, _("light square "));
3322 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3323 if (access(buf, 0) != 0) {
3327 if (appData.debugMode)
3328 fprintf(stderr, _("(File:%s:) "), buf);
3330 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3331 &xpmLightSquare, NULL, &attr)) != 0) {
3332 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3335 fprintf(stderr, _("dark square "));
3336 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3337 ExpandPathName(appData.pixmapDirectory), ss);
3338 if (appData.debugMode) {
3339 fprintf(stderr, _("(File:%s:) "), buf);
3341 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3342 &xpmDarkSquare, NULL, &attr)) != 0) {
3343 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3347 xpmJailSquare = xpmLightSquare;
3348 fprintf(stderr, _("Done.\n"));
3350 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3353 #endif /* HAVE_LIBXPM */
3356 /* No built-in bitmaps */
3361 u_int ss = squareSize;
3363 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3366 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3367 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3368 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3369 pieceBitmapNames[piece],
3370 ss, kind == SOLID ? 's' : 'o');
3371 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3372 if(piece <= (int)WhiteKing)
3373 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3377 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3381 /* With built-in bitmaps */
3384 BuiltInBits* bib = builtInBits;
3387 u_int ss = squareSize;
3389 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3392 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3394 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3395 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3396 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3397 pieceBitmapNames[piece],
3398 ss, kind == SOLID ? 's' : 'o');
3399 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3400 bib->bits[kind][piece], ss, ss);
3401 if(piece <= (int)WhiteKing)
3402 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3406 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3411 void ReadBitmap(pm, name, bits, wreq, hreq)
3414 unsigned char bits[];
3420 char msg[MSG_SIZ], fullname[MSG_SIZ];
3422 if (*appData.bitmapDirectory != NULLCHAR) {
3423 strcpy(fullname, appData.bitmapDirectory);
3424 strcat(fullname, "/");
3425 strcat(fullname, name);
3426 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3427 &w, &h, pm, &x_hot, &y_hot);
3428 fprintf(stderr, "load %s\n", name);
3429 if (errcode != BitmapSuccess) {
3431 case BitmapOpenFailed:
3432 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3434 case BitmapFileInvalid:
3435 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3437 case BitmapNoMemory:
3438 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3442 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3446 fprintf(stderr, _("%s: %s...using built-in\n"),
3448 } else if (w != wreq || h != hreq) {
3450 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3451 programName, fullname, w, h, wreq, hreq);
3457 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3466 if (lineGap == 0) return;
3468 /* [HR] Split this into 2 loops for non-square boards. */
3470 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3471 gridSegments[i].x1 = 0;
3472 gridSegments[i].x2 =
3473 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3474 gridSegments[i].y1 = gridSegments[i].y2
3475 = lineGap / 2 + (i * (squareSize + lineGap));
3478 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3479 gridSegments[j + i].y1 = 0;
3480 gridSegments[j + i].y2 =
3481 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3482 gridSegments[j + i].x1 = gridSegments[j + i].x2
3483 = lineGap / 2 + (j * (squareSize + lineGap));
3487 static void MenuBarSelect(w, addr, index)
3492 XtActionProc proc = (XtActionProc) addr;
3494 (proc)(NULL, NULL, NULL, NULL);
3497 void CreateMenuBarPopup(parent, name, mb)
3507 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3510 XtSetArg(args[j], XtNleftMargin, 20); j++;
3511 XtSetArg(args[j], XtNrightMargin, 20); j++;
3513 while (mi->string != NULL) {
3514 if (strcmp(mi->string, "----") == 0) {
3515 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3518 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3519 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3521 XtAddCallback(entry, XtNcallback,
3522 (XtCallbackProc) MenuBarSelect,
3523 (caddr_t) mi->proc);
3529 Widget CreateMenuBar(mb)
3533 Widget anchor, menuBar;
3535 char menuName[MSG_SIZ];
3538 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3539 XtSetArg(args[j], XtNvSpace, 0); j++;
3540 XtSetArg(args[j], XtNborderWidth, 0); j++;
3541 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3542 formWidget, args, j);
3544 while (mb->name != NULL) {
3545 strcpy(menuName, "menu");
3546 strcat(menuName, mb->name);
3548 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3551 shortName[0] = _(mb->name)[0];
3552 shortName[1] = NULLCHAR;
3553 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3556 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3559 XtSetArg(args[j], XtNborderWidth, 0); j++;
3560 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3562 CreateMenuBarPopup(menuBar, menuName, mb);
3568 Widget CreateButtonBar(mi)
3572 Widget button, buttonBar;
3576 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3578 XtSetArg(args[j], XtNhSpace, 0); j++;
3580 XtSetArg(args[j], XtNborderWidth, 0); j++;
3581 XtSetArg(args[j], XtNvSpace, 0); j++;
3582 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3583 formWidget, args, j);
3585 while (mi->string != NULL) {
3588 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3589 XtSetArg(args[j], XtNborderWidth, 0); j++;
3591 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3592 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3593 buttonBar, args, j);
3594 XtAddCallback(button, XtNcallback,
3595 (XtCallbackProc) MenuBarSelect,
3596 (caddr_t) mi->proc);
3603 CreatePieceMenu(name, color)
3610 ChessSquare selection;
3612 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3613 boardWidget, args, 0);
3615 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3616 String item = pieceMenuStrings[color][i];
3618 if (strcmp(item, "----") == 0) {
3619 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3622 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3623 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3625 selection = pieceMenuTranslation[color][i];
3626 XtAddCallback(entry, XtNcallback,
3627 (XtCallbackProc) PieceMenuSelect,
3628 (caddr_t) selection);
3629 if (selection == WhitePawn || selection == BlackPawn) {
3630 XtSetArg(args[0], XtNpopupOnEntry, entry);
3631 XtSetValues(menu, args, 1);
3644 ChessSquare selection;
3646 whitePieceMenu = CreatePieceMenu("menuW", 0);
3647 blackPieceMenu = CreatePieceMenu("menuB", 1);
3649 XtRegisterGrabAction(PieceMenuPopup, True,
3650 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3651 GrabModeAsync, GrabModeAsync);
3653 XtSetArg(args[0], XtNlabel, _("Drop"));
3654 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3655 boardWidget, args, 1);
3656 for (i = 0; i < DROP_MENU_SIZE; i++) {
3657 String item = dropMenuStrings[i];
3659 if (strcmp(item, "----") == 0) {
3660 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3663 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3664 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3666 selection = dropMenuTranslation[i];
3667 XtAddCallback(entry, XtNcallback,
3668 (XtCallbackProc) DropMenuSelect,
3669 (caddr_t) selection);
3674 void SetupDropMenu()
3682 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3683 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3684 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3685 dmEnables[i].piece);
3686 XtSetSensitive(entry, p != NULL || !appData.testLegality
3687 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3688 && !appData.icsActive));
3690 while (p && *p++ == dmEnables[i].piece) count++;
3691 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3693 XtSetArg(args[j], XtNlabel, label); j++;
3694 XtSetValues(entry, args, j);
3698 void PieceMenuPopup(w, event, params, num_params)
3702 Cardinal *num_params;
3705 if (event->type != ButtonPress) return;
3706 if (errorUp) ErrorPopDown();
3710 whichMenu = params[0];
3712 case IcsPlayingWhite:
3713 case IcsPlayingBlack:
3715 case MachinePlaysWhite:
3716 case MachinePlaysBlack:
3717 if (appData.testLegality &&
3718 gameInfo.variant != VariantBughouse &&
3719 gameInfo.variant != VariantCrazyhouse) return;
3721 whichMenu = "menuD";
3727 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3728 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3729 pmFromX = pmFromY = -1;
3733 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3735 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3737 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3740 static void PieceMenuSelect(w, piece, junk)
3745 if (pmFromX < 0 || pmFromY < 0) return;
3746 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3749 static void DropMenuSelect(w, piece, junk)
3754 if (pmFromX < 0 || pmFromY < 0) return;
3755 DropMenuEvent(piece, pmFromX, pmFromY);
3758 void WhiteClock(w, event, prms, nprms)
3764 if (gameMode == EditPosition || gameMode == IcsExamining) {
3765 SetWhiteToPlayEvent();
3766 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3771 void BlackClock(w, event, prms, nprms)
3777 if (gameMode == EditPosition || gameMode == IcsExamining) {
3778 SetBlackToPlayEvent();
3779 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3786 * If the user selects on a border boundary, return -1; if off the board,
3787 * return -2. Otherwise map the event coordinate to the square.
3789 int EventToSquare(x, limit)
3797 if ((x % (squareSize + lineGap)) >= squareSize)
3799 x /= (squareSize + lineGap);
3805 static void do_flash_delay(msec)
3811 static void drawHighlight(file, rank, gc)
3817 if (lineGap == 0 || appData.blindfold) return;
3820 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3821 (squareSize + lineGap);
3822 y = lineGap/2 + rank * (squareSize + lineGap);
3824 x = lineGap/2 + file * (squareSize + lineGap);
3825 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3826 (squareSize + lineGap);
3829 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3830 squareSize+lineGap, squareSize+lineGap);
3833 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3834 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3837 SetHighlights(fromX, fromY, toX, toY)
3838 int fromX, fromY, toX, toY;
3840 if (hi1X != fromX || hi1Y != fromY) {
3841 if (hi1X >= 0 && hi1Y >= 0) {
3842 drawHighlight(hi1X, hi1Y, lineGC);
3844 if (fromX >= 0 && fromY >= 0) {
3845 drawHighlight(fromX, fromY, highlineGC);
3848 if (hi2X != toX || hi2Y != toY) {
3849 if (hi2X >= 0 && hi2Y >= 0) {
3850 drawHighlight(hi2X, hi2Y, lineGC);
3852 if (toX >= 0 && toY >= 0) {
3853 drawHighlight(toX, toY, highlineGC);
3865 SetHighlights(-1, -1, -1, -1);
3870 SetPremoveHighlights(fromX, fromY, toX, toY)
3871 int fromX, fromY, toX, toY;
3873 if (pm1X != fromX || pm1Y != fromY) {
3874 if (pm1X >= 0 && pm1Y >= 0) {
3875 drawHighlight(pm1X, pm1Y, lineGC);
3877 if (fromX >= 0 && fromY >= 0) {
3878 drawHighlight(fromX, fromY, prelineGC);
3881 if (pm2X != toX || pm2Y != toY) {
3882 if (pm2X >= 0 && pm2Y >= 0) {
3883 drawHighlight(pm2X, pm2Y, lineGC);
3885 if (toX >= 0 && toY >= 0) {
3886 drawHighlight(toX, toY, prelineGC);
3896 ClearPremoveHighlights()
3898 SetPremoveHighlights(-1, -1, -1, -1);
3901 static void BlankSquare(x, y, color, piece, dest)
3906 if (useImages && useImageSqs) {
3910 pm = xpmLightSquare;
3915 case 2: /* neutral */
3920 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3921 squareSize, squareSize, x, y);
3931 case 2: /* neutral */
3936 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3941 I split out the routines to draw a piece so that I could
3942 make a generic flash routine.
3944 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3946 int square_color, x, y;
3949 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3950 switch (square_color) {
3952 case 2: /* neutral */
3954 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3955 ? *pieceToOutline(piece)
3956 : *pieceToSolid(piece),
3957 dest, bwPieceGC, 0, 0,
3958 squareSize, squareSize, x, y);
3961 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3962 ? *pieceToSolid(piece)
3963 : *pieceToOutline(piece),
3964 dest, wbPieceGC, 0, 0,
3965 squareSize, squareSize, x, y);
3970 static void monoDrawPiece(piece, square_color, x, y, dest)
3972 int square_color, x, y;
3975 switch (square_color) {
3977 case 2: /* neutral */
3979 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3980 ? *pieceToOutline(piece)
3981 : *pieceToSolid(piece),
3982 dest, bwPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3986 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3987 ? *pieceToSolid(piece)
3988 : *pieceToOutline(piece),
3989 dest, wbPieceGC, 0, 0,
3990 squareSize, squareSize, x, y, 1);
3995 static void colorDrawPiece(piece, square_color, x, y, dest)
3997 int square_color, x, y;
4000 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4001 switch (square_color) {
4003 XCopyPlane(xDisplay, *pieceToSolid(piece),
4004 dest, (int) piece < (int) BlackPawn
4005 ? wlPieceGC : blPieceGC, 0, 0,
4006 squareSize, squareSize, x, y, 1);
4009 XCopyPlane(xDisplay, *pieceToSolid(piece),
4010 dest, (int) piece < (int) BlackPawn
4011 ? wdPieceGC : bdPieceGC, 0, 0,
4012 squareSize, squareSize, x, y, 1);
4014 case 2: /* neutral */
4016 XCopyPlane(xDisplay, *pieceToSolid(piece),
4017 dest, (int) piece < (int) BlackPawn
4018 ? wjPieceGC : bjPieceGC, 0, 0,
4019 squareSize, squareSize, x, y, 1);
4024 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4026 int square_color, x, y;
4031 switch (square_color) {
4033 case 2: /* neutral */
4035 if ((int)piece < (int) BlackPawn) {
4043 if ((int)piece < (int) BlackPawn) {
4051 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4052 dest, wlPieceGC, 0, 0,
4053 squareSize, squareSize, x, y);
4056 typedef void (*DrawFunc)();
4058 DrawFunc ChooseDrawFunc()
4060 if (appData.monoMode) {
4061 if (DefaultDepth(xDisplay, xScreen) == 1) {
4062 return monoDrawPiece_1bit;
4064 return monoDrawPiece;
4068 return colorDrawPieceImage;
4070 return colorDrawPiece;
4074 /* [HR] determine square color depending on chess variant. */
4075 static int SquareColor(row, column)
4080 if (gameInfo.variant == VariantXiangqi) {
4081 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4083 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4085 } else if (row <= 4) {
4091 square_color = ((column + row) % 2) == 1;
4094 /* [hgm] holdings: next line makes all holdings squares light */
4095 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4097 return square_color;
4100 void DrawSquare(row, column, piece, do_flash)
4101 int row, column, do_flash;
4104 int square_color, x, y, direction, font_ascent, font_descent;
4107 XCharStruct overall;
4111 /* Calculate delay in milliseconds (2-delays per complete flash) */
4112 flash_delay = 500 / appData.flashRate;
4115 x = lineGap + ((BOARD_WIDTH-1)-column) *
4116 (squareSize + lineGap);
4117 y = lineGap + row * (squareSize + lineGap);
4119 x = lineGap + column * (squareSize + lineGap);
4120 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4121 (squareSize + lineGap);
4124 square_color = SquareColor(row, column);
4126 if ( // [HGM] holdings: blank out area between board and holdings
4127 column == BOARD_LEFT-1 || column == BOARD_RGHT
4128 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4129 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4130 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4132 // [HGM] print piece counts next to holdings
4133 string[1] = NULLCHAR;
4134 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4135 string[0] = '0' + piece;
4136 XTextExtents(countFontStruct, string, 1, &direction,
4137 &font_ascent, &font_descent, &overall);
4138 if (appData.monoMode) {
4139 XDrawImageString(xDisplay, xBoardWindow, countGC,
4140 x + squareSize - overall.width - 2,
4141 y + font_ascent + 1, string, 1);
4143 XDrawString(xDisplay, xBoardWindow, countGC,
4144 x + squareSize - overall.width - 2,
4145 y + font_ascent + 1, string, 1);
4148 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4149 string[0] = '0' + piece;
4150 XTextExtents(countFontStruct, string, 1, &direction,
4151 &font_ascent, &font_descent, &overall);
4152 if (appData.monoMode) {
4153 XDrawImageString(xDisplay, xBoardWindow, countGC,
4154 x + 2, y + font_ascent + 1, string, 1);
4156 XDrawString(xDisplay, xBoardWindow, countGC,
4157 x + 2, y + font_ascent + 1, string, 1);
4161 if (piece == EmptySquare || appData.blindfold) {
4162 BlankSquare(x, y, square_color, piece, xBoardWindow);
4164 drawfunc = ChooseDrawFunc();
4165 if (do_flash && appData.flashCount > 0) {
4166 for (i=0; i<appData.flashCount; ++i) {
4168 drawfunc(piece, square_color, x, y, xBoardWindow);
4169 XSync(xDisplay, False);
4170 do_flash_delay(flash_delay);
4172 BlankSquare(x, y, square_color, piece, xBoardWindow);
4173 XSync(xDisplay, False);
4174 do_flash_delay(flash_delay);
4177 drawfunc(piece, square_color, x, y, xBoardWindow);
4181 string[1] = NULLCHAR;
4182 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4183 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4184 string[0] = 'a' + column - BOARD_LEFT;
4185 XTextExtents(coordFontStruct, string, 1, &direction,
4186 &font_ascent, &font_descent, &overall);
4187 if (appData.monoMode) {
4188 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4189 x + squareSize - overall.width - 2,
4190 y + squareSize - font_descent - 1, string, 1);
4192 XDrawString(xDisplay, xBoardWindow, coordGC,
4193 x + squareSize - overall.width - 2,
4194 y + squareSize - font_descent - 1, string, 1);
4197 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4198 string[0] = ONE + row;
4199 XTextExtents(coordFontStruct, string, 1, &direction,
4200 &font_ascent, &font_descent, &overall);
4201 if (appData.monoMode) {
4202 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4203 x + 2, y + font_ascent + 1, string, 1);
4205 XDrawString(xDisplay, xBoardWindow, coordGC,
4206 x + 2, y + font_ascent + 1, string, 1);
4212 /* Why is this needed on some versions of X? */
4213 void EventProc(widget, unused, event)
4218 if (!XtIsRealized(widget))
4221 switch (event->type) {
4223 if (event->xexpose.count > 0) return; /* no clipping is done */
4224 XDrawPosition(widget, True, NULL);
4232 void DrawPosition(fullRedraw, board)
4233 /*Boolean*/int fullRedraw;
4236 XDrawPosition(boardWidget, fullRedraw, board);
4239 /* Returns 1 if there are "too many" differences between b1 and b2
4240 (i.e. more than 1 move was made) */
4241 static int too_many_diffs(b1, b2)
4247 for (i=0; i<BOARD_HEIGHT; ++i) {
4248 for (j=0; j<BOARD_WIDTH; ++j) {
4249 if (b1[i][j] != b2[i][j]) {
4250 if (++c > 4) /* Castling causes 4 diffs */
4259 /* Matrix describing castling maneuvers */
4260 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4261 static int castling_matrix[4][5] = {
4262 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4263 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4264 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4265 { 7, 7, 4, 5, 6 } /* 0-0, black */
4268 /* Checks whether castling occurred. If it did, *rrow and *rcol
4269 are set to the destination (row,col) of the rook that moved.
4271 Returns 1 if castling occurred, 0 if not.
4273 Note: Only handles a max of 1 castling move, so be sure
4274 to call too_many_diffs() first.
4276 static int check_castle_draw(newb, oldb, rrow, rcol)
4283 /* For each type of castling... */
4284 for (i=0; i<4; ++i) {
4285 r = castling_matrix[i];
4287 /* Check the 4 squares involved in the castling move */
4289 for (j=1; j<=4; ++j) {
4290 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4297 /* All 4 changed, so it must be a castling move */
4306 static int damage[BOARD_RANKS][BOARD_FILES];
4309 * event handler for redrawing the board
4311 void XDrawPosition(w, repaint, board)
4313 /*Boolean*/int repaint;
4317 static int lastFlipView = 0;
4318 static int lastBoardValid = 0;
4319 static Board lastBoard;
4323 if (board == NULL) {
4324 if (!lastBoardValid) return;
4327 if (!lastBoardValid || lastFlipView != flipView) {
4328 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4334 * It would be simpler to clear the window with XClearWindow()
4335 * but this causes a very distracting flicker.
4338 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4340 /* If too much changes (begin observing new game, etc.), don't
4342 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4344 /* Special check for castling so we don't flash both the king
4345 and the rook (just flash the king). */
4347 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4348 /* Draw rook with NO flashing. King will be drawn flashing later */
4349 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4350 lastBoard[rrow][rcol] = board[rrow][rcol];
4354 /* First pass -- Draw (newly) empty squares and repair damage.
4355 This prevents you from having a piece show up twice while it
4356 is flashing on its new square */
4357 for (i = 0; i < BOARD_HEIGHT; i++)
4358 for (j = 0; j < BOARD_WIDTH; j++)
4359 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4361 DrawSquare(i, j, board[i][j], 0);
4362 damage[i][j] = False;
4365 /* Second pass -- Draw piece(s) in new position and flash them */
4366 for (i = 0; i < BOARD_HEIGHT; i++)
4367 for (j = 0; j < BOARD_WIDTH; j++)
4368 if (board[i][j] != lastBoard[i][j]) {
4369 DrawSquare(i, j, board[i][j], do_flash);
4373 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4374 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4376 for (i = 0; i < BOARD_HEIGHT; i++)
4377 for (j = 0; j < BOARD_WIDTH; j++) {
4378 DrawSquare(i, j, board[i][j], 0);
4379 damage[i][j] = False;
4383 CopyBoard(lastBoard, board);
4385 lastFlipView = flipView;
4387 /* Draw highlights */
4388 if (pm1X >= 0 && pm1Y >= 0) {
4389 drawHighlight(pm1X, pm1Y, prelineGC);
4391 if (pm2X >= 0 && pm2Y >= 0) {
4392 drawHighlight(pm2X, pm2Y, prelineGC);
4394 if (hi1X >= 0 && hi1Y >= 0) {
4395 drawHighlight(hi1X, hi1Y, highlineGC);
4397 if (hi2X >= 0 && hi2Y >= 0) {
4398 drawHighlight(hi2X, hi2Y, highlineGC);
4401 /* If piece being dragged around board, must redraw that too */
4404 XSync(xDisplay, False);
4409 * event handler for redrawing the board
4411 void DrawPositionProc(w, event, prms, nprms)
4417 XDrawPosition(w, True, NULL);
4422 * event handler for parsing user moves
4424 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4425 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4426 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4427 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4428 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4429 // and at the end FinishMove() to perform the move after optional promotion popups.
4430 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4431 void HandleUserMove(w, event, prms, nprms)
4437 if (w != boardWidget || errorExitStatus != -1) return;
4440 if (event->type == ButtonPress) {
4441 XtPopdown(promotionShell);
4442 XtDestroyWidget(promotionShell);
4443 promotionUp = False;
4451 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4452 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4453 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4456 void AnimateUserMove (Widget w, XEvent * event,
4457 String * params, Cardinal * nParams)
4459 DragPieceMove(event->xmotion.x, event->xmotion.y);
4462 Widget CommentCreate(name, text, mutable, callback, lines)
4464 int /*Boolean*/ mutable;
4465 XtCallbackProc callback;
4469 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4474 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4475 XtGetValues(boardWidget, args, j);
4478 XtSetArg(args[j], XtNresizable, True); j++;
4481 XtCreatePopupShell(name, topLevelShellWidgetClass,
4482 shellWidget, args, j);
4485 XtCreatePopupShell(name, transientShellWidgetClass,
4486 shellWidget, args, j);
4489 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4490 layoutArgs, XtNumber(layoutArgs));
4492 XtCreateManagedWidget("form", formWidgetClass, layout,
4493 formArgs, XtNumber(formArgs));
4497 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4498 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4500 XtSetArg(args[j], XtNstring, text); j++;
4501 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4502 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4503 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4504 XtSetArg(args[j], XtNright, XtChainRight); j++;
4505 XtSetArg(args[j], XtNresizable, True); j++;
4506 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4507 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4508 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4509 XtSetArg(args[j], XtNautoFill, True); j++;
4510 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4512 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4516 XtSetArg(args[j], XtNfromVert, edit); j++;
4517 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4518 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4519 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4520 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4522 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4523 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4526 XtSetArg(args[j], XtNfromVert, edit); j++;
4527 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4528 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4529 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4530 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4531 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4533 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4534 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4537 XtSetArg(args[j], XtNfromVert, edit); j++;
4538 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4539 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4540 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4541 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4542 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4544 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4545 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4548 XtSetArg(args[j], XtNfromVert, edit); j++;
4549 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4550 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4551 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4552 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4554 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4555 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4558 XtSetArg(args[j], XtNfromVert, edit); j++;
4559 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4560 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4561 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4562 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4563 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4565 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4566 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4569 XtRealizeWidget(shell);
4571 if (commentX == -1) {
4574 Dimension pw_height;
4575 Dimension ew_height;
4578 XtSetArg(args[j], XtNheight, &ew_height); j++;
4579 XtGetValues(edit, args, j);
4582 XtSetArg(args[j], XtNheight, &pw_height); j++;
4583 XtGetValues(shell, args, j);
4584 commentH = pw_height + (lines - 1) * ew_height;
4585 commentW = bw_width - 16;
4587 XSync(xDisplay, False);
4589 /* This code seems to tickle an X bug if it is executed too soon
4590 after xboard starts up. The coordinates get transformed as if
4591 the main window was positioned at (0, 0).
4593 XtTranslateCoords(shellWidget,
4594 (bw_width - commentW) / 2, 0 - commentH / 2,
4595 &commentX, &commentY);
4597 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4598 RootWindowOfScreen(XtScreen(shellWidget)),
4599 (bw_width - commentW) / 2, 0 - commentH / 2,
4604 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4607 if(wpComment.width > 0) {
4608 commentX = wpComment.x;
4609 commentY = wpComment.y;
4610 commentW = wpComment.width;
4611 commentH = wpComment.height;
4615 XtSetArg(args[j], XtNheight, commentH); j++;
4616 XtSetArg(args[j], XtNwidth, commentW); j++;
4617 XtSetArg(args[j], XtNx, commentX); j++;
4618 XtSetArg(args[j], XtNy, commentY); j++;
4619 XtSetValues(shell, args, j);
4620 XtSetKeyboardFocus(shell, edit);
4625 /* Used for analysis window and ICS input window */
4626 Widget MiscCreate(name, text, mutable, callback, lines)
4628 int /*Boolean*/ mutable;
4629 XtCallbackProc callback;
4633 Widget shell, layout, form, edit;
4635 Dimension bw_width, pw_height, ew_height, w, h;
4641 XtSetArg(args[j], XtNresizable, True); j++;
4644 XtCreatePopupShell(name, topLevelShellWidgetClass,
4645 shellWidget, args, j);
4648 XtCreatePopupShell(name, transientShellWidgetClass,
4649 shellWidget, args, j);
4652 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4653 layoutArgs, XtNumber(layoutArgs));
4655 XtCreateManagedWidget("form", formWidgetClass, layout,
4656 formArgs, XtNumber(formArgs));
4660 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4661 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4663 XtSetArg(args[j], XtNstring, text); j++;
4664 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4665 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4666 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4667 XtSetArg(args[j], XtNright, XtChainRight); j++;
4668 XtSetArg(args[j], XtNresizable, True); j++;
4669 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4670 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4671 XtSetArg(args[j], XtNautoFill, True); j++;
4672 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4674 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4676 XtRealizeWidget(shell);
4679 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4680 XtGetValues(boardWidget, args, j);
4683 XtSetArg(args[j], XtNheight, &ew_height); j++;
4684 XtGetValues(edit, args, j);
4687 XtSetArg(args[j], XtNheight, &pw_height); j++;
4688 XtGetValues(shell, args, j);
4689 h = pw_height + (lines - 1) * ew_height;
4692 XSync(xDisplay, False);
4694 /* This code seems to tickle an X bug if it is executed too soon
4695 after xboard starts up. The coordinates get transformed as if
4696 the main window was positioned at (0, 0).
4698 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4700 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4701 RootWindowOfScreen(XtScreen(shellWidget)),
4702 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4706 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4709 XtSetArg(args[j], XtNheight, h); j++;
4710 XtSetArg(args[j], XtNwidth, w); j++;
4711 XtSetArg(args[j], XtNx, x); j++;
4712 XtSetArg(args[j], XtNy, y); j++;
4713 XtSetValues(shell, args, j);
4719 static int savedIndex; /* gross that this is global */
4721 void EditCommentPopUp(index, title, text)
4730 if (text == NULL) text = "";
4732 if (editShell == NULL) {
4734 CommentCreate(title, text, True, EditCommentCallback, 4);
4735 XtRealizeWidget(editShell);
4736 CatchDeleteWindow(editShell, "EditCommentPopDown");
4738 edit = XtNameToWidget(editShell, "*form.text");
4740 XtSetArg(args[j], XtNstring, text); j++;
4741 XtSetValues(edit, args, j);
4743 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4744 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4745 XtSetValues(editShell, args, j);
4748 XtPopup(editShell, XtGrabNone);
4752 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4753 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4757 void EditCommentCallback(w, client_data, call_data)
4759 XtPointer client_data, call_data;
4767 XtSetArg(args[j], XtNlabel, &name); j++;
4768 XtGetValues(w, args, j);
4770 if (strcmp(name, _("ok")) == 0) {
4771 edit = XtNameToWidget(editShell, "*form.text");
4773 XtSetArg(args[j], XtNstring, &val); j++;
4774 XtGetValues(edit, args, j);
4775 ReplaceComment(savedIndex, val);
4776 EditCommentPopDown();
4777 } else if (strcmp(name, _("cancel")) == 0) {
4778 EditCommentPopDown();
4779 } else if (strcmp(name, _("clear")) == 0) {
4780 edit = XtNameToWidget(editShell, "*form.text");
4781 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4782 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4786 void EditCommentPopDown()
4791 if (!editUp) return;
4793 XtSetArg(args[j], XtNx, &commentX); j++;
4794 XtSetArg(args[j], XtNy, &commentY); j++;
4795 XtSetArg(args[j], XtNheight, &commentH); j++;
4796 XtSetArg(args[j], XtNwidth, &commentW); j++;
4797 XtGetValues(editShell, args, j);
4798 XtPopdown(editShell);
4801 XtSetArg(args[j], XtNleftBitmap, None); j++;
4802 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4806 void ICSInputBoxPopUp()
4811 char *title = _("ICS Input");
4814 if (ICSInputShell == NULL) {
4815 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4816 tr = XtParseTranslationTable(ICSInputTranslations);
4817 edit = XtNameToWidget(ICSInputShell, "*form.text");
4818 XtOverrideTranslations(edit, tr);
4819 XtRealizeWidget(ICSInputShell);
4820 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4823 edit = XtNameToWidget(ICSInputShell, "*form.text");
4825 XtSetArg(args[j], XtNstring, ""); j++;
4826 XtSetValues(edit, args, j);
4828 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4829 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4830 XtSetValues(ICSInputShell, args, j);
4833 XtPopup(ICSInputShell, XtGrabNone);
4834 XtSetKeyboardFocus(ICSInputShell, edit);
4836 ICSInputBoxUp = True;
4838 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4839 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4843 void ICSInputSendText()
4850 edit = XtNameToWidget(ICSInputShell, "*form.text");
4852 XtSetArg(args[j], XtNstring, &val); j++;
4853 XtGetValues(edit, args, j);
4854 SendMultiLineToICS(val);
4855 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4856 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4859 void ICSInputBoxPopDown()
4864 if (!ICSInputBoxUp) return;
4866 XtPopdown(ICSInputShell);
4867 ICSInputBoxUp = False;
4869 XtSetArg(args[j], XtNleftBitmap, None); j++;
4870 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4874 void CommentPopUp(title, text)
4881 if (commentShell == NULL) {
4883 CommentCreate(title, text, False, CommentCallback, 4);
4884 XtRealizeWidget(commentShell);
4885 CatchDeleteWindow(commentShell, "CommentPopDown");
4887 edit = XtNameToWidget(commentShell, "*form.text");
4889 XtSetArg(args[j], XtNstring, text); j++;
4890 XtSetValues(edit, args, j);
4892 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4893 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4894 XtSetValues(commentShell, args, j);
4897 XtPopup(commentShell, XtGrabNone);
4898 XSync(xDisplay, False);
4903 void CommentCallback(w, client_data, call_data)
4905 XtPointer client_data, call_data;
4912 XtSetArg(args[j], XtNlabel, &name); j++;
4913 XtGetValues(w, args, j);
4915 if (strcmp(name, _("close")) == 0) {
4917 } else if (strcmp(name, _("edit")) == 0) {
4924 void CommentPopDown()
4929 if (!commentUp) return;
4931 XtSetArg(args[j], XtNx, &commentX); j++;
4932 XtSetArg(args[j], XtNy, &commentY); j++;
4933 XtSetArg(args[j], XtNwidth, &commentW); j++;
4934 XtSetArg(args[j], XtNheight, &commentH); j++;
4935 XtGetValues(commentShell, args, j);
4936 XtPopdown(commentShell);
4937 XSync(xDisplay, False);
4941 void FileNamePopUp(label, def, proc, openMode)
4948 Widget popup, layout, dialog, edit;
4954 fileProc = proc; /* I can't see a way not */
4955 fileOpenMode = openMode; /* to use globals here */
4958 XtSetArg(args[i], XtNresizable, True); i++;
4959 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4960 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4961 fileNameShell = popup =
4962 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4963 shellWidget, args, i);
4966 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4967 layoutArgs, XtNumber(layoutArgs));
4970 XtSetArg(args[i], XtNlabel, label); i++;
4971 XtSetArg(args[i], XtNvalue, def); i++;
4972 XtSetArg(args[i], XtNborderWidth, 0); i++;
4973 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4976 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4977 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4978 (XtPointer) dialog);
4980 XtRealizeWidget(popup);
4981 CatchDeleteWindow(popup, "FileNamePopDown");
4983 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4984 &x, &y, &win_x, &win_y, &mask);
4986 XtSetArg(args[0], XtNx, x - 10);
4987 XtSetArg(args[1], XtNy, y - 30);
4988 XtSetValues(popup, args, 2);
4990 XtPopup(popup, XtGrabExclusive);
4993 edit = XtNameToWidget(dialog, "*value");
4994 XtSetKeyboardFocus(popup, edit);
4997 void FileNamePopDown()
4999 if (!filenameUp) return;
5000 XtPopdown(fileNameShell);
5001 XtDestroyWidget(fileNameShell);
5006 void FileNameCallback(w, client_data, call_data)
5008 XtPointer client_data, call_data;
5013 XtSetArg(args[0], XtNlabel, &name);
5014 XtGetValues(w, args, 1);
5016 if (strcmp(name, _("cancel")) == 0) {
5021 FileNameAction(w, NULL, NULL, NULL);
5024 void FileNameAction(w, event, prms, nprms)
5036 name = XawDialogGetValueString(w = XtParent(w));
5038 if ((name != NULL) && (*name != NULLCHAR)) {
5040 XtPopdown(w = XtParent(XtParent(w)));
5044 p = strrchr(buf, ' ');
5051 fullname = ExpandPathName(buf);
5053 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5056 f = fopen(fullname, fileOpenMode);
5058 DisplayError(_("Failed to open file"), errno);
5060 (void) (*fileProc)(f, index, buf);
5067 XtPopdown(w = XtParent(XtParent(w)));
5073 void PromotionPopUp()
5076 Widget dialog, layout;
5078 Dimension bw_width, pw_width;
5082 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5083 XtGetValues(boardWidget, args, j);
5086 XtSetArg(args[j], XtNresizable, True); j++;
5087 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5089 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5090 shellWidget, args, j);
5092 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5093 layoutArgs, XtNumber(layoutArgs));
5096 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5097 XtSetArg(args[j], XtNborderWidth, 0); j++;
5098 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5101 if(gameInfo.variant != VariantShogi) {
5102 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5103 (XtPointer) dialog);
5104 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5105 (XtPointer) dialog);
5106 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5107 (XtPointer) dialog);
5108 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5109 (XtPointer) dialog);
5110 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5111 gameInfo.variant == VariantGiveaway) {
5112 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5113 (XtPointer) dialog);
5115 if(gameInfo.variant == VariantCapablanca ||
5116 gameInfo.variant == VariantGothic ||
5117 gameInfo.variant == VariantCapaRandom) {
5118 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5119 (XtPointer) dialog);
5120 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5121 (XtPointer) dialog);
5123 } else // [HGM] shogi
5125 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5126 (XtPointer) dialog);
5127 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5128 (XtPointer) dialog);
5130 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5131 (XtPointer) dialog);
5133 XtRealizeWidget(promotionShell);
5134 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5137 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5138 XtGetValues(promotionShell, args, j);
5140 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5141 lineGap + squareSize/3 +
5142 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5143 0 : 6*(squareSize + lineGap)), &x, &y);
5146 XtSetArg(args[j], XtNx, x); j++;
5147 XtSetArg(args[j], XtNy, y); j++;
5148 XtSetValues(promotionShell, args, j);
5150 XtPopup(promotionShell, XtGrabNone);
5155 void PromotionPopDown()
5157 if (!promotionUp) return;
5158 XtPopdown(promotionShell);
5159 XtDestroyWidget(promotionShell);
5160 promotionUp = False;
5163 void PromotionCallback(w, client_data, call_data)
5165 XtPointer client_data, call_data;
5171 XtSetArg(args[0], XtNlabel, &name);
5172 XtGetValues(w, args, 1);
5176 if (fromX == -1) return;
5178 if (strcmp(name, _("cancel")) == 0) {
5182 } else if (strcmp(name, _("Knight")) == 0) {
5184 } else if (strcmp(name, _("Promote")) == 0) {
5186 } else if (strcmp(name, _("Defer")) == 0) {
5189 promoChar = ToLower(name[0]);
5192 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5194 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5195 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5200 void ErrorCallback(w, client_data, call_data)
5202 XtPointer client_data, call_data;
5205 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5207 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5213 if (!errorUp) return;
5215 XtPopdown(errorShell);
5216 XtDestroyWidget(errorShell);
5217 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5220 void ErrorPopUp(title, label, modal)
5221 char *title, *label;
5225 Widget dialog, layout;
5229 Dimension bw_width, pw_width;
5230 Dimension pw_height;
5234 XtSetArg(args[i], XtNresizable, True); i++;
5235 XtSetArg(args[i], XtNtitle, title); i++;
5237 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5238 shellWidget, args, i);
5240 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5241 layoutArgs, XtNumber(layoutArgs));
5244 XtSetArg(args[i], XtNlabel, label); i++;
5245 XtSetArg(args[i], XtNborderWidth, 0); i++;
5246 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5249 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5251 XtRealizeWidget(errorShell);
5252 CatchDeleteWindow(errorShell, "ErrorPopDown");
5255 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5256 XtGetValues(boardWidget, args, i);
5258 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5259 XtSetArg(args[i], XtNheight, &pw_height); i++;
5260 XtGetValues(errorShell, args, i);
5263 /* This code seems to tickle an X bug if it is executed too soon
5264 after xboard starts up. The coordinates get transformed as if
5265 the main window was positioned at (0, 0).
5267 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5268 0 - pw_height + squareSize / 3, &x, &y);
5270 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5271 RootWindowOfScreen(XtScreen(boardWidget)),
5272 (bw_width - pw_width) / 2,
5273 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5277 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5280 XtSetArg(args[i], XtNx, x); i++;
5281 XtSetArg(args[i], XtNy, y); i++;
5282 XtSetValues(errorShell, args, i);
5285 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5288 /* Disable all user input other than deleting the window */
5289 static int frozen = 0;
5293 /* Grab by a widget that doesn't accept input */
5294 XtAddGrab(messageWidget, TRUE, FALSE);
5298 /* Undo a FreezeUI */
5301 if (!frozen) return;
5302 XtRemoveGrab(messageWidget);
5306 char *ModeToWidgetName(mode)
5310 case BeginningOfGame:
5311 if (appData.icsActive)
5312 return "menuMode.ICS Client";
5313 else if (appData.noChessProgram ||
5314 *appData.cmailGameName != NULLCHAR)
5315 return "menuMode.Edit Game";
5317 return "menuMode.Machine Black";
5318 case MachinePlaysBlack:
5319 return "menuMode.Machine Black";
5320 case MachinePlaysWhite:
5321 return "menuMode.Machine White";
5323 return "menuMode.Analysis Mode";
5325 return "menuMode.Analyze File";
5326 case TwoMachinesPlay:
5327 return "menuMode.Two Machines";
5329 return "menuMode.Edit Game";
5330 case PlayFromGameFile:
5331 return "menuFile.Load Game";
5333 return "menuMode.Edit Position";
5335 return "menuMode.Training";
5336 case IcsPlayingWhite:
5337 case IcsPlayingBlack:
5341 return "menuMode.ICS Client";
5348 void ModeHighlight()
5351 static int oldPausing = FALSE;
5352 static GameMode oldmode = (GameMode) -1;
5355 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5357 if (pausing != oldPausing) {
5358 oldPausing = pausing;
5360 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5362 XtSetArg(args[0], XtNleftBitmap, None);
5364 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5367 if (appData.showButtonBar) {
5368 /* Always toggle, don't set. Previous code messes up when
5369 invoked while the button is pressed, as releasing it
5370 toggles the state again. */
5373 XtSetArg(args[0], XtNbackground, &oldbg);
5374 XtSetArg(args[1], XtNforeground, &oldfg);
5375 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5377 XtSetArg(args[0], XtNbackground, oldfg);
5378 XtSetArg(args[1], XtNforeground, oldbg);
5380 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5384 wname = ModeToWidgetName(oldmode);
5385 if (wname != NULL) {
5386 XtSetArg(args[0], XtNleftBitmap, None);
5387 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5389 wname = ModeToWidgetName(gameMode);
5390 if (wname != NULL) {
5391 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5392 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5396 /* Maybe all the enables should be handled here, not just this one */
5397 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5398 gameMode == Training || gameMode == PlayFromGameFile);
5403 * Button/menu procedures
5405 void ResetProc(w, event, prms, nprms)
5414 int LoadGamePopUp(f, gameNumber, title)
5419 cmailMsgLoaded = FALSE;
5420 if (gameNumber == 0) {
5421 int error = GameListBuild(f);
5423 DisplayError(_("Cannot build game list"), error);
5424 } else if (!ListEmpty(&gameList) &&
5425 ((ListGame *) gameList.tailPred)->number > 1) {
5426 GameListPopUp(f, title);
5432 return LoadGame(f, gameNumber, title, FALSE);
5435 void LoadGameProc(w, event, prms, nprms)
5441 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5444 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5447 void LoadNextGameProc(w, event, prms, nprms)
5456 void LoadPrevGameProc(w, event, prms, nprms)
5465 void ReloadGameProc(w, event, prms, nprms)
5474 void LoadNextPositionProc(w, event, prms, nprms)
5483 void LoadPrevPositionProc(w, event, prms, nprms)
5492 void ReloadPositionProc(w, event, prms, nprms)
5501 void LoadPositionProc(w, event, prms, nprms)
5507 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5510 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5513 void SaveGameProc(w, event, prms, nprms)
5519 FileNamePopUp(_("Save game file name?"),
5520 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5524 void SavePositionProc(w, event, prms, nprms)
5530 FileNamePopUp(_("Save position file name?"),
5531 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5535 void ReloadCmailMsgProc(w, event, prms, nprms)
5541 ReloadCmailMsgEvent(FALSE);
5544 void MailMoveProc(w, event, prms, nprms)
5553 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5554 static char *selected_fen_position=NULL;
5557 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5558 Atom *type_return, XtPointer *value_return,
5559 unsigned long *length_return, int *format_return)
5561 char *selection_tmp;
5563 if (!selected_fen_position) return False; /* should never happen */
5564 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5565 /* note: since no XtSelectionDoneProc was registered, Xt will
5566 * automatically call XtFree on the value returned. So have to
5567 * make a copy of it allocated with XtMalloc */
5568 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5569 strcpy(selection_tmp, selected_fen_position);
5571 *value_return=selection_tmp;
5572 *length_return=strlen(selection_tmp);
5573 *type_return=*target;
5574 *format_return = 8; /* bits per byte */
5576 } else if (*target == XA_TARGETS(xDisplay)) {
5577 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5578 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5579 targets_tmp[1] = XA_STRING;
5580 *value_return = targets_tmp;
5581 *type_return = XA_ATOM;
5583 *format_return = 8 * sizeof(Atom);
5584 if (*format_return > 32) {
5585 *length_return *= *format_return / 32;
5586 *format_return = 32;
5594 /* note: when called from menu all parameters are NULL, so no clue what the
5595 * Widget which was clicked on was, or what the click event was
5597 void CopyPositionProc(w, event, prms, nprms)
5604 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5605 * have a notion of a position that is selected but not copied.
5606 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5608 if (selected_fen_position) free(selected_fen_position);
5609 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5610 if (!selected_fen_position) return;
5611 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5613 SendPositionSelection,
5614 NULL/* lose_ownership_proc */ ,
5615 NULL/* transfer_done_proc */);
5616 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5618 SendPositionSelection,
5619 NULL/* lose_ownership_proc */ ,
5620 NULL/* transfer_done_proc */);
5623 /* function called when the data to Paste is ready */
5625 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5626 Atom *type, XtPointer value, unsigned long *len, int *format)
5629 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5630 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5631 EditPositionPasteFEN(fenstr);
5635 /* called when Paste Position button is pressed,
5636 * all parameters will be NULL */
5637 void PastePositionProc(w, event, prms, nprms)
5643 XtGetSelectionValue(menuBarWidget,
5644 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5645 /* (XtSelectionCallbackProc) */ PastePositionCB,
5646 NULL, /* client_data passed to PastePositionCB */
5648 /* better to use the time field from the event that triggered the
5649 * call to this function, but that isn't trivial to get
5657 SendGameSelection(Widget w, Atom *selection, Atom *target,
5658 Atom *type_return, XtPointer *value_return,
5659 unsigned long *length_return, int *format_return)
5661 char *selection_tmp;
5663 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5664 FILE* f = fopen(gameCopyFilename, "r");
5667 if (f == NULL) return False;
5671 selection_tmp = XtMalloc(len + 1);
5672 count = fread(selection_tmp, 1, len, f);
5674 XtFree(selection_tmp);
5677 selection_tmp[len] = NULLCHAR;
5678 *value_return = selection_tmp;
5679 *length_return = len;
5680 *type_return = *target;
5681 *format_return = 8; /* bits per byte */
5683 } else if (*target == XA_TARGETS(xDisplay)) {
5684 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5685 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5686 targets_tmp[1] = XA_STRING;
5687 *value_return = targets_tmp;
5688 *type_return = XA_ATOM;
5690 *format_return = 8 * sizeof(Atom);
5691 if (*format_return > 32) {
5692 *length_return *= *format_return / 32;
5693 *format_return = 32;
5701 /* note: when called from menu all parameters are NULL, so no clue what the
5702 * Widget which was clicked on was, or what the click event was
5704 void CopyGameProc(w, event, prms, nprms)
5712 ret = SaveGameToFile(gameCopyFilename, FALSE);
5716 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5717 * have a notion of a game that is selected but not copied.
5718 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5720 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5723 NULL/* lose_ownership_proc */ ,
5724 NULL/* transfer_done_proc */);
5725 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5728 NULL/* lose_ownership_proc */ ,
5729 NULL/* transfer_done_proc */);
5732 /* function called when the data to Paste is ready */
5734 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5735 Atom *type, XtPointer value, unsigned long *len, int *format)
5738 if (value == NULL || *len == 0) {
5739 return; /* nothing had been selected to copy */
5741 f = fopen(gamePasteFilename, "w");
5743 DisplayError(_("Can't open temp file"), errno);
5746 fwrite(value, 1, *len, f);
5749 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5752 /* called when Paste Game button is pressed,
5753 * all parameters will be NULL */
5754 void PasteGameProc(w, event, prms, nprms)
5760 XtGetSelectionValue(menuBarWidget,
5761 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5762 /* (XtSelectionCallbackProc) */ PasteGameCB,
5763 NULL, /* client_data passed to PasteGameCB */
5765 /* better to use the time field from the event that triggered the
5766 * call to this function, but that isn't trivial to get
5776 SaveGameProc(NULL, NULL, NULL, NULL);
5780 void QuitProc(w, event, prms, nprms)
5789 void PauseProc(w, event, prms, nprms)
5799 void MachineBlackProc(w, event, prms, nprms)
5805 MachineBlackEvent();
5808 void MachineWhiteProc(w, event, prms, nprms)
5814 MachineWhiteEvent();
5817 void AnalyzeModeProc(w, event, prms, nprms)
5825 if (!first.analysisSupport) {
5826 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5827 DisplayError(buf, 0);
5830 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5831 if (appData.icsActive) {
5832 if (gameMode != IcsObserving) {
5833 sprintf(buf,_("You are not observing a game"));
5834 DisplayError(buf, 0);
5836 if (appData.icsEngineAnalyze) {
5837 if (appData.debugMode)
5838 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5844 /* if enable, use want disable icsEngineAnalyze */
5845 if (appData.icsEngineAnalyze) {
5850 appData.icsEngineAnalyze = TRUE;
5851 if (appData.debugMode)
5852 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5854 if (!appData.showThinking)
5855 ShowThinkingProc(w,event,prms,nprms);
5860 void AnalyzeFileProc(w, event, prms, nprms)
5866 if (!first.analysisSupport) {
5868 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5869 DisplayError(buf, 0);
5874 if (!appData.showThinking)
5875 ShowThinkingProc(w,event,prms,nprms);
5878 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5879 AnalysisPeriodicEvent(1);
5882 void TwoMachinesProc(w, event, prms, nprms)
5891 void IcsClientProc(w, event, prms, nprms)
5900 void EditGameProc(w, event, prms, nprms)
5909 void EditPositionProc(w, event, prms, nprms)
5915 EditPositionEvent();
5918 void TrainingProc(w, event, prms, nprms)
5927 void EditCommentProc(w, event, prms, nprms)
5934 EditCommentPopDown();
5940 void IcsInputBoxProc(w, event, prms, nprms)
5946 if (ICSInputBoxUp) {
5947 ICSInputBoxPopDown();
5953 void AcceptProc(w, event, prms, nprms)
5962 void DeclineProc(w, event, prms, nprms)
5971 void RematchProc(w, event, prms, nprms)
5980 void CallFlagProc(w, event, prms, nprms)
5989 void DrawProc(w, event, prms, nprms)
5998 void AbortProc(w, event, prms, nprms)
6007 void AdjournProc(w, event, prms, nprms)
6016 void ResignProc(w, event, prms, nprms)
6025 void AdjuWhiteProc(w, event, prms, nprms)
6031 UserAdjudicationEvent(+1);
6034 void AdjuBlackProc(w, event, prms, nprms)
6040 UserAdjudicationEvent(-1);
6043 void AdjuDrawProc(w, event, prms, nprms)
6049 UserAdjudicationEvent(0);
6052 void EnterKeyProc(w, event, prms, nprms)
6058 if (ICSInputBoxUp == True)
6062 void StopObservingProc(w, event, prms, nprms)
6068 StopObservingEvent();
6071 void StopExaminingProc(w, event, prms, nprms)
6077 StopExaminingEvent();
6081 void ForwardProc(w, event, prms, nprms)
6091 void BackwardProc(w, event, prms, nprms)
6100 void ToStartProc(w, event, prms, nprms)
6109 void ToEndProc(w, event, prms, nprms)
6118 void RevertProc(w, event, prms, nprms)
6127 void TruncateGameProc(w, event, prms, nprms)
6133 TruncateGameEvent();
6135 void RetractMoveProc(w, event, prms, nprms)
6144 void MoveNowProc(w, event, prms, nprms)
6154 void AlwaysQueenProc(w, event, prms, nprms)
6162 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6164 if (appData.alwaysPromoteToQueen) {
6165 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6167 XtSetArg(args[0], XtNleftBitmap, None);
6169 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6173 void AnimateDraggingProc(w, event, prms, nprms)
6181 appData.animateDragging = !appData.animateDragging;
6183 if (appData.animateDragging) {
6184 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6187 XtSetArg(args[0], XtNleftBitmap, None);
6189 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6193 void AnimateMovingProc(w, event, prms, nprms)
6201 appData.animate = !appData.animate;
6203 if (appData.animate) {
6204 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6207 XtSetArg(args[0], XtNleftBitmap, None);
6209 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6213 void AutocommProc(w, event, prms, nprms)
6221 appData.autoComment = !appData.autoComment;
6223 if (appData.autoComment) {
6224 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6226 XtSetArg(args[0], XtNleftBitmap, None);
6228 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6233 void AutoflagProc(w, event, prms, nprms)
6241 appData.autoCallFlag = !appData.autoCallFlag;
6243 if (appData.autoCallFlag) {
6244 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6246 XtSetArg(args[0], XtNleftBitmap, None);
6248 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6252 void AutoflipProc(w, event, prms, nprms)
6260 appData.autoFlipView = !appData.autoFlipView;
6262 if (appData.autoFlipView) {
6263 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6265 XtSetArg(args[0], XtNleftBitmap, None);
6267 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6271 void AutobsProc(w, event, prms, nprms)
6279 appData.autoObserve = !appData.autoObserve;
6281 if (appData.autoObserve) {
6282 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6284 XtSetArg(args[0], XtNleftBitmap, None);
6286 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6290 void AutoraiseProc(w, event, prms, nprms)
6298 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6300 if (appData.autoRaiseBoard) {
6301 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6303 XtSetArg(args[0], XtNleftBitmap, None);
6305 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6309 void AutosaveProc(w, event, prms, nprms)
6317 appData.autoSaveGames = !appData.autoSaveGames;
6319 if (appData.autoSaveGames) {
6320 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6322 XtSetArg(args[0], XtNleftBitmap, None);
6324 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6328 void BlindfoldProc(w, event, prms, nprms)
6336 appData.blindfold = !appData.blindfold;
6338 if (appData.blindfold) {
6339 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6341 XtSetArg(args[0], XtNleftBitmap, None);
6343 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6346 DrawPosition(True, NULL);
6349 void TestLegalityProc(w, event, prms, nprms)
6357 appData.testLegality = !appData.testLegality;
6359 if (appData.testLegality) {
6360 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6362 XtSetArg(args[0], XtNleftBitmap, None);
6364 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6369 void FlashMovesProc(w, event, prms, nprms)
6377 if (appData.flashCount == 0) {
6378 appData.flashCount = 3;
6380 appData.flashCount = -appData.flashCount;
6383 if (appData.flashCount > 0) {
6384 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6386 XtSetArg(args[0], XtNleftBitmap, None);
6388 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6392 void FlipViewProc(w, event, prms, nprms)
6398 flipView = !flipView;
6399 DrawPosition(True, NULL);
6402 void GetMoveListProc(w, event, prms, nprms)
6410 appData.getMoveList = !appData.getMoveList;
6412 if (appData.getMoveList) {
6413 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6416 XtSetArg(args[0], XtNleftBitmap, None);
6418 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6423 void HighlightDraggingProc(w, event, prms, nprms)
6431 appData.highlightDragging = !appData.highlightDragging;
6433 if (appData.highlightDragging) {
6434 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6436 XtSetArg(args[0], XtNleftBitmap, None);
6438 XtSetValues(XtNameToWidget(menuBarWidget,
6439 "menuOptions.Highlight Dragging"), args, 1);
6443 void HighlightLastMoveProc(w, event, prms, nprms)
6451 appData.highlightLastMove = !appData.highlightLastMove;
6453 if (appData.highlightLastMove) {
6454 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6456 XtSetArg(args[0], XtNleftBitmap, None);
6458 XtSetValues(XtNameToWidget(menuBarWidget,
6459 "menuOptions.Highlight Last Move"), args, 1);
6462 void IcsAlarmProc(w, event, prms, nprms)
6470 appData.icsAlarm = !appData.icsAlarm;
6472 if (appData.icsAlarm) {
6473 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6475 XtSetArg(args[0], XtNleftBitmap, None);
6477 XtSetValues(XtNameToWidget(menuBarWidget,
6478 "menuOptions.ICS Alarm"), args, 1);
6481 void MoveSoundProc(w, event, prms, nprms)
6489 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6491 if (appData.ringBellAfterMoves) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6494 XtSetArg(args[0], XtNleftBitmap, None);
6496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6501 void OldSaveStyleProc(w, event, prms, nprms)
6509 appData.oldSaveStyle = !appData.oldSaveStyle;
6511 if (appData.oldSaveStyle) {
6512 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6520 void PeriodicUpdatesProc(w, event, prms, nprms)
6528 PeriodicUpdatesEvent(!appData.periodicUpdates);
6530 if (appData.periodicUpdates) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6539 void PonderNextMoveProc(w, event, prms, nprms)
6547 PonderNextMoveEvent(!appData.ponderNextMove);
6549 if (appData.ponderNextMove) {
6550 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6552 XtSetArg(args[0], XtNleftBitmap, None);
6554 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6558 void PopupExitMessageProc(w, event, prms, nprms)
6566 appData.popupExitMessage = !appData.popupExitMessage;
6568 if (appData.popupExitMessage) {
6569 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6571 XtSetArg(args[0], XtNleftBitmap, None);
6573 XtSetValues(XtNameToWidget(menuBarWidget,
6574 "menuOptions.Popup Exit Message"), args, 1);
6577 void PopupMoveErrorsProc(w, event, prms, nprms)
6585 appData.popupMoveErrors = !appData.popupMoveErrors;
6587 if (appData.popupMoveErrors) {
6588 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6590 XtSetArg(args[0], XtNleftBitmap, None);
6592 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6596 void PremoveProc(w, event, prms, nprms)
6604 appData.premove = !appData.premove;
6606 if (appData.premove) {
6607 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6609 XtSetArg(args[0], XtNleftBitmap, None);
6611 XtSetValues(XtNameToWidget(menuBarWidget,
6612 "menuOptions.Premove"), args, 1);
6615 void QuietPlayProc(w, event, prms, nprms)
6623 appData.quietPlay = !appData.quietPlay;
6625 if (appData.quietPlay) {
6626 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6628 XtSetArg(args[0], XtNleftBitmap, None);
6630 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6634 void ShowCoordsProc(w, event, prms, nprms)
6642 appData.showCoords = !appData.showCoords;
6644 if (appData.showCoords) {
6645 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6647 XtSetArg(args[0], XtNleftBitmap, None);
6649 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6652 DrawPosition(True, NULL);
6655 void ShowThinkingProc(w, event, prms, nprms)
6661 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6662 ShowThinkingEvent();
6665 void HideThinkingProc(w, event, prms, nprms)
6673 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6674 ShowThinkingEvent();
6676 if (appData.hideThinkingFromHuman) {
6677 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6679 XtSetArg(args[0], XtNleftBitmap, None);
6681 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6685 void SaveOnExitProc(w, event, prms, nprms)
6693 saveSettingsOnExit = !saveSettingsOnExit;
6695 if (saveSettingsOnExit) {
6696 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6698 XtSetArg(args[0], XtNleftBitmap, None);
6700 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6704 void SaveSettingsProc(w, event, prms, nprms)
6710 SaveSettings(settingsFileName);
6713 void InfoProc(w, event, prms, nprms)
6720 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6725 void ManProc(w, event, prms, nprms)
6733 if (nprms && *nprms > 0)
6737 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6741 void HintProc(w, event, prms, nprms)
6750 void BookProc(w, event, prms, nprms)
6759 void AboutProc(w, event, prms, nprms)
6767 char *zippy = " (with Zippy code)";
6771 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6772 programVersion, zippy,
6773 "Copyright 1991 Digital Equipment Corporation",
6774 "Enhancements Copyright 1992-2009 Free Software Foundation",
6775 "Enhancements Copyright 2005 Alessandro Scotti",
6776 PACKAGE, " is free software and carries NO WARRANTY;",
6777 "see the file COPYING for more information.");
6778 ErrorPopUp(_("About XBoard"), buf, FALSE);
6781 void DebugProc(w, event, prms, nprms)
6787 appData.debugMode = !appData.debugMode;
6790 void AboutGameProc(w, event, prms, nprms)
6799 void NothingProc(w, event, prms, nprms)
6808 void Iconify(w, event, prms, nprms)
6817 XtSetArg(args[0], XtNiconic, True);
6818 XtSetValues(shellWidget, args, 1);
6821 void DisplayMessage(message, extMessage)
6822 char *message, *extMessage;
6824 /* display a message in the message widget */
6833 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6838 message = extMessage;
6842 /* need to test if messageWidget already exists, since this function
6843 can also be called during the startup, if for example a Xresource
6844 is not set up correctly */
6847 XtSetArg(arg, XtNlabel, message);
6848 XtSetValues(messageWidget, &arg, 1);
6854 void DisplayTitle(text)
6859 char title[MSG_SIZ];
6862 if (text == NULL) text = "";
6864 if (appData.titleInWindow) {
6866 XtSetArg(args[i], XtNlabel, text); i++;
6867 XtSetValues(titleWidget, args, i);
6870 if (*text != NULLCHAR) {
6872 strcpy(title, text);
6873 } else if (appData.icsActive) {
6874 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6875 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6876 } else if (appData.cmailGameName[0] != NULLCHAR) {
6877 snprintf(icon, sizeof(icon), "%s", "CMail");
6878 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6880 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6881 } else if (gameInfo.variant == VariantGothic) {
6882 strcpy(icon, programName);
6883 strcpy(title, GOTHIC);
6886 } else if (gameInfo.variant == VariantFalcon) {
6887 strcpy(icon, programName);
6888 strcpy(title, FALCON);
6890 } else if (appData.noChessProgram) {
6891 strcpy(icon, programName);
6892 strcpy(title, programName);
6894 strcpy(icon, first.tidy);
6895 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6898 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6899 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6900 XtSetValues(shellWidget, args, i);
6904 void DisplayError(message, error)
6911 if (appData.debugMode || appData.matchMode) {
6912 fprintf(stderr, "%s: %s\n", programName, message);
6915 if (appData.debugMode || appData.matchMode) {
6916 fprintf(stderr, "%s: %s: %s\n",
6917 programName, message, strerror(error));
6919 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6922 ErrorPopUp(_("Error"), message, FALSE);
6926 void DisplayMoveError(message)
6931 DrawPosition(FALSE, NULL);
6932 if (appData.debugMode || appData.matchMode) {
6933 fprintf(stderr, "%s: %s\n", programName, message);
6935 if (appData.popupMoveErrors) {
6936 ErrorPopUp(_("Error"), message, FALSE);
6938 DisplayMessage(message, "");
6943 void DisplayFatalError(message, error, status)
6949 errorExitStatus = status;
6951 fprintf(stderr, "%s: %s\n", programName, message);
6953 fprintf(stderr, "%s: %s: %s\n",
6954 programName, message, strerror(error));
6955 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6958 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6959 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6965 void DisplayInformation(message)
6969 ErrorPopUp(_("Information"), message, TRUE);
6972 void DisplayNote(message)
6976 ErrorPopUp(_("Note"), message, FALSE);
6980 NullXErrorCheck(dpy, error_event)
6982 XErrorEvent *error_event;
6987 void DisplayIcsInteractionTitle(message)
6990 if (oldICSInteractionTitle == NULL) {
6991 /* Magic to find the old window title, adapted from vim */
6992 char *wina = getenv("WINDOWID");
6994 Window win = (Window) atoi(wina);
6995 Window root, parent, *children;
6996 unsigned int nchildren;
6997 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6999 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7000 if (!XQueryTree(xDisplay, win, &root, &parent,
7001 &children, &nchildren)) break;
7002 if (children) XFree((void *)children);
7003 if (parent == root || parent == 0) break;
7006 XSetErrorHandler(oldHandler);
7008 if (oldICSInteractionTitle == NULL) {
7009 oldICSInteractionTitle = "xterm";
7012 printf("\033]0;%s\007", message);
7016 char pendingReplyPrefix[MSG_SIZ];
7017 ProcRef pendingReplyPR;
7019 void AskQuestionProc(w, event, prms, nprms)
7026 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7030 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7033 void AskQuestionPopDown()
7035 if (!askQuestionUp) return;
7036 XtPopdown(askQuestionShell);
7037 XtDestroyWidget(askQuestionShell);
7038 askQuestionUp = False;
7041 void AskQuestionReplyAction(w, event, prms, nprms)
7051 reply = XawDialogGetValueString(w = XtParent(w));
7052 strcpy(buf, pendingReplyPrefix);
7053 if (*buf) strcat(buf, " ");
7056 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7057 AskQuestionPopDown();
7059 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7062 void AskQuestionCallback(w, client_data, call_data)
7064 XtPointer client_data, call_data;
7069 XtSetArg(args[0], XtNlabel, &name);
7070 XtGetValues(w, args, 1);
7072 if (strcmp(name, _("cancel")) == 0) {
7073 AskQuestionPopDown();
7075 AskQuestionReplyAction(w, NULL, NULL, NULL);
7079 void AskQuestion(title, question, replyPrefix, pr)
7080 char *title, *question, *replyPrefix;
7084 Widget popup, layout, dialog, edit;
7090 strcpy(pendingReplyPrefix, replyPrefix);
7091 pendingReplyPR = pr;
7094 XtSetArg(args[i], XtNresizable, True); i++;
7095 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7096 askQuestionShell = popup =
7097 XtCreatePopupShell(title, transientShellWidgetClass,
7098 shellWidget, args, i);
7101 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7102 layoutArgs, XtNumber(layoutArgs));
7105 XtSetArg(args[i], XtNlabel, question); i++;
7106 XtSetArg(args[i], XtNvalue, ""); i++;
7107 XtSetArg(args[i], XtNborderWidth, 0); i++;
7108 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7111 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7112 (XtPointer) dialog);
7113 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7114 (XtPointer) dialog);
7116 XtRealizeWidget(popup);
7117 CatchDeleteWindow(popup, "AskQuestionPopDown");
7119 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7120 &x, &y, &win_x, &win_y, &mask);
7122 XtSetArg(args[0], XtNx, x - 10);
7123 XtSetArg(args[1], XtNy, y - 30);
7124 XtSetValues(popup, args, 2);
7126 XtPopup(popup, XtGrabExclusive);
7127 askQuestionUp = True;
7129 edit = XtNameToWidget(dialog, "*value");
7130 XtSetKeyboardFocus(popup, edit);
7138 if (*name == NULLCHAR) {
7140 } else if (strcmp(name, "$") == 0) {
7141 putc(BELLCHAR, stderr);
7144 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7152 PlaySound(appData.soundMove);
7158 PlaySound(appData.soundIcsWin);
7164 PlaySound(appData.soundIcsLoss);
7170 PlaySound(appData.soundIcsDraw);
7174 PlayIcsUnfinishedSound()
7176 PlaySound(appData.soundIcsUnfinished);
7182 PlaySound(appData.soundIcsAlarm);
7188 system("stty echo");
7194 system("stty -echo");
7198 Colorize(cc, continuation)
7203 int count, outCount, error;
7205 if (textColors[(int)cc].bg > 0) {
7206 if (textColors[(int)cc].fg > 0) {
7207 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7208 textColors[(int)cc].fg, textColors[(int)cc].bg);
7210 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7211 textColors[(int)cc].bg);
7214 if (textColors[(int)cc].fg > 0) {
7215 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7216 textColors[(int)cc].fg);
7218 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7221 count = strlen(buf);
7222 outCount = OutputToProcess(NoProc, buf, count, &error);
7223 if (outCount < count) {
7224 DisplayFatalError(_("Error writing to display"), error, 1);
7227 if (continuation) return;
7230 PlaySound(appData.soundShout);
7233 PlaySound(appData.soundSShout);
7236 PlaySound(appData.soundChannel1);
7239 PlaySound(appData.soundChannel);
7242 PlaySound(appData.soundKibitz);
7245 PlaySound(appData.soundTell);
7247 case ColorChallenge:
7248 PlaySound(appData.soundChallenge);
7251 PlaySound(appData.soundRequest);
7254 PlaySound(appData.soundSeek);
7265 return getpwuid(getuid())->pw_name;
7268 static char *ExpandPathName(path)
7271 static char static_buf[2000];
7272 char *d, *s, buf[2000];
7278 while (*s && isspace(*s))
7287 if (*(s+1) == '/') {
7288 strcpy(d, getpwuid(getuid())->pw_dir);
7293 *strchr(buf, '/') = 0;
7294 pwd = getpwnam(buf);
7297 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7301 strcpy(d, pwd->pw_dir);
7302 strcat(d, strchr(s+1, '/'));
7313 static char host_name[MSG_SIZ];
7315 #if HAVE_GETHOSTNAME
7316 gethostname(host_name, MSG_SIZ);
7318 #else /* not HAVE_GETHOSTNAME */
7319 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7320 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7322 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7324 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7325 #endif /* not HAVE_GETHOSTNAME */
7328 XtIntervalId delayedEventTimerXID = 0;
7329 DelayedEventCallback delayedEventCallback = 0;
7334 delayedEventTimerXID = 0;
7335 delayedEventCallback();
7339 ScheduleDelayedEvent(cb, millisec)
7340 DelayedEventCallback cb; long millisec;
7342 if(delayedEventTimerXID && delayedEventCallback == cb)
7343 // [HGM] alive: replace, rather than add or flush identical event
7344 XtRemoveTimeOut(delayedEventTimerXID);
7345 delayedEventCallback = cb;
7346 delayedEventTimerXID =
7347 XtAppAddTimeOut(appContext, millisec,
7348 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7351 DelayedEventCallback
7354 if (delayedEventTimerXID) {
7355 return delayedEventCallback;
7362 CancelDelayedEvent()
7364 if (delayedEventTimerXID) {
7365 XtRemoveTimeOut(delayedEventTimerXID);
7366 delayedEventTimerXID = 0;
7370 XtIntervalId loadGameTimerXID = 0;
7372 int LoadGameTimerRunning()
7374 return loadGameTimerXID != 0;
7377 int StopLoadGameTimer()
7379 if (loadGameTimerXID != 0) {
7380 XtRemoveTimeOut(loadGameTimerXID);
7381 loadGameTimerXID = 0;
7389 LoadGameTimerCallback(arg, id)
7393 loadGameTimerXID = 0;
7398 StartLoadGameTimer(millisec)
7402 XtAppAddTimeOut(appContext, millisec,
7403 (XtTimerCallbackProc) LoadGameTimerCallback,
7407 XtIntervalId analysisClockXID = 0;
7410 AnalysisClockCallback(arg, id)
7414 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7415 || appData.icsEngineAnalyze) { // [DM]
7416 AnalysisPeriodicEvent(0);
7417 StartAnalysisClock();
7422 StartAnalysisClock()
7425 XtAppAddTimeOut(appContext, 2000,
7426 (XtTimerCallbackProc) AnalysisClockCallback,
7430 XtIntervalId clockTimerXID = 0;
7432 int ClockTimerRunning()
7434 return clockTimerXID != 0;
7437 int StopClockTimer()
7439 if (clockTimerXID != 0) {
7440 XtRemoveTimeOut(clockTimerXID);
7449 ClockTimerCallback(arg, id)
7458 StartClockTimer(millisec)
7462 XtAppAddTimeOut(appContext, millisec,
7463 (XtTimerCallbackProc) ClockTimerCallback,
7468 DisplayTimerLabel(w, color, timer, highlight)
7477 /* check for low time warning */
7478 Pixel foregroundOrWarningColor = timerForegroundPixel;
7481 appData.lowTimeWarning &&
7482 (timer / 1000) < appData.icsAlarmTime)
7483 foregroundOrWarningColor = lowTimeWarningColor;
7485 if (appData.clockMode) {
7486 sprintf(buf, "%s: %s", color, TimeString(timer));
7487 XtSetArg(args[0], XtNlabel, buf);
7489 sprintf(buf, "%s ", color);
7490 XtSetArg(args[0], XtNlabel, buf);
7495 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7496 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7498 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7499 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7502 XtSetValues(w, args, 3);
7506 DisplayWhiteClock(timeRemaining, highlight)
7512 if(appData.noGUI) return;
7513 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7514 if (highlight && iconPixmap == bIconPixmap) {
7515 iconPixmap = wIconPixmap;
7516 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7517 XtSetValues(shellWidget, args, 1);
7522 DisplayBlackClock(timeRemaining, highlight)
7528 if(appData.noGUI) return;
7529 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7530 if (highlight && iconPixmap == wIconPixmap) {
7531 iconPixmap = bIconPixmap;
7532 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7533 XtSetValues(shellWidget, args, 1);
7551 int StartChildProcess(cmdLine, dir, pr)
7558 int to_prog[2], from_prog[2];
7562 if (appData.debugMode) {
7563 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7566 /* We do NOT feed the cmdLine to the shell; we just
7567 parse it into blank-separated arguments in the
7568 most simple-minded way possible.
7571 strcpy(buf, cmdLine);
7576 if (p == NULL) break;
7581 SetUpChildIO(to_prog, from_prog);
7583 if ((pid = fork()) == 0) {
7585 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7586 close(to_prog[1]); // first close the unused pipe ends
7587 close(from_prog[0]);
7588 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7589 dup2(from_prog[1], 1);
7590 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7591 close(from_prog[1]); // and closing again loses one of the pipes!
7592 if(fileno(stderr) >= 2) // better safe than sorry...
7593 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7595 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7600 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7602 execvp(argv[0], argv);
7604 /* If we get here, exec failed */
7609 /* Parent process */
7611 close(from_prog[1]);
7613 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7616 cp->fdFrom = from_prog[0];
7617 cp->fdTo = to_prog[1];
7622 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7623 static RETSIGTYPE AlarmCallBack(int n)
7629 DestroyChildProcess(pr, signalType)
7633 ChildProc *cp = (ChildProc *) pr;
7635 if (cp->kind != CPReal) return;
7637 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7638 signal(SIGALRM, AlarmCallBack);
7640 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7641 kill(cp->pid, SIGKILL); // kill it forcefully
7642 wait((int *) 0); // and wait again
7646 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7648 /* Process is exiting either because of the kill or because of
7649 a quit command sent by the backend; either way, wait for it to die.
7658 InterruptChildProcess(pr)
7661 ChildProc *cp = (ChildProc *) pr;
7663 if (cp->kind != CPReal) return;
7664 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7667 int OpenTelnet(host, port, pr)
7672 char cmdLine[MSG_SIZ];
7674 if (port[0] == NULLCHAR) {
7675 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7677 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7679 return StartChildProcess(cmdLine, "", pr);
7682 int OpenTCP(host, port, pr)
7688 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7689 #else /* !OMIT_SOCKETS */
7691 struct sockaddr_in sa;
7693 unsigned short uport;
7696 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7700 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7701 sa.sin_family = AF_INET;
7702 sa.sin_addr.s_addr = INADDR_ANY;
7703 uport = (unsigned short) 0;
7704 sa.sin_port = htons(uport);
7705 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7709 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7710 if (!(hp = gethostbyname(host))) {
7712 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7713 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7714 hp->h_addrtype = AF_INET;
7716 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7717 hp->h_addr_list[0] = (char *) malloc(4);
7718 hp->h_addr_list[0][0] = b0;
7719 hp->h_addr_list[0][1] = b1;
7720 hp->h_addr_list[0][2] = b2;
7721 hp->h_addr_list[0][3] = b3;
7726 sa.sin_family = hp->h_addrtype;
7727 uport = (unsigned short) atoi(port);
7728 sa.sin_port = htons(uport);
7729 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7731 if (connect(s, (struct sockaddr *) &sa,
7732 sizeof(struct sockaddr_in)) < 0) {
7736 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7743 #endif /* !OMIT_SOCKETS */
7748 int OpenCommPort(name, pr)
7755 fd = open(name, 2, 0);
7756 if (fd < 0) return errno;
7758 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7768 int OpenLoopback(pr)
7774 SetUpChildIO(to, from);
7776 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7779 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7786 int OpenRcmd(host, user, cmd, pr)
7787 char *host, *user, *cmd;
7790 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7794 #define INPUT_SOURCE_BUF_SIZE 8192
7803 char buf[INPUT_SOURCE_BUF_SIZE];
7808 DoInputCallback(closure, source, xid)
7813 InputSource *is = (InputSource *) closure;
7818 if (is->lineByLine) {
7819 count = read(is->fd, is->unused,
7820 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7822 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7825 is->unused += count;
7827 while (p < is->unused) {
7828 q = memchr(p, '\n', is->unused - p);
7829 if (q == NULL) break;
7831 (is->func)(is, is->closure, p, q - p, 0);
7835 while (p < is->unused) {
7840 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7845 (is->func)(is, is->closure, is->buf, count, error);
7849 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7856 ChildProc *cp = (ChildProc *) pr;
7858 is = (InputSource *) calloc(1, sizeof(InputSource));
7859 is->lineByLine = lineByLine;
7863 is->fd = fileno(stdin);
7865 is->kind = cp->kind;
7866 is->fd = cp->fdFrom;
7869 is->unused = is->buf;
7872 is->xid = XtAppAddInput(appContext, is->fd,
7873 (XtPointer) (XtInputReadMask),
7874 (XtInputCallbackProc) DoInputCallback,
7876 is->closure = closure;
7877 return (InputSourceRef) is;
7881 RemoveInputSource(isr)
7884 InputSource *is = (InputSource *) isr;
7886 if (is->xid == 0) return;
7887 XtRemoveInput(is->xid);
7891 int OutputToProcess(pr, message, count, outError)
7897 static int line = 0;
7898 ChildProc *cp = (ChildProc *) pr;
7903 if (appData.noJoin || !appData.useInternalWrap)
7904 outCount = fwrite(message, 1, count, stdout);
7907 int width = get_term_width();
7908 int len = wrap(NULL, message, count, width, &line);
7909 char *msg = malloc(len);
7913 outCount = fwrite(message, 1, count, stdout);
7916 dbgchk = wrap(msg, message, count, width, &line);
7917 if (dbgchk != len && appData.debugMode)
7918 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7919 outCount = fwrite(msg, 1, dbgchk, stdout);
7925 outCount = write(cp->fdTo, message, count);
7935 /* Output message to process, with "ms" milliseconds of delay
7936 between each character. This is needed when sending the logon
7937 script to ICC, which for some reason doesn't like the
7938 instantaneous send. */
7939 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7946 ChildProc *cp = (ChildProc *) pr;
7951 r = write(cp->fdTo, message++, 1);
7964 /**** Animation code by Hugh Fisher, DCS, ANU.
7966 Known problem: if a window overlapping the board is
7967 moved away while a piece is being animated underneath,
7968 the newly exposed area won't be updated properly.
7969 I can live with this.
7971 Known problem: if you look carefully at the animation
7972 of pieces in mono mode, they are being drawn as solid
7973 shapes without interior detail while moving. Fixing
7974 this would be a major complication for minimal return.
7977 /* Masks for XPM pieces. Black and white pieces can have
7978 different shapes, but in the interest of retaining my
7979 sanity pieces must have the same outline on both light
7980 and dark squares, and all pieces must use the same
7981 background square colors/images. */
7983 static int xpmDone = 0;
7986 CreateAnimMasks (pieceDepth)
7993 unsigned long plane;
7996 /* Need a bitmap just to get a GC with right depth */
7997 buf = XCreatePixmap(xDisplay, xBoardWindow,
7999 values.foreground = 1;
8000 values.background = 0;
8001 /* Don't use XtGetGC, not read only */
8002 maskGC = XCreateGC(xDisplay, buf,
8003 GCForeground | GCBackground, &values);
8004 XFreePixmap(xDisplay, buf);
8006 buf = XCreatePixmap(xDisplay, xBoardWindow,
8007 squareSize, squareSize, pieceDepth);
8008 values.foreground = XBlackPixel(xDisplay, xScreen);
8009 values.background = XWhitePixel(xDisplay, xScreen);
8010 bufGC = XCreateGC(xDisplay, buf,
8011 GCForeground | GCBackground, &values);
8013 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8014 /* Begin with empty mask */
8015 if(!xpmDone) // [HGM] pieces: keep using existing
8016 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8017 squareSize, squareSize, 1);
8018 XSetFunction(xDisplay, maskGC, GXclear);
8019 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8020 0, 0, squareSize, squareSize);
8022 /* Take a copy of the piece */
8027 XSetFunction(xDisplay, bufGC, GXcopy);
8028 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8030 0, 0, squareSize, squareSize, 0, 0);
8032 /* XOR the background (light) over the piece */
8033 XSetFunction(xDisplay, bufGC, GXxor);
8035 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8036 0, 0, squareSize, squareSize, 0, 0);
8038 XSetForeground(xDisplay, bufGC, lightSquareColor);
8039 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8042 /* We now have an inverted piece image with the background
8043 erased. Construct mask by just selecting all the non-zero
8044 pixels - no need to reconstruct the original image. */
8045 XSetFunction(xDisplay, maskGC, GXor);
8047 /* Might be quicker to download an XImage and create bitmap
8048 data from it rather than this N copies per piece, but it
8049 only takes a fraction of a second and there is a much
8050 longer delay for loading the pieces. */
8051 for (n = 0; n < pieceDepth; n ++) {
8052 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8053 0, 0, squareSize, squareSize,
8059 XFreePixmap(xDisplay, buf);
8060 XFreeGC(xDisplay, bufGC);
8061 XFreeGC(xDisplay, maskGC);
8065 InitAnimState (anim, info)
8067 XWindowAttributes * info;
8072 /* Each buffer is square size, same depth as window */
8073 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8074 squareSize, squareSize, info->depth);
8075 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8076 squareSize, squareSize, info->depth);
8078 /* Create a plain GC for blitting */
8079 mask = GCForeground | GCBackground | GCFunction |
8080 GCPlaneMask | GCGraphicsExposures;
8081 values.foreground = XBlackPixel(xDisplay, xScreen);
8082 values.background = XWhitePixel(xDisplay, xScreen);
8083 values.function = GXcopy;
8084 values.plane_mask = AllPlanes;
8085 values.graphics_exposures = False;
8086 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8088 /* Piece will be copied from an existing context at
8089 the start of each new animation/drag. */
8090 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8092 /* Outline will be a read-only copy of an existing */
8093 anim->outlineGC = None;
8099 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8100 XWindowAttributes info;
8102 if (xpmDone && gameInfo.variant == old) return;
8103 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8104 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8106 InitAnimState(&game, &info);
8107 InitAnimState(&player, &info);
8109 /* For XPM pieces, we need bitmaps to use as masks. */
8111 CreateAnimMasks(info.depth);
8117 static Boolean frameWaiting;
8119 static RETSIGTYPE FrameAlarm (sig)
8122 frameWaiting = False;
8123 /* In case System-V style signals. Needed?? */
8124 signal(SIGALRM, FrameAlarm);
8131 struct itimerval delay;
8133 XSync(xDisplay, False);
8136 frameWaiting = True;
8137 signal(SIGALRM, FrameAlarm);
8138 delay.it_interval.tv_sec =
8139 delay.it_value.tv_sec = time / 1000;
8140 delay.it_interval.tv_usec =
8141 delay.it_value.tv_usec = (time % 1000) * 1000;
8142 setitimer(ITIMER_REAL, &delay, NULL);
8143 while (frameWaiting) pause();
8144 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8145 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8146 setitimer(ITIMER_REAL, &delay, NULL);
8156 XSync(xDisplay, False);
8158 usleep(time * 1000);
8163 /* Convert board position to corner of screen rect and color */
8166 ScreenSquare(column, row, pt, color)
8167 int column; int row; XPoint * pt; int * color;
8170 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8171 pt->y = lineGap + row * (squareSize + lineGap);
8173 pt->x = lineGap + column * (squareSize + lineGap);
8174 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8176 *color = SquareColor(row, column);
8179 /* Convert window coords to square */
8182 BoardSquare(x, y, column, row)
8183 int x; int y; int * column; int * row;
8185 *column = EventToSquare(x, BOARD_WIDTH);
8186 if (flipView && *column >= 0)
8187 *column = BOARD_WIDTH - 1 - *column;
8188 *row = EventToSquare(y, BOARD_HEIGHT);
8189 if (!flipView && *row >= 0)
8190 *row = BOARD_HEIGHT - 1 - *row;
8195 #undef Max /* just in case */
8197 #define Max(a, b) ((a) > (b) ? (a) : (b))
8198 #define Min(a, b) ((a) < (b) ? (a) : (b))
8201 SetRect(rect, x, y, width, height)
8202 XRectangle * rect; int x; int y; int width; int height;
8206 rect->width = width;
8207 rect->height = height;
8210 /* Test if two frames overlap. If they do, return
8211 intersection rect within old and location of
8212 that rect within new. */
8215 Intersect(old, new, size, area, pt)
8216 XPoint * old; XPoint * new;
8217 int size; XRectangle * area; XPoint * pt;
8219 if (old->x > new->x + size || new->x > old->x + size ||
8220 old->y > new->y + size || new->y > old->y + size) {
8223 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8224 size - abs(old->x - new->x), size - abs(old->y - new->y));
8225 pt->x = Max(old->x - new->x, 0);
8226 pt->y = Max(old->y - new->y, 0);
8231 /* For two overlapping frames, return the rect(s)
8232 in the old that do not intersect with the new. */
8235 CalcUpdateRects(old, new, size, update, nUpdates)
8236 XPoint * old; XPoint * new; int size;
8237 XRectangle update[]; int * nUpdates;
8241 /* If old = new (shouldn't happen) then nothing to draw */
8242 if (old->x == new->x && old->y == new->y) {
8246 /* Work out what bits overlap. Since we know the rects
8247 are the same size we don't need a full intersect calc. */
8249 /* Top or bottom edge? */
8250 if (new->y > old->y) {
8251 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8253 } else if (old->y > new->y) {
8254 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8255 size, old->y - new->y);
8258 /* Left or right edge - don't overlap any update calculated above. */
8259 if (new->x > old->x) {
8260 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8261 new->x - old->x, size - abs(new->y - old->y));
8263 } else if (old->x > new->x) {
8264 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8265 old->x - new->x, size - abs(new->y - old->y));
8272 /* Generate a series of frame coords from start->mid->finish.
8273 The movement rate doubles until the half way point is
8274 reached, then halves back down to the final destination,
8275 which gives a nice slow in/out effect. The algorithmn
8276 may seem to generate too many intermediates for short
8277 moves, but remember that the purpose is to attract the
8278 viewers attention to the piece about to be moved and
8279 then to where it ends up. Too few frames would be less
8283 Tween(start, mid, finish, factor, frames, nFrames)
8284 XPoint * start; XPoint * mid;
8285 XPoint * finish; int factor;
8286 XPoint frames[]; int * nFrames;
8288 int fraction, n, count;
8292 /* Slow in, stepping 1/16th, then 1/8th, ... */
8294 for (n = 0; n < factor; n++)
8296 for (n = 0; n < factor; n++) {
8297 frames[count].x = start->x + (mid->x - start->x) / fraction;
8298 frames[count].y = start->y + (mid->y - start->y) / fraction;
8300 fraction = fraction / 2;
8304 frames[count] = *mid;
8307 /* Slow out, stepping 1/2, then 1/4, ... */
8309 for (n = 0; n < factor; n++) {
8310 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8311 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8313 fraction = fraction * 2;
8318 /* Draw a piece on the screen without disturbing what's there */
8321 SelectGCMask(piece, clip, outline, mask)
8322 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8326 /* Bitmap for piece being moved. */
8327 if (appData.monoMode) {
8328 *mask = *pieceToSolid(piece);
8329 } else if (useImages) {
8331 *mask = xpmMask[piece];
8333 *mask = ximMaskPm[piece];
8336 *mask = *pieceToSolid(piece);
8339 /* GC for piece being moved. Square color doesn't matter, but
8340 since it gets modified we make a copy of the original. */
8342 if (appData.monoMode)
8347 if (appData.monoMode)
8352 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8354 /* Outline only used in mono mode and is not modified */
8356 *outline = bwPieceGC;
8358 *outline = wbPieceGC;
8362 OverlayPiece(piece, clip, outline, dest)
8363 ChessSquare piece; GC clip; GC outline; Drawable dest;
8368 /* Draw solid rectangle which will be clipped to shape of piece */
8369 XFillRectangle(xDisplay, dest, clip,
8370 0, 0, squareSize, squareSize);
8371 if (appData.monoMode)
8372 /* Also draw outline in contrasting color for black
8373 on black / white on white cases */
8374 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8375 0, 0, squareSize, squareSize, 0, 0, 1);
8377 /* Copy the piece */
8382 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8384 0, 0, squareSize, squareSize,
8389 /* Animate the movement of a single piece */
8392 BeginAnimation(anim, piece, startColor, start)
8400 /* The old buffer is initialised with the start square (empty) */
8401 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8402 anim->prevFrame = *start;
8404 /* The piece will be drawn using its own bitmap as a matte */
8405 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8406 XSetClipMask(xDisplay, anim->pieceGC, mask);
8410 AnimationFrame(anim, frame, piece)
8415 XRectangle updates[4];
8420 /* Save what we are about to draw into the new buffer */
8421 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8422 frame->x, frame->y, squareSize, squareSize,
8425 /* Erase bits of the previous frame */
8426 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8427 /* Where the new frame overlapped the previous,
8428 the contents in newBuf are wrong. */
8429 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8430 overlap.x, overlap.y,
8431 overlap.width, overlap.height,
8433 /* Repaint the areas in the old that don't overlap new */
8434 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8435 for (i = 0; i < count; i++)
8436 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8437 updates[i].x - anim->prevFrame.x,
8438 updates[i].y - anim->prevFrame.y,
8439 updates[i].width, updates[i].height,
8440 updates[i].x, updates[i].y);
8442 /* Easy when no overlap */
8443 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8444 0, 0, squareSize, squareSize,
8445 anim->prevFrame.x, anim->prevFrame.y);
8448 /* Save this frame for next time round */
8449 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8450 0, 0, squareSize, squareSize,
8452 anim->prevFrame = *frame;
8454 /* Draw piece over original screen contents, not current,
8455 and copy entire rect. Wipes out overlapping piece images. */
8456 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8457 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8458 0, 0, squareSize, squareSize,
8459 frame->x, frame->y);
8463 EndAnimation (anim, finish)
8467 XRectangle updates[4];
8472 /* The main code will redraw the final square, so we
8473 only need to erase the bits that don't overlap. */
8474 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8475 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8476 for (i = 0; i < count; i++)
8477 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8478 updates[i].x - anim->prevFrame.x,
8479 updates[i].y - anim->prevFrame.y,
8480 updates[i].width, updates[i].height,
8481 updates[i].x, updates[i].y);
8483 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8484 0, 0, squareSize, squareSize,
8485 anim->prevFrame.x, anim->prevFrame.y);
8490 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8492 ChessSquare piece; int startColor;
8493 XPoint * start; XPoint * finish;
8494 XPoint frames[]; int nFrames;
8498 BeginAnimation(anim, piece, startColor, start);
8499 for (n = 0; n < nFrames; n++) {
8500 AnimationFrame(anim, &(frames[n]), piece);
8501 FrameDelay(appData.animSpeed);
8503 EndAnimation(anim, finish);
8506 /* Main control logic for deciding what to animate and how */
8509 AnimateMove(board, fromX, fromY, toX, toY)
8518 XPoint start, finish, mid;
8519 XPoint frames[kFactor * 2 + 1];
8520 int nFrames, startColor, endColor;
8522 /* Are we animating? */
8523 if (!appData.animate || appData.blindfold)
8526 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8527 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8528 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8530 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8531 piece = board[fromY][fromX];
8532 if (piece >= EmptySquare) return;
8537 hop = (piece == WhiteKnight || piece == BlackKnight);
8540 if (appData.debugMode) {
8541 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8542 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8543 piece, fromX, fromY, toX, toY); }
8545 ScreenSquare(fromX, fromY, &start, &startColor);
8546 ScreenSquare(toX, toY, &finish, &endColor);
8549 /* Knight: make diagonal movement then straight */
8550 if (abs(toY - fromY) < abs(toX - fromX)) {
8551 mid.x = start.x + (finish.x - start.x) / 2;
8555 mid.y = start.y + (finish.y - start.y) / 2;
8558 mid.x = start.x + (finish.x - start.x) / 2;
8559 mid.y = start.y + (finish.y - start.y) / 2;
8562 /* Don't use as many frames for very short moves */
8563 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8564 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8566 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8567 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8569 /* Be sure end square is redrawn */
8570 damage[toY][toX] = True;
8574 DragPieceBegin(x, y)
8577 int boardX, boardY, color;
8580 /* Are we animating? */
8581 if (!appData.animateDragging || appData.blindfold)
8584 /* Figure out which square we start in and the
8585 mouse position relative to top left corner. */
8586 BoardSquare(x, y, &boardX, &boardY);
8587 player.startBoardX = boardX;
8588 player.startBoardY = boardY;
8589 ScreenSquare(boardX, boardY, &corner, &color);
8590 player.startSquare = corner;
8591 player.startColor = color;
8592 /* As soon as we start dragging, the piece will jump slightly to
8593 be centered over the mouse pointer. */
8594 player.mouseDelta.x = squareSize/2;
8595 player.mouseDelta.y = squareSize/2;
8596 /* Initialise animation */
8597 player.dragPiece = PieceForSquare(boardX, boardY);
8599 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8600 player.dragActive = True;
8601 BeginAnimation(&player, player.dragPiece, color, &corner);
8602 /* Mark this square as needing to be redrawn. Note that
8603 we don't remove the piece though, since logically (ie
8604 as seen by opponent) the move hasn't been made yet. */
8605 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8606 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8607 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8608 corner.x, corner.y, squareSize, squareSize,
8609 0, 0); // [HGM] zh: unstack in stead of grab
8610 damage[boardY][boardX] = True;
8612 player.dragActive = False;
8622 /* Are we animating? */
8623 if (!appData.animateDragging || appData.blindfold)
8627 if (! player.dragActive)
8629 /* Move piece, maintaining same relative position
8630 of mouse within square */
8631 corner.x = x - player.mouseDelta.x;
8632 corner.y = y - player.mouseDelta.y;
8633 AnimationFrame(&player, &corner, player.dragPiece);
8635 if (appData.highlightDragging) {
8637 BoardSquare(x, y, &boardX, &boardY);
8638 SetHighlights(fromX, fromY, boardX, boardY);
8647 int boardX, boardY, color;
8650 /* Are we animating? */
8651 if (!appData.animateDragging || appData.blindfold)
8655 if (! player.dragActive)
8657 /* Last frame in sequence is square piece is
8658 placed on, which may not match mouse exactly. */
8659 BoardSquare(x, y, &boardX, &boardY);
8660 ScreenSquare(boardX, boardY, &corner, &color);
8661 EndAnimation(&player, &corner);
8663 /* Be sure end square is redrawn */
8664 damage[boardY][boardX] = True;
8666 /* This prevents weird things happening with fast successive
8667 clicks which on my Sun at least can cause motion events
8668 without corresponding press/release. */
8669 player.dragActive = False;
8672 /* Handle expose event while piece being dragged */
8677 if (!player.dragActive || appData.blindfold)
8680 /* What we're doing: logically, the move hasn't been made yet,
8681 so the piece is still in it's original square. But visually
8682 it's being dragged around the board. So we erase the square
8683 that the piece is on and draw it at the last known drag point. */
8684 BlankSquare(player.startSquare.x, player.startSquare.y,
8685 player.startColor, EmptySquare, xBoardWindow);
8686 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8687 damage[player.startBoardY][player.startBoardX] = TRUE;
8690 #include <sys/ioctl.h>
8691 int get_term_width()
8693 int fd, default_width;
8696 default_width = 79; // this is FICS default anyway...
8698 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8700 if (!ioctl(fd, TIOCGSIZE, &win))
8701 default_width = win.ts_cols;
8702 #elif defined(TIOCGWINSZ)
8704 if (!ioctl(fd, TIOCGWINSZ, &win))
8705 default_width = win.ws_col;
8707 return default_width;
8710 void update_ics_width()
8712 static int old_width = 0;
8713 int new_width = get_term_width();
8715 if (old_width != new_width)
8716 ics_printf("set width %d\n", new_width);
8717 old_width = new_width;
8720 void NotifyFrontendLogin()