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. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 RETSIGTYPE CmailSigHandler P((int sig));
237 RETSIGTYPE IntSigHandler P((int sig));
238 RETSIGTYPE TermSizeSigHandler P((int sig));
239 void CreateGCs P((void));
240 void CreateXIMPieces P((void));
241 void CreateXPMPieces P((void));
242 void CreatePieces P((void));
243 void CreatePieceMenus P((void));
244 Widget CreateMenuBar P((Menu *mb));
245 Widget CreateButtonBar P ((MenuItem *mi));
246 char *FindFont P((char *pattern, int targetPxlSize));
247 void PieceMenuPopup P((Widget w, XEvent *event,
248 String *params, Cardinal *num_params));
249 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
250 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
251 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
252 u_int wreq, u_int hreq));
253 void CreateGrid P((void));
254 int EventToSquare P((int x, int limit));
255 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
256 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
257 void HandleUserMove P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void AnimateUserMove P((Widget w, XEvent * event,
260 String * params, Cardinal * nParams));
261 void HandlePV P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void WhiteClock P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void BlackClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void DrawPositionProc P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
271 void CommentPopUp P((char *title, char *label));
272 void CommentPopDown P((void));
273 void CommentCallback P((Widget w, XtPointer client_data,
274 XtPointer call_data));
275 void ICSInputBoxPopUp P((void));
276 void ICSInputBoxPopDown P((void));
277 void FileNamePopUp P((char *label, char *def,
278 FileProc proc, char *openMode));
279 void FileNamePopDown P((void));
280 void FileNameCallback P((Widget w, XtPointer client_data,
281 XtPointer call_data));
282 void FileNameAction P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionReplyAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionProc P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionPopDown P((void));
289 void PromotionPopDown P((void));
290 void PromotionCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void EditCommentPopDown P((void));
293 void EditCommentCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
296 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
297 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
298 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
302 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
304 void LoadPositionProc P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
310 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
314 void PastePositionProc P((Widget w, XEvent *event, String *prms,
316 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void SavePositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
324 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
328 void MachineWhiteProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void AnalyzeModeProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeFileProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
336 void IcsClientProc P((Widget w, XEvent *event, String *prms,
338 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void EditPositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void EditCommentProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void IcsInputBoxProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void StopObservingProc P((Widget w, XEvent *event, String *prms,
360 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
362 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
369 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
371 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
374 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
376 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
378 void AutocommProc P((Widget w, XEvent *event, String *prms,
380 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AutobsProc P((Widget w, XEvent *event, String *prms,
384 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
389 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
392 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
394 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
396 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
400 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
402 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
404 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
406 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
408 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
412 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
414 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
416 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
418 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void DisplayMove P((int moveNumber));
430 void DisplayTitle P((char *title));
431 void ICSInitScript P((void));
432 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
433 void ErrorPopUp P((char *title, char *text, int modal));
434 void ErrorPopDown P((void));
435 static char *ExpandPathName P((char *path));
436 static void CreateAnimVars P((void));
437 static void DragPieceMove P((int x, int y));
438 static void DrawDragPiece P((void));
439 char *ModeToWidgetName P((GameMode mode));
440 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void ShufflePopDown P(());
448 void EnginePopDown P(());
449 void UciPopDown P(());
450 void TimeControlPopDown P(());
451 void NewVariantPopDown P(());
452 void SettingsPopDown P(());
453 void update_ics_width P(());
454 int get_term_width P(());
455 int CopyMemoProc P(());
457 * XBoard depends on Xt R4 or higher
459 int xtVersion = XtSpecificationRelease;
464 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
465 jailSquareColor, highlightSquareColor, premoveHighlightColor;
466 Pixel lowTimeWarningColor;
467 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
468 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
469 wjPieceGC, bjPieceGC, prelineGC, countGC;
470 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
471 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
472 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
473 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
474 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
475 ICSInputShell, fileNameShell, askQuestionShell;
476 Widget historyShell, evalGraphShell, gameListShell;
477 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
478 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
479 Font clockFontID, coordFontID, countFontID;
480 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
481 XtAppContext appContext;
483 char *oldICSInteractionTitle;
487 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
489 Position commentX = -1, commentY = -1;
490 Dimension commentW, commentH;
491 typedef unsigned int BoardSize;
493 Boolean chessProgram;
495 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
496 int squareSize, smallLayout = 0, tinyLayout = 0,
497 marginW, marginH, // [HGM] for run-time resizing
498 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
499 ICSInputBoxUp = False, askQuestionUp = False,
500 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
501 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
502 Pixel timerForegroundPixel, timerBackgroundPixel;
503 Pixel buttonForegroundPixel, buttonBackgroundPixel;
504 char *chessDir, *programName, *programVersion,
505 *gameCopyFilename, *gamePasteFilename;
506 Boolean alwaysOnTop = False;
507 Boolean saveSettingsOnExit;
508 char *settingsFileName;
509 char *icsTextMenuString;
511 char *firstChessProgramNames;
512 char *secondChessProgramNames;
514 WindowPlacement wpMain;
515 WindowPlacement wpConsole;
516 WindowPlacement wpComment;
517 WindowPlacement wpMoveHistory;
518 WindowPlacement wpEvalGraph;
519 WindowPlacement wpEngineOutput;
520 WindowPlacement wpGameList;
521 WindowPlacement wpTags;
525 Pixmap pieceBitmap[2][(int)BlackPawn];
526 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
527 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
528 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
529 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
530 int useImages, useImageSqs;
531 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
532 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
533 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
534 XImage *ximLightSquare, *ximDarkSquare;
537 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
538 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
540 #define White(piece) ((int)(piece) < (int)BlackPawn)
542 /* Variables for doing smooth animation. This whole thing
543 would be much easier if the board was double-buffered,
544 but that would require a fairly major rewrite. */
549 GC blitGC, pieceGC, outlineGC;
550 XPoint startSquare, prevFrame, mouseDelta;
554 int startBoardX, startBoardY;
557 /* There can be two pieces being animated at once: a player
558 can begin dragging a piece before the remote opponent has moved. */
560 static AnimState game, player;
562 /* Bitmaps for use as masks when drawing XPM pieces.
563 Need one for each black and white piece. */
564 static Pixmap xpmMask[BlackKing + 1];
566 /* This magic number is the number of intermediate frames used
567 in each half of the animation. For short moves it's reduced
568 by 1. The total number of frames will be factor * 2 + 1. */
571 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
573 MenuItem fileMenu[] = {
574 {N_("New Game"), ResetProc},
575 {N_("New Shuffle Game ..."), ShuffleMenuProc},
576 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
577 {"----", NothingProc},
578 {N_("Load Game"), LoadGameProc},
579 {N_("Load Next Game"), LoadNextGameProc},
580 {N_("Load Previous Game"), LoadPrevGameProc},
581 {N_("Reload Same Game"), ReloadGameProc},
582 {N_("Save Game"), SaveGameProc},
583 {"----", NothingProc},
584 {N_("Copy Game"), CopyGameProc},
585 {N_("Paste Game"), PasteGameProc},
586 {"----", NothingProc},
587 {N_("Load Position"), LoadPositionProc},
588 {N_("Load Next Position"), LoadNextPositionProc},
589 {N_("Load Previous Position"), LoadPrevPositionProc},
590 {N_("Reload Same Position"), ReloadPositionProc},
591 {N_("Save Position"), SavePositionProc},
592 {"----", NothingProc},
593 {N_("Copy Position"), CopyPositionProc},
594 {N_("Paste Position"), PastePositionProc},
595 {"----", NothingProc},
596 {N_("Mail Move"), MailMoveProc},
597 {N_("Reload CMail Message"), ReloadCmailMsgProc},
598 {"----", NothingProc},
599 {N_("Exit"), QuitProc},
603 MenuItem modeMenu[] = {
604 {N_("Machine White"), MachineWhiteProc},
605 {N_("Machine Black"), MachineBlackProc},
606 {N_("Two Machines"), TwoMachinesProc},
607 {N_("Analysis Mode"), AnalyzeModeProc},
608 {N_("Analyze File"), AnalyzeFileProc },
609 {N_("ICS Client"), IcsClientProc},
610 {N_("Edit Game"), EditGameProc},
611 {N_("Edit Position"), EditPositionProc},
612 {N_("Training"), TrainingProc},
613 {"----", NothingProc},
614 {N_("Show Engine Output"), EngineOutputProc},
615 {N_("Show Evaluation Graph"), EvalGraphProc},
616 {N_("Show Game List"), ShowGameListProc},
617 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
618 {"----", NothingProc},
619 {N_("Edit Tags"), EditTagsProc},
620 {N_("Edit Comment"), EditCommentProc},
621 {N_("ICS Input Box"), IcsInputBoxProc},
622 {N_("Pause"), PauseProc},
626 MenuItem actionMenu[] = {
627 {N_("Accept"), AcceptProc},
628 {N_("Decline"), DeclineProc},
629 {N_("Rematch"), RematchProc},
630 {"----", NothingProc},
631 {N_("Call Flag"), CallFlagProc},
632 {N_("Draw"), DrawProc},
633 {N_("Adjourn"), AdjournProc},
634 {N_("Abort"), AbortProc},
635 {N_("Resign"), ResignProc},
636 {"----", NothingProc},
637 {N_("Stop Observing"), StopObservingProc},
638 {N_("Stop Examining"), StopExaminingProc},
639 {"----", NothingProc},
640 {N_("Adjudicate to White"), AdjuWhiteProc},
641 {N_("Adjudicate to Black"), AdjuBlackProc},
642 {N_("Adjudicate Draw"), AdjuDrawProc},
646 MenuItem stepMenu[] = {
647 {N_("Backward"), BackwardProc},
648 {N_("Forward"), ForwardProc},
649 {N_("Back to Start"), ToStartProc},
650 {N_("Forward to End"), ToEndProc},
651 {N_("Revert"), RevertProc},
652 {N_("Truncate Game"), TruncateGameProc},
653 {"----", NothingProc},
654 {N_("Move Now"), MoveNowProc},
655 {N_("Retract Move"), RetractMoveProc},
659 MenuItem optionsMenu[] = {
660 {N_("Flip View"), FlipViewProc},
661 {"----", NothingProc},
662 {N_("Adjudications ..."), EngineMenuProc},
663 {N_("General Settings ..."), UciMenuProc},
664 {N_("Engine #1 Settings ..."), FirstSettingsProc},
665 {N_("Engine #2 Settings ..."), SecondSettingsProc},
666 {N_("Time Control ..."), TimeControlProc},
667 {"----", NothingProc},
668 {N_("Always Queen"), AlwaysQueenProc},
669 {N_("Animate Dragging"), AnimateDraggingProc},
670 {N_("Animate Moving"), AnimateMovingProc},
671 {N_("Auto Comment"), AutocommProc},
672 {N_("Auto Flag"), AutoflagProc},
673 {N_("Auto Flip View"), AutoflipProc},
674 {N_("Auto Observe"), AutobsProc},
675 {N_("Auto Raise Board"), AutoraiseProc},
676 {N_("Auto Save"), AutosaveProc},
677 {N_("Blindfold"), BlindfoldProc},
678 {N_("Flash Moves"), FlashMovesProc},
679 {N_("Get Move List"), GetMoveListProc},
681 {N_("Highlight Dragging"), HighlightDraggingProc},
683 {N_("Highlight Last Move"), HighlightLastMoveProc},
684 {N_("Move Sound"), MoveSoundProc},
685 {N_("ICS Alarm"), IcsAlarmProc},
686 {N_("Old Save Style"), OldSaveStyleProc},
687 {N_("Periodic Updates"), PeriodicUpdatesProc},
688 {N_("Ponder Next Move"), PonderNextMoveProc},
689 {N_("Popup Exit Message"), PopupExitMessageProc},
690 {N_("Popup Move Errors"), PopupMoveErrorsProc},
691 {N_("Premove"), PremoveProc},
692 {N_("Quiet Play"), QuietPlayProc},
693 {N_("Show Coords"), ShowCoordsProc},
694 {N_("Hide Thinking"), HideThinkingProc},
695 {N_("Test Legality"), TestLegalityProc},
696 {"----", NothingProc},
697 {N_("Save Settings Now"), SaveSettingsProc},
698 {N_("Save Settings on Exit"), SaveOnExitProc},
702 MenuItem helpMenu[] = {
703 {N_("Info XBoard"), InfoProc},
704 {N_("Man XBoard"), ManProc},
705 {"----", NothingProc},
706 {N_("Hint"), HintProc},
707 {N_("Book"), BookProc},
708 {"----", NothingProc},
709 {N_("About XBoard"), AboutProc},
714 {N_("File"), fileMenu},
715 {N_("Mode"), modeMenu},
716 {N_("Action"), actionMenu},
717 {N_("Step"), stepMenu},
718 {N_("Options"), optionsMenu},
719 {N_("Help"), helpMenu},
723 #define PAUSE_BUTTON N_("P")
724 MenuItem buttonBar[] = {
727 {PAUSE_BUTTON, PauseProc},
733 #define PIECE_MENU_SIZE 18
734 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
735 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
736 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
737 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
738 N_("Empty square"), N_("Clear board") },
739 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
740 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
741 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
742 N_("Empty square"), N_("Clear board") }
744 /* must be in same order as PieceMenuStrings! */
745 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
746 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
747 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
748 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
749 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
750 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
751 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
752 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
753 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
756 #define DROP_MENU_SIZE 6
757 String dropMenuStrings[DROP_MENU_SIZE] = {
758 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
760 /* must be in same order as PieceMenuStrings! */
761 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
762 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
763 WhiteRook, WhiteQueen
771 DropMenuEnables dmEnables[] = {
789 { XtNborderWidth, 0 },
790 { XtNdefaultDistance, 0 },
794 { XtNborderWidth, 0 },
795 { XtNresizable, (XtArgVal) True },
799 { XtNborderWidth, 0 },
805 { XtNjustify, (XtArgVal) XtJustifyRight },
806 { XtNlabel, (XtArgVal) "..." },
807 { XtNresizable, (XtArgVal) True },
808 { XtNresize, (XtArgVal) False }
811 Arg messageArgs[] = {
812 { XtNjustify, (XtArgVal) XtJustifyLeft },
813 { XtNlabel, (XtArgVal) "..." },
814 { XtNresizable, (XtArgVal) True },
815 { XtNresize, (XtArgVal) False }
819 { XtNborderWidth, 0 },
820 { XtNjustify, (XtArgVal) XtJustifyLeft }
823 XtResource clientResources[] = {
824 { "flashCount", "flashCount", XtRInt, sizeof(int),
825 XtOffset(AppDataPtr, flashCount), XtRImmediate,
826 (XtPointer) FLASH_COUNT },
829 XrmOptionDescRec shellOptions[] = {
830 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
831 { "-flash", "flashCount", XrmoptionNoArg, "3" },
832 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
835 XtActionsRec boardActions[] = {
836 { "DrawPosition", DrawPositionProc },
837 { "HandleUserMove", HandleUserMove },
838 { "AnimateUserMove", AnimateUserMove },
839 { "HandlePV", HandlePV },
840 { "UnLoadPV", UnLoadPV },
841 { "FileNameAction", FileNameAction },
842 { "AskQuestionProc", AskQuestionProc },
843 { "AskQuestionReplyAction", AskQuestionReplyAction },
844 { "PieceMenuPopup", PieceMenuPopup },
845 { "WhiteClock", WhiteClock },
846 { "BlackClock", BlackClock },
847 { "Iconify", Iconify },
848 { "ResetProc", ResetProc },
849 { "LoadGameProc", LoadGameProc },
850 { "LoadNextGameProc", LoadNextGameProc },
851 { "LoadPrevGameProc", LoadPrevGameProc },
852 { "LoadSelectedProc", LoadSelectedProc },
853 { "SetFilterProc", SetFilterProc },
854 { "ReloadGameProc", ReloadGameProc },
855 { "LoadPositionProc", LoadPositionProc },
856 { "LoadNextPositionProc", LoadNextPositionProc },
857 { "LoadPrevPositionProc", LoadPrevPositionProc },
858 { "ReloadPositionProc", ReloadPositionProc },
859 { "CopyPositionProc", CopyPositionProc },
860 { "PastePositionProc", PastePositionProc },
861 { "CopyGameProc", CopyGameProc },
862 { "PasteGameProc", PasteGameProc },
863 { "SaveGameProc", SaveGameProc },
864 { "SavePositionProc", SavePositionProc },
865 { "MailMoveProc", MailMoveProc },
866 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
867 { "QuitProc", QuitProc },
868 { "MachineWhiteProc", MachineWhiteProc },
869 { "MachineBlackProc", MachineBlackProc },
870 { "AnalysisModeProc", AnalyzeModeProc },
871 { "AnalyzeFileProc", AnalyzeFileProc },
872 { "TwoMachinesProc", TwoMachinesProc },
873 { "IcsClientProc", IcsClientProc },
874 { "EditGameProc", EditGameProc },
875 { "EditPositionProc", EditPositionProc },
876 { "TrainingProc", EditPositionProc },
877 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
878 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
879 { "ShowGameListProc", ShowGameListProc },
880 { "ShowMoveListProc", HistoryShowProc},
881 { "EditTagsProc", EditCommentProc },
882 { "EditCommentProc", EditCommentProc },
883 { "IcsAlarmProc", IcsAlarmProc },
884 { "IcsInputBoxProc", IcsInputBoxProc },
885 { "PauseProc", PauseProc },
886 { "AcceptProc", AcceptProc },
887 { "DeclineProc", DeclineProc },
888 { "RematchProc", RematchProc },
889 { "CallFlagProc", CallFlagProc },
890 { "DrawProc", DrawProc },
891 { "AdjournProc", AdjournProc },
892 { "AbortProc", AbortProc },
893 { "ResignProc", ResignProc },
894 { "AdjuWhiteProc", AdjuWhiteProc },
895 { "AdjuBlackProc", AdjuBlackProc },
896 { "AdjuDrawProc", AdjuDrawProc },
897 { "EnterKeyProc", EnterKeyProc },
898 { "StopObservingProc", StopObservingProc },
899 { "StopExaminingProc", StopExaminingProc },
900 { "BackwardProc", BackwardProc },
901 { "ForwardProc", ForwardProc },
902 { "ToStartProc", ToStartProc },
903 { "ToEndProc", ToEndProc },
904 { "RevertProc", RevertProc },
905 { "TruncateGameProc", TruncateGameProc },
906 { "MoveNowProc", MoveNowProc },
907 { "RetractMoveProc", RetractMoveProc },
908 { "AlwaysQueenProc", AlwaysQueenProc },
909 { "AnimateDraggingProc", AnimateDraggingProc },
910 { "AnimateMovingProc", AnimateMovingProc },
911 { "AutoflagProc", AutoflagProc },
912 { "AutoflipProc", AutoflipProc },
913 { "AutobsProc", AutobsProc },
914 { "AutoraiseProc", AutoraiseProc },
915 { "AutosaveProc", AutosaveProc },
916 { "BlindfoldProc", BlindfoldProc },
917 { "FlashMovesProc", FlashMovesProc },
918 { "FlipViewProc", FlipViewProc },
919 { "GetMoveListProc", GetMoveListProc },
921 { "HighlightDraggingProc", HighlightDraggingProc },
923 { "HighlightLastMoveProc", HighlightLastMoveProc },
924 { "IcsAlarmProc", IcsAlarmProc },
925 { "MoveSoundProc", MoveSoundProc },
926 { "OldSaveStyleProc", OldSaveStyleProc },
927 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
928 { "PonderNextMoveProc", PonderNextMoveProc },
929 { "PopupExitMessageProc", PopupExitMessageProc },
930 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
931 { "PremoveProc", PremoveProc },
932 { "QuietPlayProc", QuietPlayProc },
933 { "ShowCoordsProc", ShowCoordsProc },
934 { "ShowThinkingProc", ShowThinkingProc },
935 { "HideThinkingProc", HideThinkingProc },
936 { "TestLegalityProc", TestLegalityProc },
937 { "SaveSettingsProc", SaveSettingsProc },
938 { "SaveOnExitProc", SaveOnExitProc },
939 { "InfoProc", InfoProc },
940 { "ManProc", ManProc },
941 { "HintProc", HintProc },
942 { "BookProc", BookProc },
943 { "AboutGameProc", AboutGameProc },
944 { "AboutProc", AboutProc },
945 { "DebugProc", DebugProc },
946 { "NothingProc", NothingProc },
947 { "CommentPopDown", (XtActionProc) CommentPopDown },
948 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
949 { "TagsPopDown", (XtActionProc) TagsPopDown },
950 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
951 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
952 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
953 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
954 { "GameListPopDown", (XtActionProc) GameListPopDown },
955 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
956 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
957 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
958 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
959 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
960 { "EnginePopDown", (XtActionProc) EnginePopDown },
961 { "UciPopDown", (XtActionProc) UciPopDown },
962 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
963 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
964 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
965 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
968 char globalTranslations[] =
969 ":<Key>R: ResignProc() \n \
970 :<Key>r: ResetProc() \n \
971 :<Key>g: LoadGameProc() \n \
972 :<Key>N: LoadNextGameProc() \n \
973 :<Key>P: LoadPrevGameProc() \n \
974 :<Key>Q: QuitProc() \n \
975 :<Key>F: ToEndProc() \n \
976 :<Key>f: ForwardProc() \n \
977 :<Key>B: ToStartProc() \n \
978 :<Key>b: BackwardProc() \n \
979 :<Key>p: PauseProc() \n \
980 :<Key>d: DrawProc() \n \
981 :<Key>t: CallFlagProc() \n \
982 :<Key>i: Iconify() \n \
983 :<Key>c: Iconify() \n \
984 :<Key>v: FlipViewProc() \n \
985 <KeyDown>Control_L: BackwardProc() \n \
986 <KeyUp>Control_L: ForwardProc() \n \
987 <KeyDown>Control_R: BackwardProc() \n \
988 <KeyUp>Control_R: ForwardProc() \n \
989 Shift<Key>1: AskQuestionProc(\"Direct command\",\
990 \"Send to chess program:\",,1) \n \
991 Shift<Key>2: AskQuestionProc(\"Direct command\",\
992 \"Send to second chess program:\",,2) \n";
994 char boardTranslations[] =
995 "<Btn1Down>: HandleUserMove() \n \
996 <Btn1Up>: HandleUserMove() \n \
997 <Btn1Motion>: AnimateUserMove() \n \
998 <Btn3Motion>: HandlePV() \n \
999 <Btn3Up>: UnLoadPV() \n \
1000 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1001 PieceMenuPopup(menuB) \n \
1002 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1003 PieceMenuPopup(menuW) \n \
1004 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1005 PieceMenuPopup(menuW) \n \
1006 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1007 PieceMenuPopup(menuB) \n";
1009 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1010 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1012 char ICSInputTranslations[] =
1013 "<Key>Return: EnterKeyProc() \n";
1015 String xboardResources[] = {
1016 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1017 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1018 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1023 /* Max possible square size */
1024 #define MAXSQSIZE 256
1026 static int xpm_avail[MAXSQSIZE];
1028 #ifdef HAVE_DIR_STRUCT
1030 /* Extract piece size from filename */
1032 xpm_getsize(name, len, ext)
1043 if ((p=strchr(name, '.')) == NULL ||
1044 StrCaseCmp(p+1, ext) != 0)
1050 while (*p && isdigit(*p))
1057 /* Setup xpm_avail */
1059 xpm_getavail(dirname, ext)
1067 for (i=0; i<MAXSQSIZE; ++i)
1070 if (appData.debugMode)
1071 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1073 dir = opendir(dirname);
1076 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1077 programName, dirname);
1081 while ((ent=readdir(dir)) != NULL) {
1082 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1083 if (i > 0 && i < MAXSQSIZE)
1093 xpm_print_avail(fp, ext)
1099 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1100 for (i=1; i<MAXSQSIZE; ++i) {
1106 /* Return XPM piecesize closest to size */
1108 xpm_closest_to(dirname, size, ext)
1114 int sm_diff = MAXSQSIZE;
1118 xpm_getavail(dirname, ext);
1120 if (appData.debugMode)
1121 xpm_print_avail(stderr, ext);
1123 for (i=1; i<MAXSQSIZE; ++i) {
1126 diff = (diff<0) ? -diff : diff;
1127 if (diff < sm_diff) {
1135 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1141 #else /* !HAVE_DIR_STRUCT */
1142 /* If we are on a system without a DIR struct, we can't
1143 read the directory, so we can't collect a list of
1144 filenames, etc., so we can't do any size-fitting. */
1146 xpm_closest_to(dirname, size, ext)
1151 fprintf(stderr, _("\
1152 Warning: No DIR structure found on this system --\n\
1153 Unable to autosize for XPM/XIM pieces.\n\
1154 Please report this error to frankm@hiwaay.net.\n\
1155 Include system type & operating system in message.\n"));
1158 #endif /* HAVE_DIR_STRUCT */
1160 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1161 "magenta", "cyan", "white" };
1165 TextColors textColors[(int)NColorClasses];
1167 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1169 parse_color(str, which)
1173 char *p, buf[100], *d;
1176 if (strlen(str) > 99) /* watch bounds on buf */
1181 for (i=0; i<which; ++i) {
1188 /* Could be looking at something like:
1190 .. in which case we want to stop on a comma also */
1191 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1195 return -1; /* Use default for empty field */
1198 if (which == 2 || isdigit(*p))
1201 while (*p && isalpha(*p))
1206 for (i=0; i<8; ++i) {
1207 if (!StrCaseCmp(buf, cnames[i]))
1208 return which? (i+40) : (i+30);
1210 if (!StrCaseCmp(buf, "default")) return -1;
1212 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1217 parse_cpair(cc, str)
1221 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1222 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1227 /* bg and attr are optional */
1228 textColors[(int)cc].bg = parse_color(str, 1);
1229 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1230 textColors[(int)cc].attr = 0;
1236 /* Arrange to catch delete-window events */
1237 Atom wm_delete_window;
1239 CatchDeleteWindow(Widget w, String procname)
1242 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1243 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1244 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1251 XtSetArg(args[0], XtNiconic, False);
1252 XtSetValues(shellWidget, args, 1);
1254 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1257 //---------------------------------------------------------------------------------------------------------
1258 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1261 #define CW_USEDEFAULT (1<<31)
1262 #define ICS_TEXT_MENU_SIZE 90
1263 #define DEBUG_FILE "xboard.debug"
1264 #define SetCurrentDirectory chdir
1265 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1269 // these two must some day move to frontend.h, when they are implemented
1270 Boolean GameListIsUp();
1272 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1275 // front-end part of option handling
1277 // [HGM] This platform-dependent table provides the location for storing the color info
1278 extern char *crWhite, * crBlack;
1282 &appData.whitePieceColor,
1283 &appData.blackPieceColor,
1284 &appData.lightSquareColor,
1285 &appData.darkSquareColor,
1286 &appData.highlightSquareColor,
1287 &appData.premoveHighlightColor,
1288 &appData.lowTimeWarningColor,
1299 // [HGM] font: keep a font for each square size, even non-stndard ones
1300 #define NUM_SIZES 18
1301 #define MAX_SIZE 130
1302 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1303 char *fontTable[NUM_FONTS][MAX_SIZE];
1306 ParseFont(char *name, int number)
1307 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1309 if(sscanf(name, "size%d:", &size)) {
1310 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1311 // defer processing it until we know if it matches our board size
1312 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1313 fontTable[number][size] = strdup(strchr(name, ':')+1);
1314 fontValid[number][size] = True;
1319 case 0: // CLOCK_FONT
1320 appData.clockFont = strdup(name);
1322 case 1: // MESSAGE_FONT
1323 appData.font = strdup(name);
1325 case 2: // COORD_FONT
1326 appData.coordFont = strdup(name);
1331 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1336 { // only 2 fonts currently
1337 appData.clockFont = CLOCK_FONT_NAME;
1338 appData.coordFont = COORD_FONT_NAME;
1339 appData.font = DEFAULT_FONT_NAME;
1344 { // no-op, until we identify the code for this already in XBoard and move it here
1348 ParseColor(int n, char *name)
1349 { // in XBoard, just copy the color-name string
1350 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1354 ParseTextAttribs(ColorClass cc, char *s)
1356 (&appData.colorShout)[cc] = strdup(s);
1360 ParseBoardSize(void *addr, char *name)
1362 appData.boardSize = strdup(name);
1367 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1371 SetCommPortDefaults()
1372 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1375 // [HGM] args: these three cases taken out to stay in front-end
1377 SaveFontArg(FILE *f, ArgDescriptor *ad)
1379 char *name, buf[MSG_SIZ];
1380 int i, n = (int)ad->argLoc;
1382 case 0: // CLOCK_FONT
1383 name = appData.clockFont;
1385 case 1: // MESSAGE_FONT
1386 name = appData.font;
1388 case 2: // COORD_FONT
1389 name = appData.coordFont;
1394 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1395 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1396 fontTable[n][squareSize] = strdup(name);
1397 fontValid[n][squareSize] = True;
1400 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1401 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1406 { // nothing to do, as the sounds are at all times represented by their text-string names already
1410 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1411 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1412 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1416 SaveColor(FILE *f, ArgDescriptor *ad)
1417 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1418 if(colorVariable[(int)ad->argLoc])
1419 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1423 SaveBoardSize(FILE *f, char *name, void *addr)
1424 { // wrapper to shield back-end from BoardSize & sizeInfo
1425 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1429 ParseCommPortSettings(char *s)
1430 { // no such option in XBoard (yet)
1433 extern Widget engineOutputShell;
1434 extern Widget tagsShell, editTagsShell;
1436 GetActualPlacement(Widget wg, WindowPlacement *wp)
1446 XtSetArg(args[i], XtNx, &x); i++;
1447 XtSetArg(args[i], XtNy, &y); i++;
1448 XtSetArg(args[i], XtNwidth, &w); i++;
1449 XtSetArg(args[i], XtNheight, &h); i++;
1450 XtGetValues(wg, args, i);
1459 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1460 // In XBoard this will have to wait until awareness of window parameters is implemented
1461 GetActualPlacement(shellWidget, &wpMain);
1462 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1463 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1464 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1465 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1466 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1467 else GetActualPlacement(editShell, &wpComment);
1468 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1469 else GetActualPlacement(editTagsShell, &wpTags);
1473 PrintCommPortSettings(FILE *f, char *name)
1474 { // This option does not exist in XBoard
1478 MySearchPath(char *installDir, char *name, char *fullname)
1479 { // just append installDir and name. Perhaps ExpandPath should be used here?
1480 name = ExpandPathName(name);
1481 if(name && name[0] == '/') strcpy(fullname, name); else {
1482 sprintf(fullname, "%s%c%s", installDir, '/', name);
1488 MyGetFullPathName(char *name, char *fullname)
1489 { // should use ExpandPath?
1490 name = ExpandPathName(name);
1491 strcpy(fullname, name);
1496 EnsureOnScreen(int *x, int *y, int minX, int minY)
1503 { // [HGM] args: allows testing if main window is realized from back-end
1504 return xBoardWindow != 0;
1508 PopUpStartupDialog()
1509 { // start menu not implemented in XBoard
1512 ConvertToLine(int argc, char **argv)
1514 static char line[128*1024], buf[1024];
1518 for(i=1; i<argc; i++) {
1519 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1520 && argv[i][0] != '{' )
1521 sprintf(buf, "{%s} ", argv[i]);
1522 else sprintf(buf, "%s ", argv[i]);
1525 line[strlen(line)-1] = NULLCHAR;
1529 //--------------------------------------------------------------------------------------------
1532 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1534 #define BoardSize int
1535 void InitDrawingSizes(BoardSize boardSize, int flags)
1536 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1537 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1539 XtGeometryResult gres;
1542 if(!formWidget) return;
1545 * Enable shell resizing.
1547 shellArgs[0].value = (XtArgVal) &w;
1548 shellArgs[1].value = (XtArgVal) &h;
1549 XtGetValues(shellWidget, shellArgs, 2);
1551 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1552 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1553 XtSetValues(shellWidget, &shellArgs[2], 4);
1555 XtSetArg(args[0], XtNdefaultDistance, &sep);
1556 XtGetValues(formWidget, args, 1);
1558 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1559 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1562 XtSetArg(args[0], XtNwidth, boardWidth);
1563 XtSetArg(args[1], XtNheight, boardHeight);
1564 XtSetValues(boardWidget, args, 2);
1566 timerWidth = (boardWidth - sep) / 2;
1567 XtSetArg(args[0], XtNwidth, timerWidth);
1568 XtSetValues(whiteTimerWidget, args, 1);
1569 XtSetValues(blackTimerWidget, args, 1);
1571 XawFormDoLayout(formWidget, False);
1573 if (appData.titleInWindow) {
1575 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1576 XtSetArg(args[i], XtNheight, &h); i++;
1577 XtGetValues(titleWidget, args, i);
1579 w = boardWidth - 2*bor;
1581 XtSetArg(args[0], XtNwidth, &w);
1582 XtGetValues(menuBarWidget, args, 1);
1583 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1586 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1587 if (gres != XtGeometryYes && appData.debugMode) {
1589 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1590 programName, gres, w, h, wr, hr);
1594 XawFormDoLayout(formWidget, True);
1597 * Inhibit shell resizing.
1599 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1600 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1601 shellArgs[4].value = shellArgs[2].value = w;
1602 shellArgs[5].value = shellArgs[3].value = h;
1603 XtSetValues(shellWidget, &shellArgs[0], 6);
1605 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1608 for(i=0; i<4; i++) {
1610 for(p=0; p<=(int)WhiteKing; p++)
1611 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1612 if(gameInfo.variant == VariantShogi) {
1613 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1614 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1615 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1616 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1617 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1620 if(gameInfo.variant == VariantGothic) {
1621 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1625 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1626 for(p=0; p<=(int)WhiteKing; p++)
1627 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1628 if(gameInfo.variant == VariantShogi) {
1629 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1630 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1631 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1632 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1633 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1636 if(gameInfo.variant == VariantGothic) {
1637 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1643 for(i=0; i<2; i++) {
1645 for(p=0; p<=(int)WhiteKing; p++)
1646 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1647 if(gameInfo.variant == VariantShogi) {
1648 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1649 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1650 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1651 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1652 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1655 if(gameInfo.variant == VariantGothic) {
1656 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1667 void EscapeExpand(char *p, char *q)
1668 { // [HGM] initstring: routine to shape up string arguments
1669 while(*p++ = *q++) if(p[-1] == '\\')
1671 case 'n': p[-1] = '\n'; break;
1672 case 'r': p[-1] = '\r'; break;
1673 case 't': p[-1] = '\t'; break;
1674 case '\\': p[-1] = '\\'; break;
1675 case 0: *p = 0; return;
1676 default: p[-1] = q[-1]; break;
1685 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1686 XSetWindowAttributes window_attributes;
1688 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1689 XrmValue vFrom, vTo;
1690 XtGeometryResult gres;
1693 int forceMono = False;
1695 srandom(time(0)); // [HGM] book: make random truly random
1697 setbuf(stdout, NULL);
1698 setbuf(stderr, NULL);
1701 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1702 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1706 programName = strrchr(argv[0], '/');
1707 if (programName == NULL)
1708 programName = argv[0];
1713 XtSetLanguageProc(NULL, NULL, NULL);
1714 bindtextdomain(PACKAGE, LOCALEDIR);
1715 textdomain(PACKAGE);
1719 XtAppInitialize(&appContext, "XBoard", shellOptions,
1720 XtNumber(shellOptions),
1721 &argc, argv, xboardResources, NULL, 0);
1722 appData.boardSize = "";
1723 InitAppData(ConvertToLine(argc, argv));
1725 if (p == NULL) p = "/tmp";
1726 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1727 gameCopyFilename = (char*) malloc(i);
1728 gamePasteFilename = (char*) malloc(i);
1729 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1730 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1732 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1733 clientResources, XtNumber(clientResources),
1736 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1737 static char buf[MSG_SIZ];
1738 EscapeExpand(buf, appData.initString);
1739 appData.initString = strdup(buf);
1740 EscapeExpand(buf, appData.secondInitString);
1741 appData.secondInitString = strdup(buf);
1742 EscapeExpand(buf, appData.firstComputerString);
1743 appData.firstComputerString = strdup(buf);
1744 EscapeExpand(buf, appData.secondComputerString);
1745 appData.secondComputerString = strdup(buf);
1748 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1751 if (chdir(chessDir) != 0) {
1752 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1758 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1759 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1760 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1761 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1764 setbuf(debugFP, NULL);
1767 /* [HGM,HR] make sure board size is acceptable */
1768 if(appData.NrFiles > BOARD_FILES ||
1769 appData.NrRanks > BOARD_RANKS )
1770 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1773 /* This feature does not work; animation needs a rewrite */
1774 appData.highlightDragging = FALSE;
1778 xDisplay = XtDisplay(shellWidget);
1779 xScreen = DefaultScreen(xDisplay);
1780 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1782 gameInfo.variant = StringToVariant(appData.variant);
1783 InitPosition(FALSE);
1786 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1788 if (isdigit(appData.boardSize[0])) {
1789 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1790 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1791 &fontPxlSize, &smallLayout, &tinyLayout);
1793 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1794 programName, appData.boardSize);
1798 /* Find some defaults; use the nearest known size */
1799 SizeDefaults *szd, *nearest;
1800 int distance = 99999;
1801 nearest = szd = sizeDefaults;
1802 while (szd->name != NULL) {
1803 if (abs(szd->squareSize - squareSize) < distance) {
1805 distance = abs(szd->squareSize - squareSize);
1806 if (distance == 0) break;
1810 if (i < 2) lineGap = nearest->lineGap;
1811 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1812 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1813 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1814 if (i < 6) smallLayout = nearest->smallLayout;
1815 if (i < 7) tinyLayout = nearest->tinyLayout;
1818 SizeDefaults *szd = sizeDefaults;
1819 if (*appData.boardSize == NULLCHAR) {
1820 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1821 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1824 if (szd->name == NULL) szd--;
1825 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1827 while (szd->name != NULL &&
1828 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1829 if (szd->name == NULL) {
1830 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1831 programName, appData.boardSize);
1835 squareSize = szd->squareSize;
1836 lineGap = szd->lineGap;
1837 clockFontPxlSize = szd->clockFontPxlSize;
1838 coordFontPxlSize = szd->coordFontPxlSize;
1839 fontPxlSize = szd->fontPxlSize;
1840 smallLayout = szd->smallLayout;
1841 tinyLayout = szd->tinyLayout;
1842 // [HGM] font: use defaults from settings file if available and not overruled
1844 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1845 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1846 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1847 appData.font = fontTable[MESSAGE_FONT][squareSize];
1848 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1849 appData.coordFont = fontTable[COORD_FONT][squareSize];
1851 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1852 if (strlen(appData.pixmapDirectory) > 0) {
1853 p = ExpandPathName(appData.pixmapDirectory);
1855 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1856 appData.pixmapDirectory);
1859 if (appData.debugMode) {
1860 fprintf(stderr, _("\
1861 XBoard square size (hint): %d\n\
1862 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1864 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1865 if (appData.debugMode) {
1866 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1870 /* [HR] height treated separately (hacked) */
1871 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1872 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1873 if (appData.showJail == 1) {
1874 /* Jail on top and bottom */
1875 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1876 XtSetArg(boardArgs[2], XtNheight,
1877 boardHeight + 2*(lineGap + squareSize));
1878 } else if (appData.showJail == 2) {
1880 XtSetArg(boardArgs[1], XtNwidth,
1881 boardWidth + 2*(lineGap + squareSize));
1882 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1885 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1886 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1890 * Determine what fonts to use.
1892 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1893 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1894 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1895 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1896 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1897 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1898 appData.font = FindFont(appData.font, fontPxlSize);
1899 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1900 countFontStruct = XQueryFont(xDisplay, countFontID);
1901 // appData.font = FindFont(appData.font, fontPxlSize);
1903 xdb = XtDatabase(xDisplay);
1904 XrmPutStringResource(&xdb, "*font", appData.font);
1907 * Detect if there are not enough colors available and adapt.
1909 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1910 appData.monoMode = True;
1913 if (!appData.monoMode) {
1914 vFrom.addr = (caddr_t) appData.lightSquareColor;
1915 vFrom.size = strlen(appData.lightSquareColor);
1916 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1917 if (vTo.addr == NULL) {
1918 appData.monoMode = True;
1921 lightSquareColor = *(Pixel *) vTo.addr;
1924 if (!appData.monoMode) {
1925 vFrom.addr = (caddr_t) appData.darkSquareColor;
1926 vFrom.size = strlen(appData.darkSquareColor);
1927 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1928 if (vTo.addr == NULL) {
1929 appData.monoMode = True;
1932 darkSquareColor = *(Pixel *) vTo.addr;
1935 if (!appData.monoMode) {
1936 vFrom.addr = (caddr_t) appData.whitePieceColor;
1937 vFrom.size = strlen(appData.whitePieceColor);
1938 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1939 if (vTo.addr == NULL) {
1940 appData.monoMode = True;
1943 whitePieceColor = *(Pixel *) vTo.addr;
1946 if (!appData.monoMode) {
1947 vFrom.addr = (caddr_t) appData.blackPieceColor;
1948 vFrom.size = strlen(appData.blackPieceColor);
1949 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1950 if (vTo.addr == NULL) {
1951 appData.monoMode = True;
1954 blackPieceColor = *(Pixel *) vTo.addr;
1958 if (!appData.monoMode) {
1959 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1960 vFrom.size = strlen(appData.highlightSquareColor);
1961 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1962 if (vTo.addr == NULL) {
1963 appData.monoMode = True;
1966 highlightSquareColor = *(Pixel *) vTo.addr;
1970 if (!appData.monoMode) {
1971 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1972 vFrom.size = strlen(appData.premoveHighlightColor);
1973 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1974 if (vTo.addr == NULL) {
1975 appData.monoMode = True;
1978 premoveHighlightColor = *(Pixel *) vTo.addr;
1983 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1986 if (appData.bitmapDirectory == NULL ||
1987 appData.bitmapDirectory[0] == NULLCHAR)
1988 appData.bitmapDirectory = DEF_BITMAP_DIR;
1991 if (appData.lowTimeWarning && !appData.monoMode) {
1992 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1993 vFrom.size = strlen(appData.lowTimeWarningColor);
1994 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1995 if (vTo.addr == NULL)
1996 appData.monoMode = True;
1998 lowTimeWarningColor = *(Pixel *) vTo.addr;
2001 if (appData.monoMode && appData.debugMode) {
2002 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2003 (unsigned long) XWhitePixel(xDisplay, xScreen),
2004 (unsigned long) XBlackPixel(xDisplay, xScreen));
2007 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2008 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2009 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2010 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2011 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2012 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2013 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2014 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2015 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2016 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2018 if (appData.colorize) {
2020 _("%s: can't parse color names; disabling colorization\n"),
2023 appData.colorize = FALSE;
2025 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2026 textColors[ColorNone].attr = 0;
2028 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2034 layoutName = "tinyLayout";
2035 } else if (smallLayout) {
2036 layoutName = "smallLayout";
2038 layoutName = "normalLayout";
2040 /* Outer layoutWidget is there only to provide a name for use in
2041 resources that depend on the layout style */
2043 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2044 layoutArgs, XtNumber(layoutArgs));
2046 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2047 formArgs, XtNumber(formArgs));
2048 XtSetArg(args[0], XtNdefaultDistance, &sep);
2049 XtGetValues(formWidget, args, 1);
2052 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2053 XtSetArg(args[0], XtNtop, XtChainTop);
2054 XtSetArg(args[1], XtNbottom, XtChainTop);
2055 XtSetArg(args[2], XtNright, XtChainLeft);
2056 XtSetValues(menuBarWidget, args, 3);
2058 widgetList[j++] = whiteTimerWidget =
2059 XtCreateWidget("whiteTime", 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(whiteTimerWidget, args, 3);
2066 widgetList[j++] = blackTimerWidget =
2067 XtCreateWidget("blackTime", labelWidgetClass,
2068 formWidget, timerArgs, XtNumber(timerArgs));
2069 XtSetArg(args[0], XtNfont, clockFontStruct);
2070 XtSetArg(args[1], XtNtop, XtChainTop);
2071 XtSetArg(args[2], XtNbottom, XtChainTop);
2072 XtSetValues(blackTimerWidget, args, 3);
2074 if (appData.titleInWindow) {
2075 widgetList[j++] = titleWidget =
2076 XtCreateWidget("title", labelWidgetClass, formWidget,
2077 titleArgs, XtNumber(titleArgs));
2078 XtSetArg(args[0], XtNtop, XtChainTop);
2079 XtSetArg(args[1], XtNbottom, XtChainTop);
2080 XtSetValues(titleWidget, args, 2);
2083 if (appData.showButtonBar) {
2084 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2085 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2086 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2087 XtSetArg(args[2], XtNtop, XtChainTop);
2088 XtSetArg(args[3], XtNbottom, XtChainTop);
2089 XtSetValues(buttonBarWidget, args, 4);
2092 widgetList[j++] = messageWidget =
2093 XtCreateWidget("message", labelWidgetClass, formWidget,
2094 messageArgs, XtNumber(messageArgs));
2095 XtSetArg(args[0], XtNtop, XtChainTop);
2096 XtSetArg(args[1], XtNbottom, XtChainTop);
2097 XtSetValues(messageWidget, args, 2);
2099 widgetList[j++] = boardWidget =
2100 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2101 XtNumber(boardArgs));
2103 XtManageChildren(widgetList, j);
2105 timerWidth = (boardWidth - sep) / 2;
2106 XtSetArg(args[0], XtNwidth, timerWidth);
2107 XtSetValues(whiteTimerWidget, args, 1);
2108 XtSetValues(blackTimerWidget, args, 1);
2110 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2111 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2112 XtGetValues(whiteTimerWidget, args, 2);
2114 if (appData.showButtonBar) {
2115 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2116 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2117 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2121 * formWidget uses these constraints but they are stored
2125 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2126 XtSetValues(menuBarWidget, args, i);
2127 if (appData.titleInWindow) {
2130 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2131 XtSetValues(whiteTimerWidget, args, i);
2133 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2134 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2135 XtSetValues(blackTimerWidget, args, i);
2137 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2138 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2139 XtSetValues(titleWidget, args, i);
2141 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2142 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2143 XtSetValues(messageWidget, args, i);
2144 if (appData.showButtonBar) {
2146 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2147 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2148 XtSetValues(buttonBarWidget, args, i);
2152 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2153 XtSetValues(whiteTimerWidget, args, i);
2155 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2156 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2157 XtSetValues(blackTimerWidget, args, i);
2159 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2160 XtSetValues(titleWidget, args, i);
2162 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2163 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2164 XtSetValues(messageWidget, args, i);
2165 if (appData.showButtonBar) {
2167 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2168 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2169 XtSetValues(buttonBarWidget, args, i);
2174 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2175 XtSetValues(whiteTimerWidget, args, i);
2177 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2178 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2179 XtSetValues(blackTimerWidget, args, i);
2181 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2182 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2183 XtSetValues(messageWidget, args, i);
2184 if (appData.showButtonBar) {
2186 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2187 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2188 XtSetValues(buttonBarWidget, args, i);
2192 XtSetArg(args[0], XtNfromVert, messageWidget);
2193 XtSetArg(args[1], XtNtop, XtChainTop);
2194 XtSetArg(args[2], XtNbottom, XtChainBottom);
2195 XtSetArg(args[3], XtNleft, XtChainLeft);
2196 XtSetArg(args[4], XtNright, XtChainRight);
2197 XtSetValues(boardWidget, args, 5);
2199 XtRealizeWidget(shellWidget);
2202 XtSetArg(args[0], XtNx, wpMain.x);
2203 XtSetArg(args[1], XtNy, wpMain.y);
2204 XtSetValues(shellWidget, args, 2);
2208 * Correct the width of the message and title widgets.
2209 * It is not known why some systems need the extra fudge term.
2210 * The value "2" is probably larger than needed.
2212 XawFormDoLayout(formWidget, False);
2214 #define WIDTH_FUDGE 2
2216 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2217 XtSetArg(args[i], XtNheight, &h); i++;
2218 XtGetValues(messageWidget, args, i);
2219 if (appData.showButtonBar) {
2221 XtSetArg(args[i], XtNwidth, &w); i++;
2222 XtGetValues(buttonBarWidget, args, i);
2223 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2225 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2228 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2229 if (gres != XtGeometryYes && appData.debugMode) {
2230 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2231 programName, gres, w, h, wr, hr);
2234 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2235 /* The size used for the child widget in layout lags one resize behind
2236 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2238 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2239 if (gres != XtGeometryYes && appData.debugMode) {
2240 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2241 programName, gres, w, h, wr, hr);
2244 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2245 XtSetArg(args[1], XtNright, XtChainRight);
2246 XtSetValues(messageWidget, args, 2);
2248 if (appData.titleInWindow) {
2250 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2251 XtSetArg(args[i], XtNheight, &h); i++;
2252 XtGetValues(titleWidget, args, i);
2254 w = boardWidth - 2*bor;
2256 XtSetArg(args[0], XtNwidth, &w);
2257 XtGetValues(menuBarWidget, args, 1);
2258 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2261 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2262 if (gres != XtGeometryYes && appData.debugMode) {
2264 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2265 programName, gres, w, h, wr, hr);
2268 XawFormDoLayout(formWidget, True);
2270 xBoardWindow = XtWindow(boardWidget);
2272 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2273 // not need to go into InitDrawingSizes().
2277 * Create X checkmark bitmap and initialize option menu checks.
2279 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2280 checkmark_bits, checkmark_width, checkmark_height);
2281 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2282 if (appData.alwaysPromoteToQueen) {
2283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2286 if (appData.animateDragging) {
2287 XtSetValues(XtNameToWidget(menuBarWidget,
2288 "menuOptions.Animate Dragging"),
2291 if (appData.animate) {
2292 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2295 if (appData.autoComment) {
2296 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2299 if (appData.autoCallFlag) {
2300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2303 if (appData.autoFlipView) {
2304 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2307 if (appData.autoObserve) {
2308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2311 if (appData.autoRaiseBoard) {
2312 XtSetValues(XtNameToWidget(menuBarWidget,
2313 "menuOptions.Auto Raise Board"), args, 1);
2315 if (appData.autoSaveGames) {
2316 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2319 if (appData.saveGameFile[0] != NULLCHAR) {
2320 /* Can't turn this off from menu */
2321 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2323 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2327 if (appData.blindfold) {
2328 XtSetValues(XtNameToWidget(menuBarWidget,
2329 "menuOptions.Blindfold"), args, 1);
2331 if (appData.flashCount > 0) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Flash Moves"),
2336 if (appData.getMoveList) {
2337 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2341 if (appData.highlightDragging) {
2342 XtSetValues(XtNameToWidget(menuBarWidget,
2343 "menuOptions.Highlight Dragging"),
2347 if (appData.highlightLastMove) {
2348 XtSetValues(XtNameToWidget(menuBarWidget,
2349 "menuOptions.Highlight Last Move"),
2352 if (appData.icsAlarm) {
2353 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2356 if (appData.ringBellAfterMoves) {
2357 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2360 if (appData.oldSaveStyle) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,
2362 "menuOptions.Old Save Style"), args, 1);
2364 if (appData.periodicUpdates) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,
2366 "menuOptions.Periodic Updates"), args, 1);
2368 if (appData.ponderNextMove) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Ponder Next Move"), args, 1);
2372 if (appData.popupExitMessage) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Popup Exit Message"), args, 1);
2376 if (appData.popupMoveErrors) {
2377 XtSetValues(XtNameToWidget(menuBarWidget,
2378 "menuOptions.Popup Move Errors"), args, 1);
2380 if (appData.premove) {
2381 XtSetValues(XtNameToWidget(menuBarWidget,
2382 "menuOptions.Premove"), args, 1);
2384 if (appData.quietPlay) {
2385 XtSetValues(XtNameToWidget(menuBarWidget,
2386 "menuOptions.Quiet Play"), args, 1);
2388 if (appData.showCoords) {
2389 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2392 if (appData.hideThinkingFromHuman) {
2393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2396 if (appData.testLegality) {
2397 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2400 if (saveSettingsOnExit) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2408 ReadBitmap(&wIconPixmap, "icon_white.bm",
2409 icon_white_bits, icon_white_width, icon_white_height);
2410 ReadBitmap(&bIconPixmap, "icon_black.bm",
2411 icon_black_bits, icon_black_width, icon_black_height);
2412 iconPixmap = wIconPixmap;
2414 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2415 XtSetValues(shellWidget, args, i);
2418 * Create a cursor for the board widget.
2420 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2421 XChangeWindowAttributes(xDisplay, xBoardWindow,
2422 CWCursor, &window_attributes);
2425 * Inhibit shell resizing.
2427 shellArgs[0].value = (XtArgVal) &w;
2428 shellArgs[1].value = (XtArgVal) &h;
2429 XtGetValues(shellWidget, shellArgs, 2);
2430 shellArgs[4].value = shellArgs[2].value = w;
2431 shellArgs[5].value = shellArgs[3].value = h;
2432 XtSetValues(shellWidget, &shellArgs[2], 4);
2433 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2434 marginH = h - boardHeight;
2436 CatchDeleteWindow(shellWidget, "QuitProc");
2441 if (appData.bitmapDirectory[0] != NULLCHAR) {
2448 /* Create regular pieces */
2449 if (!useImages) CreatePieces();
2454 if (appData.animate || appData.animateDragging)
2457 XtAugmentTranslations(formWidget,
2458 XtParseTranslationTable(globalTranslations));
2459 XtAugmentTranslations(boardWidget,
2460 XtParseTranslationTable(boardTranslations));
2461 XtAugmentTranslations(whiteTimerWidget,
2462 XtParseTranslationTable(whiteTranslations));
2463 XtAugmentTranslations(blackTimerWidget,
2464 XtParseTranslationTable(blackTranslations));
2466 /* Why is the following needed on some versions of X instead
2467 * of a translation? */
2468 XtAddEventHandler(boardWidget, ExposureMask, False,
2469 (XtEventHandler) EventProc, NULL);
2472 /* [AS] Restore layout */
2473 if( wpMoveHistory.visible ) {
2477 if( wpEvalGraph.visible )
2482 if( wpEngineOutput.visible ) {
2483 EngineOutputPopUp();
2488 if (errorExitStatus == -1) {
2489 if (appData.icsActive) {
2490 /* We now wait until we see "login:" from the ICS before
2491 sending the logon script (problems with timestamp otherwise) */
2492 /*ICSInitScript();*/
2493 if (appData.icsInputBox) ICSInputBoxPopUp();
2497 signal(SIGWINCH, TermSizeSigHandler);
2499 signal(SIGINT, IntSigHandler);
2500 signal(SIGTERM, IntSigHandler);
2501 if (*appData.cmailGameName != NULLCHAR) {
2502 signal(SIGUSR1, CmailSigHandler);
2505 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2508 XtAppMainLoop(appContext);
2509 if (appData.debugMode) fclose(debugFP); // [DM] debug
2516 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2517 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2519 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2520 unlink(gameCopyFilename);
2521 unlink(gamePasteFilename);
2524 RETSIGTYPE TermSizeSigHandler(int sig)
2537 CmailSigHandler(sig)
2543 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2545 /* Activate call-back function CmailSigHandlerCallBack() */
2546 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2548 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2552 CmailSigHandlerCallBack(isr, closure, message, count, error)
2560 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2562 /**** end signal code ****/
2572 f = fopen(appData.icsLogon, "r");
2578 strcat(buf, appData.icsLogon);
2579 f = fopen(buf, "r");
2583 ProcessICSInitScript(f);
2590 EditCommentPopDown();
2605 if (!menuBarWidget) return;
2606 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2608 DisplayError("menuStep.Revert", 0);
2610 XtSetSensitive(w, !grey);
2615 SetMenuEnables(enab)
2619 if (!menuBarWidget) return;
2620 while (enab->name != NULL) {
2621 w = XtNameToWidget(menuBarWidget, enab->name);
2623 DisplayError(enab->name, 0);
2625 XtSetSensitive(w, enab->value);
2631 Enables icsEnables[] = {
2632 { "menuFile.Mail Move", False },
2633 { "menuFile.Reload CMail Message", False },
2634 { "menuMode.Machine Black", False },
2635 { "menuMode.Machine White", False },
2636 { "menuMode.Analysis Mode", False },
2637 { "menuMode.Analyze File", False },
2638 { "menuMode.Two Machines", False },
2640 { "menuHelp.Hint", False },
2641 { "menuHelp.Book", False },
2642 { "menuStep.Move Now", False },
2643 { "menuOptions.Periodic Updates", False },
2644 { "menuOptions.Hide Thinking", False },
2645 { "menuOptions.Ponder Next Move", False },
2650 Enables ncpEnables[] = {
2651 { "menuFile.Mail Move", False },
2652 { "menuFile.Reload CMail Message", False },
2653 { "menuMode.Machine White", False },
2654 { "menuMode.Machine Black", False },
2655 { "menuMode.Analysis Mode", False },
2656 { "menuMode.Analyze File", False },
2657 { "menuMode.Two Machines", False },
2658 { "menuMode.ICS Client", False },
2659 { "menuMode.ICS Input Box", False },
2660 { "Action", False },
2661 { "menuStep.Revert", False },
2662 { "menuStep.Move Now", False },
2663 { "menuStep.Retract Move", False },
2664 { "menuOptions.Auto Comment", False },
2665 { "menuOptions.Auto Flag", False },
2666 { "menuOptions.Auto Flip View", False },
2667 { "menuOptions.Auto Observe", False },
2668 { "menuOptions.Auto Raise Board", False },
2669 { "menuOptions.Get Move List", False },
2670 { "menuOptions.ICS Alarm", False },
2671 { "menuOptions.Move Sound", False },
2672 { "menuOptions.Quiet Play", False },
2673 { "menuOptions.Hide Thinking", False },
2674 { "menuOptions.Periodic Updates", False },
2675 { "menuOptions.Ponder Next Move", False },
2676 { "menuHelp.Hint", False },
2677 { "menuHelp.Book", False },
2681 Enables gnuEnables[] = {
2682 { "menuMode.ICS Client", False },
2683 { "menuMode.ICS Input Box", False },
2684 { "menuAction.Accept", False },
2685 { "menuAction.Decline", False },
2686 { "menuAction.Rematch", False },
2687 { "menuAction.Adjourn", False },
2688 { "menuAction.Stop Examining", False },
2689 { "menuAction.Stop Observing", False },
2690 { "menuStep.Revert", False },
2691 { "menuOptions.Auto Comment", False },
2692 { "menuOptions.Auto Observe", False },
2693 { "menuOptions.Auto Raise Board", False },
2694 { "menuOptions.Get Move List", False },
2695 { "menuOptions.Premove", False },
2696 { "menuOptions.Quiet Play", False },
2698 /* The next two options rely on SetCmailMode being called *after* */
2699 /* SetGNUMode so that when GNU is being used to give hints these */
2700 /* menu options are still available */
2702 { "menuFile.Mail Move", False },
2703 { "menuFile.Reload CMail Message", False },
2707 Enables cmailEnables[] = {
2709 { "menuAction.Call Flag", False },
2710 { "menuAction.Draw", True },
2711 { "menuAction.Adjourn", False },
2712 { "menuAction.Abort", False },
2713 { "menuAction.Stop Observing", False },
2714 { "menuAction.Stop Examining", False },
2715 { "menuFile.Mail Move", True },
2716 { "menuFile.Reload CMail Message", True },
2720 Enables trainingOnEnables[] = {
2721 { "menuMode.Edit Comment", False },
2722 { "menuMode.Pause", False },
2723 { "menuStep.Forward", False },
2724 { "menuStep.Backward", False },
2725 { "menuStep.Forward to End", False },
2726 { "menuStep.Back to Start", False },
2727 { "menuStep.Move Now", False },
2728 { "menuStep.Truncate Game", False },
2732 Enables trainingOffEnables[] = {
2733 { "menuMode.Edit Comment", True },
2734 { "menuMode.Pause", True },
2735 { "menuStep.Forward", True },
2736 { "menuStep.Backward", True },
2737 { "menuStep.Forward to End", True },
2738 { "menuStep.Back to Start", True },
2739 { "menuStep.Move Now", True },
2740 { "menuStep.Truncate Game", True },
2744 Enables machineThinkingEnables[] = {
2745 { "menuFile.Load Game", False },
2746 { "menuFile.Load Next Game", False },
2747 { "menuFile.Load Previous Game", False },
2748 { "menuFile.Reload Same Game", False },
2749 { "menuFile.Paste Game", False },
2750 { "menuFile.Load Position", False },
2751 { "menuFile.Load Next Position", False },
2752 { "menuFile.Load Previous Position", False },
2753 { "menuFile.Reload Same Position", False },
2754 { "menuFile.Paste Position", False },
2755 { "menuMode.Machine White", False },
2756 { "menuMode.Machine Black", False },
2757 { "menuMode.Two Machines", False },
2758 { "menuStep.Retract Move", False },
2762 Enables userThinkingEnables[] = {
2763 { "menuFile.Load Game", True },
2764 { "menuFile.Load Next Game", True },
2765 { "menuFile.Load Previous Game", True },
2766 { "menuFile.Reload Same Game", True },
2767 { "menuFile.Paste Game", True },
2768 { "menuFile.Load Position", True },
2769 { "menuFile.Load Next Position", True },
2770 { "menuFile.Load Previous Position", True },
2771 { "menuFile.Reload Same Position", True },
2772 { "menuFile.Paste Position", True },
2773 { "menuMode.Machine White", True },
2774 { "menuMode.Machine Black", True },
2775 { "menuMode.Two Machines", True },
2776 { "menuStep.Retract Move", True },
2782 SetMenuEnables(icsEnables);
2785 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2786 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2793 SetMenuEnables(ncpEnables);
2799 SetMenuEnables(gnuEnables);
2805 SetMenuEnables(cmailEnables);
2811 SetMenuEnables(trainingOnEnables);
2812 if (appData.showButtonBar) {
2813 XtSetSensitive(buttonBarWidget, False);
2819 SetTrainingModeOff()
2821 SetMenuEnables(trainingOffEnables);
2822 if (appData.showButtonBar) {
2823 XtSetSensitive(buttonBarWidget, True);
2828 SetUserThinkingEnables()
2830 if (appData.noChessProgram) return;
2831 SetMenuEnables(userThinkingEnables);
2835 SetMachineThinkingEnables()
2837 if (appData.noChessProgram) return;
2838 SetMenuEnables(machineThinkingEnables);
2840 case MachinePlaysBlack:
2841 case MachinePlaysWhite:
2842 case TwoMachinesPlay:
2843 XtSetSensitive(XtNameToWidget(menuBarWidget,
2844 ModeToWidgetName(gameMode)), True);
2851 #define Abs(n) ((n)<0 ? -(n) : (n))
2854 * Find a font that matches "pattern" that is as close as
2855 * possible to the targetPxlSize. Prefer fonts that are k
2856 * pixels smaller to fonts that are k pixels larger. The
2857 * pattern must be in the X Consortium standard format,
2858 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2859 * The return value should be freed with XtFree when no
2862 char *FindFont(pattern, targetPxlSize)
2866 char **fonts, *p, *best, *scalable, *scalableTail;
2867 int i, j, nfonts, minerr, err, pxlSize;
2870 char **missing_list;
2872 char *def_string, *base_fnt_lst, strInt[3];
2874 XFontStruct **fnt_list;
2876 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2877 sprintf(strInt, "%d", targetPxlSize);
2878 p = strstr(pattern, "--");
2879 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2880 strcat(base_fnt_lst, strInt);
2881 strcat(base_fnt_lst, strchr(p + 2, '-'));
2883 if ((fntSet = XCreateFontSet(xDisplay,
2887 &def_string)) == NULL) {
2889 fprintf(stderr, _("Unable to create font set.\n"));
2893 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2895 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2897 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2898 programName, pattern);
2906 for (i=0; i<nfonts; i++) {
2909 if (*p != '-') continue;
2911 if (*p == NULLCHAR) break;
2912 if (*p++ == '-') j++;
2914 if (j < 7) continue;
2917 scalable = fonts[i];
2920 err = pxlSize - targetPxlSize;
2921 if (Abs(err) < Abs(minerr) ||
2922 (minerr > 0 && err < 0 && -err == minerr)) {
2928 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2929 /* If the error is too big and there is a scalable font,
2930 use the scalable font. */
2931 int headlen = scalableTail - scalable;
2932 p = (char *) XtMalloc(strlen(scalable) + 10);
2933 while (isdigit(*scalableTail)) scalableTail++;
2934 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2936 p = (char *) XtMalloc(strlen(best) + 1);
2939 if (appData.debugMode) {
2940 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2941 pattern, targetPxlSize, p);
2944 if (missing_count > 0)
2945 XFreeStringList(missing_list);
2946 XFreeFontSet(xDisplay, fntSet);
2948 XFreeFontNames(fonts);
2955 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2956 | GCBackground | GCFunction | GCPlaneMask;
2957 XGCValues gc_values;
2960 gc_values.plane_mask = AllPlanes;
2961 gc_values.line_width = lineGap;
2962 gc_values.line_style = LineSolid;
2963 gc_values.function = GXcopy;
2965 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2966 gc_values.background = XBlackPixel(xDisplay, xScreen);
2967 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2969 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2970 gc_values.background = XWhitePixel(xDisplay, xScreen);
2971 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2972 XSetFont(xDisplay, coordGC, coordFontID);
2974 // [HGM] make font for holdings counts (white on black0
2975 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2976 gc_values.background = XBlackPixel(xDisplay, xScreen);
2977 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2978 XSetFont(xDisplay, countGC, countFontID);
2980 if (appData.monoMode) {
2981 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2982 gc_values.background = XWhitePixel(xDisplay, xScreen);
2983 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2985 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2986 gc_values.background = XBlackPixel(xDisplay, xScreen);
2987 lightSquareGC = wbPieceGC
2988 = XtGetGC(shellWidget, value_mask, &gc_values);
2990 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2991 gc_values.background = XWhitePixel(xDisplay, xScreen);
2992 darkSquareGC = bwPieceGC
2993 = XtGetGC(shellWidget, value_mask, &gc_values);
2995 if (DefaultDepth(xDisplay, xScreen) == 1) {
2996 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2997 gc_values.function = GXcopyInverted;
2998 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2999 gc_values.function = GXcopy;
3000 if (XBlackPixel(xDisplay, xScreen) == 1) {
3001 bwPieceGC = darkSquareGC;
3002 wbPieceGC = copyInvertedGC;
3004 bwPieceGC = copyInvertedGC;
3005 wbPieceGC = lightSquareGC;
3009 gc_values.foreground = highlightSquareColor;
3010 gc_values.background = highlightSquareColor;
3011 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3013 gc_values.foreground = premoveHighlightColor;
3014 gc_values.background = premoveHighlightColor;
3015 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 gc_values.foreground = lightSquareColor;
3018 gc_values.background = darkSquareColor;
3019 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3021 gc_values.foreground = darkSquareColor;
3022 gc_values.background = lightSquareColor;
3023 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 gc_values.foreground = jailSquareColor;
3026 gc_values.background = jailSquareColor;
3027 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3029 gc_values.foreground = whitePieceColor;
3030 gc_values.background = darkSquareColor;
3031 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3033 gc_values.foreground = whitePieceColor;
3034 gc_values.background = lightSquareColor;
3035 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3037 gc_values.foreground = whitePieceColor;
3038 gc_values.background = jailSquareColor;
3039 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3041 gc_values.foreground = blackPieceColor;
3042 gc_values.background = darkSquareColor;
3043 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3045 gc_values.foreground = blackPieceColor;
3046 gc_values.background = lightSquareColor;
3047 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3049 gc_values.foreground = blackPieceColor;
3050 gc_values.background = jailSquareColor;
3051 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3055 void loadXIM(xim, xmask, filename, dest, mask)
3068 fp = fopen(filename, "rb");
3070 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3077 for (y=0; y<h; ++y) {
3078 for (x=0; x<h; ++x) {
3083 XPutPixel(xim, x, y, blackPieceColor);
3085 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3088 XPutPixel(xim, x, y, darkSquareColor);
3090 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3093 XPutPixel(xim, x, y, whitePieceColor);
3095 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3098 XPutPixel(xim, x, y, lightSquareColor);
3100 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3106 /* create Pixmap of piece */
3107 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3109 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3112 /* create Pixmap of clipmask
3113 Note: We assume the white/black pieces have the same
3114 outline, so we make only 6 masks. This is okay
3115 since the XPM clipmask routines do the same. */
3117 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3119 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3122 /* now create the 1-bit version */
3123 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3126 values.foreground = 1;
3127 values.background = 0;
3129 /* Don't use XtGetGC, not read only */
3130 maskGC = XCreateGC(xDisplay, *mask,
3131 GCForeground | GCBackground, &values);
3132 XCopyPlane(xDisplay, temp, *mask, maskGC,
3133 0, 0, squareSize, squareSize, 0, 0, 1);
3134 XFreePixmap(xDisplay, temp);
3139 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3141 void CreateXIMPieces()
3146 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3151 /* The XSynchronize calls were copied from CreatePieces.
3152 Not sure if needed, but can't hurt */
3153 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3156 /* temp needed by loadXIM() */
3157 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3158 0, 0, ss, ss, AllPlanes, XYPixmap);
3160 if (strlen(appData.pixmapDirectory) == 0) {
3164 if (appData.monoMode) {
3165 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3169 fprintf(stderr, _("\nLoading XIMs...\n"));
3171 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3172 fprintf(stderr, "%d", piece+1);
3173 for (kind=0; kind<4; kind++) {
3174 fprintf(stderr, ".");
3175 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3176 ExpandPathName(appData.pixmapDirectory),
3177 piece <= (int) WhiteKing ? "" : "w",
3178 pieceBitmapNames[piece],
3180 ximPieceBitmap[kind][piece] =
3181 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3182 0, 0, ss, ss, AllPlanes, XYPixmap);
3183 if (appData.debugMode)
3184 fprintf(stderr, _("(File:%s:) "), buf);
3185 loadXIM(ximPieceBitmap[kind][piece],
3187 &(xpmPieceBitmap2[kind][piece]),
3188 &(ximMaskPm2[piece]));
3189 if(piece <= (int)WhiteKing)
3190 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3192 fprintf(stderr," ");
3194 /* Load light and dark squares */
3195 /* If the LSQ and DSQ pieces don't exist, we will
3196 draw them with solid squares. */
3197 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3198 if (access(buf, 0) != 0) {
3202 fprintf(stderr, _("light square "));
3204 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3205 0, 0, ss, ss, AllPlanes, XYPixmap);
3206 if (appData.debugMode)
3207 fprintf(stderr, _("(File:%s:) "), buf);
3209 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3210 fprintf(stderr, _("dark square "));
3211 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3212 ExpandPathName(appData.pixmapDirectory), ss);
3213 if (appData.debugMode)
3214 fprintf(stderr, _("(File:%s:) "), buf);
3216 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3217 0, 0, ss, ss, AllPlanes, XYPixmap);
3218 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3219 xpmJailSquare = xpmLightSquare;
3221 fprintf(stderr, _("Done.\n"));
3223 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3227 void CreateXPMPieces()
3231 u_int ss = squareSize;
3233 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3234 XpmColorSymbol symbols[4];
3236 /* The XSynchronize calls were copied from CreatePieces.
3237 Not sure if needed, but can't hurt */
3238 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3240 /* Setup translations so piece colors match square colors */
3241 symbols[0].name = "light_piece";
3242 symbols[0].value = appData.whitePieceColor;
3243 symbols[1].name = "dark_piece";
3244 symbols[1].value = appData.blackPieceColor;
3245 symbols[2].name = "light_square";
3246 symbols[2].value = appData.lightSquareColor;
3247 symbols[3].name = "dark_square";
3248 symbols[3].value = appData.darkSquareColor;
3250 attr.valuemask = XpmColorSymbols;
3251 attr.colorsymbols = symbols;
3252 attr.numsymbols = 4;
3254 if (appData.monoMode) {
3255 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3259 if (strlen(appData.pixmapDirectory) == 0) {
3260 XpmPieces* pieces = builtInXpms;
3263 while (pieces->size != squareSize && pieces->size) pieces++;
3264 if (!pieces->size) {
3265 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3268 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3269 for (kind=0; kind<4; kind++) {
3271 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3272 pieces->xpm[piece][kind],
3273 &(xpmPieceBitmap2[kind][piece]),
3274 NULL, &attr)) != 0) {
3275 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3279 if(piece <= (int) WhiteKing)
3280 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3284 xpmJailSquare = xpmLightSquare;
3288 fprintf(stderr, _("\nLoading XPMs...\n"));
3291 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3292 fprintf(stderr, "%d ", piece+1);
3293 for (kind=0; kind<4; kind++) {
3294 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3295 ExpandPathName(appData.pixmapDirectory),
3296 piece > (int) WhiteKing ? "w" : "",
3297 pieceBitmapNames[piece],
3299 if (appData.debugMode) {
3300 fprintf(stderr, _("(File:%s:) "), buf);
3302 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3303 &(xpmPieceBitmap2[kind][piece]),
3304 NULL, &attr)) != 0) {
3305 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3306 // [HGM] missing: read of unorthodox piece failed; substitute King.
3307 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3308 ExpandPathName(appData.pixmapDirectory),
3310 if (appData.debugMode) {
3311 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3313 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3314 &(xpmPieceBitmap2[kind][piece]),
3318 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3323 if(piece <= (int) WhiteKing)
3324 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3327 /* Load light and dark squares */
3328 /* If the LSQ and DSQ pieces don't exist, we will
3329 draw them with solid squares. */
3330 fprintf(stderr, _("light square "));
3331 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3332 if (access(buf, 0) != 0) {
3336 if (appData.debugMode)
3337 fprintf(stderr, _("(File:%s:) "), buf);
3339 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3340 &xpmLightSquare, NULL, &attr)) != 0) {
3341 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3344 fprintf(stderr, _("dark square "));
3345 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3346 ExpandPathName(appData.pixmapDirectory), ss);
3347 if (appData.debugMode) {
3348 fprintf(stderr, _("(File:%s:) "), buf);
3350 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3351 &xpmDarkSquare, NULL, &attr)) != 0) {
3352 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3356 xpmJailSquare = xpmLightSquare;
3357 fprintf(stderr, _("Done.\n"));
3359 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3362 #endif /* HAVE_LIBXPM */
3365 /* No built-in bitmaps */
3370 u_int ss = squareSize;
3372 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3375 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3376 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3377 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3378 pieceBitmapNames[piece],
3379 ss, kind == SOLID ? 's' : 'o');
3380 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3381 if(piece <= (int)WhiteKing)
3382 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3386 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3390 /* With built-in bitmaps */
3393 BuiltInBits* bib = builtInBits;
3396 u_int ss = squareSize;
3398 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3401 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3403 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3404 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3405 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3406 pieceBitmapNames[piece],
3407 ss, kind == SOLID ? 's' : 'o');
3408 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3409 bib->bits[kind][piece], ss, ss);
3410 if(piece <= (int)WhiteKing)
3411 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3415 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3420 void ReadBitmap(pm, name, bits, wreq, hreq)
3423 unsigned char bits[];
3429 char msg[MSG_SIZ], fullname[MSG_SIZ];
3431 if (*appData.bitmapDirectory != NULLCHAR) {
3432 strcpy(fullname, appData.bitmapDirectory);
3433 strcat(fullname, "/");
3434 strcat(fullname, name);
3435 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3436 &w, &h, pm, &x_hot, &y_hot);
3437 fprintf(stderr, "load %s\n", name);
3438 if (errcode != BitmapSuccess) {
3440 case BitmapOpenFailed:
3441 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3443 case BitmapFileInvalid:
3444 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3446 case BitmapNoMemory:
3447 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3451 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3455 fprintf(stderr, _("%s: %s...using built-in\n"),
3457 } else if (w != wreq || h != hreq) {
3459 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3460 programName, fullname, w, h, wreq, hreq);
3466 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3475 if (lineGap == 0) return;
3477 /* [HR] Split this into 2 loops for non-square boards. */
3479 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3480 gridSegments[i].x1 = 0;
3481 gridSegments[i].x2 =
3482 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3483 gridSegments[i].y1 = gridSegments[i].y2
3484 = lineGap / 2 + (i * (squareSize + lineGap));
3487 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3488 gridSegments[j + i].y1 = 0;
3489 gridSegments[j + i].y2 =
3490 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3491 gridSegments[j + i].x1 = gridSegments[j + i].x2
3492 = lineGap / 2 + (j * (squareSize + lineGap));
3496 static void MenuBarSelect(w, addr, index)
3501 XtActionProc proc = (XtActionProc) addr;
3503 (proc)(NULL, NULL, NULL, NULL);
3506 void CreateMenuBarPopup(parent, name, mb)
3516 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3519 XtSetArg(args[j], XtNleftMargin, 20); j++;
3520 XtSetArg(args[j], XtNrightMargin, 20); j++;
3522 while (mi->string != NULL) {
3523 if (strcmp(mi->string, "----") == 0) {
3524 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3527 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3528 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3530 XtAddCallback(entry, XtNcallback,
3531 (XtCallbackProc) MenuBarSelect,
3532 (caddr_t) mi->proc);
3538 Widget CreateMenuBar(mb)
3542 Widget anchor, menuBar;
3544 char menuName[MSG_SIZ];
3547 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3548 XtSetArg(args[j], XtNvSpace, 0); j++;
3549 XtSetArg(args[j], XtNborderWidth, 0); j++;
3550 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3551 formWidget, args, j);
3553 while (mb->name != NULL) {
3554 strcpy(menuName, "menu");
3555 strcat(menuName, mb->name);
3557 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3560 shortName[0] = _(mb->name)[0];
3561 shortName[1] = NULLCHAR;
3562 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3565 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3568 XtSetArg(args[j], XtNborderWidth, 0); j++;
3569 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3571 CreateMenuBarPopup(menuBar, menuName, mb);
3577 Widget CreateButtonBar(mi)
3581 Widget button, buttonBar;
3585 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3587 XtSetArg(args[j], XtNhSpace, 0); j++;
3589 XtSetArg(args[j], XtNborderWidth, 0); j++;
3590 XtSetArg(args[j], XtNvSpace, 0); j++;
3591 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3592 formWidget, args, j);
3594 while (mi->string != NULL) {
3597 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3598 XtSetArg(args[j], XtNborderWidth, 0); j++;
3600 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3601 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3602 buttonBar, args, j);
3603 XtAddCallback(button, XtNcallback,
3604 (XtCallbackProc) MenuBarSelect,
3605 (caddr_t) mi->proc);
3612 CreatePieceMenu(name, color)
3619 ChessSquare selection;
3621 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3622 boardWidget, args, 0);
3624 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3625 String item = pieceMenuStrings[color][i];
3627 if (strcmp(item, "----") == 0) {
3628 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3631 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3632 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3634 selection = pieceMenuTranslation[color][i];
3635 XtAddCallback(entry, XtNcallback,
3636 (XtCallbackProc) PieceMenuSelect,
3637 (caddr_t) selection);
3638 if (selection == WhitePawn || selection == BlackPawn) {
3639 XtSetArg(args[0], XtNpopupOnEntry, entry);
3640 XtSetValues(menu, args, 1);
3653 ChessSquare selection;
3655 whitePieceMenu = CreatePieceMenu("menuW", 0);
3656 blackPieceMenu = CreatePieceMenu("menuB", 1);
3658 XtRegisterGrabAction(PieceMenuPopup, True,
3659 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3660 GrabModeAsync, GrabModeAsync);
3662 XtSetArg(args[0], XtNlabel, _("Drop"));
3663 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3664 boardWidget, args, 1);
3665 for (i = 0; i < DROP_MENU_SIZE; i++) {
3666 String item = dropMenuStrings[i];
3668 if (strcmp(item, "----") == 0) {
3669 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3672 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3673 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3675 selection = dropMenuTranslation[i];
3676 XtAddCallback(entry, XtNcallback,
3677 (XtCallbackProc) DropMenuSelect,
3678 (caddr_t) selection);
3683 void SetupDropMenu()
3691 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3692 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3693 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3694 dmEnables[i].piece);
3695 XtSetSensitive(entry, p != NULL || !appData.testLegality
3696 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3697 && !appData.icsActive));
3699 while (p && *p++ == dmEnables[i].piece) count++;
3700 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3702 XtSetArg(args[j], XtNlabel, label); j++;
3703 XtSetValues(entry, args, j);
3707 void PieceMenuPopup(w, event, params, num_params)
3711 Cardinal *num_params;
3715 if (event->type == ButtonRelease) UnLoadPV(); // [HGM] pv
3716 if (event->type != ButtonPress) return;
3717 if (errorUp) ErrorPopDown();
3721 whichMenu = params[0];
3724 if(!appData.icsEngineAnalyze) return;
3725 case IcsPlayingWhite:
3726 case IcsPlayingBlack:
3727 if(!appData.zippyPlay) goto noZip;
3730 case MachinePlaysWhite:
3731 case MachinePlaysBlack:
3732 case TwoMachinesPlay: // [HGM] pv: use for showing PV
3733 if (!appData.dropMenu) {
3734 LoadPV(event->xbutton.x, event->xbutton.y);
3737 if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
3738 gameMode == AnalyzeFile || gameMode == IcsObserving) return;
3741 if (!appData.dropMenu || appData.testLegality &&
3742 gameInfo.variant != VariantBughouse &&
3743 gameInfo.variant != VariantCrazyhouse) return;
3745 whichMenu = "menuD";
3751 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3752 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3753 pmFromX = pmFromY = -1;
3757 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3759 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3761 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3764 static void PieceMenuSelect(w, piece, junk)
3769 if (pmFromX < 0 || pmFromY < 0) return;
3770 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3773 static void DropMenuSelect(w, piece, junk)
3778 if (pmFromX < 0 || pmFromY < 0) return;
3779 DropMenuEvent(piece, pmFromX, pmFromY);
3782 void WhiteClock(w, event, prms, nprms)
3788 if (gameMode == EditPosition || gameMode == IcsExamining) {
3789 SetWhiteToPlayEvent();
3790 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3795 void BlackClock(w, event, prms, nprms)
3801 if (gameMode == EditPosition || gameMode == IcsExamining) {
3802 SetBlackToPlayEvent();
3803 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3810 * If the user selects on a border boundary, return -1; if off the board,
3811 * return -2. Otherwise map the event coordinate to the square.
3813 int EventToSquare(x, limit)
3821 if ((x % (squareSize + lineGap)) >= squareSize)
3823 x /= (squareSize + lineGap);
3829 static void do_flash_delay(msec)
3835 static void drawHighlight(file, rank, gc)
3841 if (lineGap == 0 || appData.blindfold) return;
3844 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3845 (squareSize + lineGap);
3846 y = lineGap/2 + rank * (squareSize + lineGap);
3848 x = lineGap/2 + file * (squareSize + lineGap);
3849 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3850 (squareSize + lineGap);
3853 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3854 squareSize+lineGap, squareSize+lineGap);
3857 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3858 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3861 SetHighlights(fromX, fromY, toX, toY)
3862 int fromX, fromY, toX, toY;
3864 if (hi1X != fromX || hi1Y != fromY) {
3865 if (hi1X >= 0 && hi1Y >= 0) {
3866 drawHighlight(hi1X, hi1Y, lineGC);
3868 if (fromX >= 0 && fromY >= 0) {
3869 drawHighlight(fromX, fromY, highlineGC);
3872 if (hi2X != toX || hi2Y != toY) {
3873 if (hi2X >= 0 && hi2Y >= 0) {
3874 drawHighlight(hi2X, hi2Y, lineGC);
3876 if (toX >= 0 && toY >= 0) {
3877 drawHighlight(toX, toY, highlineGC);
3889 SetHighlights(-1, -1, -1, -1);
3894 SetPremoveHighlights(fromX, fromY, toX, toY)
3895 int fromX, fromY, toX, toY;
3897 if (pm1X != fromX || pm1Y != fromY) {
3898 if (pm1X >= 0 && pm1Y >= 0) {
3899 drawHighlight(pm1X, pm1Y, lineGC);
3901 if (fromX >= 0 && fromY >= 0) {
3902 drawHighlight(fromX, fromY, prelineGC);
3905 if (pm2X != toX || pm2Y != toY) {
3906 if (pm2X >= 0 && pm2Y >= 0) {
3907 drawHighlight(pm2X, pm2Y, lineGC);
3909 if (toX >= 0 && toY >= 0) {
3910 drawHighlight(toX, toY, prelineGC);
3920 ClearPremoveHighlights()
3922 SetPremoveHighlights(-1, -1, -1, -1);
3925 static void BlankSquare(x, y, color, piece, dest)
3930 if (useImages && useImageSqs) {
3934 pm = xpmLightSquare;
3939 case 2: /* neutral */
3944 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3945 squareSize, squareSize, x, y);
3955 case 2: /* neutral */
3960 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3965 I split out the routines to draw a piece so that I could
3966 make a generic flash routine.
3968 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3970 int square_color, x, y;
3973 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3974 switch (square_color) {
3976 case 2: /* neutral */
3978 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3979 ? *pieceToOutline(piece)
3980 : *pieceToSolid(piece),
3981 dest, bwPieceGC, 0, 0,
3982 squareSize, squareSize, x, y);
3985 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3986 ? *pieceToSolid(piece)
3987 : *pieceToOutline(piece),
3988 dest, wbPieceGC, 0, 0,
3989 squareSize, squareSize, x, y);
3994 static void monoDrawPiece(piece, square_color, x, y, dest)
3996 int square_color, x, y;
3999 switch (square_color) {
4001 case 2: /* neutral */
4003 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4004 ? *pieceToOutline(piece)
4005 : *pieceToSolid(piece),
4006 dest, bwPieceGC, 0, 0,
4007 squareSize, squareSize, x, y, 1);
4010 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4011 ? *pieceToSolid(piece)
4012 : *pieceToOutline(piece),
4013 dest, wbPieceGC, 0, 0,
4014 squareSize, squareSize, x, y, 1);
4019 static void colorDrawPiece(piece, square_color, x, y, dest)
4021 int square_color, x, y;
4024 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4025 switch (square_color) {
4027 XCopyPlane(xDisplay, *pieceToSolid(piece),
4028 dest, (int) piece < (int) BlackPawn
4029 ? wlPieceGC : blPieceGC, 0, 0,
4030 squareSize, squareSize, x, y, 1);
4033 XCopyPlane(xDisplay, *pieceToSolid(piece),
4034 dest, (int) piece < (int) BlackPawn
4035 ? wdPieceGC : bdPieceGC, 0, 0,
4036 squareSize, squareSize, x, y, 1);
4038 case 2: /* neutral */
4040 XCopyPlane(xDisplay, *pieceToSolid(piece),
4041 dest, (int) piece < (int) BlackPawn
4042 ? wjPieceGC : bjPieceGC, 0, 0,
4043 squareSize, squareSize, x, y, 1);
4048 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4050 int square_color, x, y;
4055 switch (square_color) {
4057 case 2: /* neutral */
4059 if ((int)piece < (int) BlackPawn) {
4067 if ((int)piece < (int) BlackPawn) {
4075 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4076 dest, wlPieceGC, 0, 0,
4077 squareSize, squareSize, x, y);
4080 typedef void (*DrawFunc)();
4082 DrawFunc ChooseDrawFunc()
4084 if (appData.monoMode) {
4085 if (DefaultDepth(xDisplay, xScreen) == 1) {
4086 return monoDrawPiece_1bit;
4088 return monoDrawPiece;
4092 return colorDrawPieceImage;
4094 return colorDrawPiece;
4098 /* [HR] determine square color depending on chess variant. */
4099 static int SquareColor(row, column)
4104 if (gameInfo.variant == VariantXiangqi) {
4105 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4107 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4109 } else if (row <= 4) {
4115 square_color = ((column + row) % 2) == 1;
4118 /* [hgm] holdings: next line makes all holdings squares light */
4119 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4121 return square_color;
4124 void DrawSquare(row, column, piece, do_flash)
4125 int row, column, do_flash;
4128 int square_color, x, y, direction, font_ascent, font_descent;
4131 XCharStruct overall;
4135 /* Calculate delay in milliseconds (2-delays per complete flash) */
4136 flash_delay = 500 / appData.flashRate;
4139 x = lineGap + ((BOARD_WIDTH-1)-column) *
4140 (squareSize + lineGap);
4141 y = lineGap + row * (squareSize + lineGap);
4143 x = lineGap + column * (squareSize + lineGap);
4144 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4145 (squareSize + lineGap);
4148 square_color = SquareColor(row, column);
4150 if ( // [HGM] holdings: blank out area between board and holdings
4151 column == BOARD_LEFT-1 || column == BOARD_RGHT
4152 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4153 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4154 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4156 // [HGM] print piece counts next to holdings
4157 string[1] = NULLCHAR;
4158 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4159 string[0] = '0' + piece;
4160 XTextExtents(countFontStruct, string, 1, &direction,
4161 &font_ascent, &font_descent, &overall);
4162 if (appData.monoMode) {
4163 XDrawImageString(xDisplay, xBoardWindow, countGC,
4164 x + squareSize - overall.width - 2,
4165 y + font_ascent + 1, string, 1);
4167 XDrawString(xDisplay, xBoardWindow, countGC,
4168 x + squareSize - overall.width - 2,
4169 y + font_ascent + 1, string, 1);
4172 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4173 string[0] = '0' + piece;
4174 XTextExtents(countFontStruct, string, 1, &direction,
4175 &font_ascent, &font_descent, &overall);
4176 if (appData.monoMode) {
4177 XDrawImageString(xDisplay, xBoardWindow, countGC,
4178 x + 2, y + font_ascent + 1, string, 1);
4180 XDrawString(xDisplay, xBoardWindow, countGC,
4181 x + 2, y + font_ascent + 1, string, 1);
4185 if (piece == EmptySquare || appData.blindfold) {
4186 BlankSquare(x, y, square_color, piece, xBoardWindow);
4188 drawfunc = ChooseDrawFunc();
4189 if (do_flash && appData.flashCount > 0) {
4190 for (i=0; i<appData.flashCount; ++i) {
4192 drawfunc(piece, square_color, x, y, xBoardWindow);
4193 XSync(xDisplay, False);
4194 do_flash_delay(flash_delay);
4196 BlankSquare(x, y, square_color, piece, xBoardWindow);
4197 XSync(xDisplay, False);
4198 do_flash_delay(flash_delay);
4201 drawfunc(piece, square_color, x, y, xBoardWindow);
4205 string[1] = NULLCHAR;
4206 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4207 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4208 string[0] = 'a' + column - BOARD_LEFT;
4209 XTextExtents(coordFontStruct, string, 1, &direction,
4210 &font_ascent, &font_descent, &overall);
4211 if (appData.monoMode) {
4212 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4213 x + squareSize - overall.width - 2,
4214 y + squareSize - font_descent - 1, string, 1);
4216 XDrawString(xDisplay, xBoardWindow, coordGC,
4217 x + squareSize - overall.width - 2,
4218 y + squareSize - font_descent - 1, string, 1);
4221 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4222 string[0] = ONE + row;
4223 XTextExtents(coordFontStruct, string, 1, &direction,
4224 &font_ascent, &font_descent, &overall);
4225 if (appData.monoMode) {
4226 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4227 x + 2, y + font_ascent + 1, string, 1);
4229 XDrawString(xDisplay, xBoardWindow, coordGC,
4230 x + 2, y + font_ascent + 1, string, 1);
4233 if(marker[row][column]) {
4234 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4235 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4240 /* Why is this needed on some versions of X? */
4241 void EventProc(widget, unused, event)
4246 if (!XtIsRealized(widget))
4249 switch (event->type) {
4251 if (event->xexpose.count > 0) return; /* no clipping is done */
4252 XDrawPosition(widget, True, NULL);
4260 void DrawPosition(fullRedraw, board)
4261 /*Boolean*/int fullRedraw;
4264 XDrawPosition(boardWidget, fullRedraw, board);
4267 /* Returns 1 if there are "too many" differences between b1 and b2
4268 (i.e. more than 1 move was made) */
4269 static int too_many_diffs(b1, b2)
4275 for (i=0; i<BOARD_HEIGHT; ++i) {
4276 for (j=0; j<BOARD_WIDTH; ++j) {
4277 if (b1[i][j] != b2[i][j]) {
4278 if (++c > 4) /* Castling causes 4 diffs */
4287 /* Matrix describing castling maneuvers */
4288 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4289 static int castling_matrix[4][5] = {
4290 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4291 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4292 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4293 { 7, 7, 4, 5, 6 } /* 0-0, black */
4296 /* Checks whether castling occurred. If it did, *rrow and *rcol
4297 are set to the destination (row,col) of the rook that moved.
4299 Returns 1 if castling occurred, 0 if not.
4301 Note: Only handles a max of 1 castling move, so be sure
4302 to call too_many_diffs() first.
4304 static int check_castle_draw(newb, oldb, rrow, rcol)
4311 /* For each type of castling... */
4312 for (i=0; i<4; ++i) {
4313 r = castling_matrix[i];
4315 /* Check the 4 squares involved in the castling move */
4317 for (j=1; j<=4; ++j) {
4318 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4325 /* All 4 changed, so it must be a castling move */
4334 static int damage[BOARD_RANKS][BOARD_FILES];
4337 * event handler for redrawing the board
4339 void XDrawPosition(w, repaint, board)
4341 /*Boolean*/int repaint;
4345 static int lastFlipView = 0;
4346 static int lastBoardValid = 0;
4347 static Board lastBoard;
4351 if (board == NULL) {
4352 if (!lastBoardValid) return;
4355 if (!lastBoardValid || lastFlipView != flipView) {
4356 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4357 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4362 * It would be simpler to clear the window with XClearWindow()
4363 * but this causes a very distracting flicker.
4366 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4368 /* If too much changes (begin observing new game, etc.), don't
4370 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4372 /* Special check for castling so we don't flash both the king
4373 and the rook (just flash the king). */
4375 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4376 /* Draw rook with NO flashing. King will be drawn flashing later */
4377 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4378 lastBoard[rrow][rcol] = board[rrow][rcol];
4382 /* First pass -- Draw (newly) empty squares and repair damage.
4383 This prevents you from having a piece show up twice while it
4384 is flashing on its new square */
4385 for (i = 0; i < BOARD_HEIGHT; i++)
4386 for (j = 0; j < BOARD_WIDTH; j++)
4387 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4389 DrawSquare(i, j, board[i][j], 0);
4390 damage[i][j] = False;
4393 /* Second pass -- Draw piece(s) in new position and flash them */
4394 for (i = 0; i < BOARD_HEIGHT; i++)
4395 for (j = 0; j < BOARD_WIDTH; j++)
4396 if (board[i][j] != lastBoard[i][j]) {
4397 DrawSquare(i, j, board[i][j], do_flash);
4401 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4402 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4404 for (i = 0; i < BOARD_HEIGHT; i++)
4405 for (j = 0; j < BOARD_WIDTH; j++) {
4406 DrawSquare(i, j, board[i][j], 0);
4407 damage[i][j] = False;
4411 CopyBoard(lastBoard, board);
4413 lastFlipView = flipView;
4415 /* Draw highlights */
4416 if (pm1X >= 0 && pm1Y >= 0) {
4417 drawHighlight(pm1X, pm1Y, prelineGC);
4419 if (pm2X >= 0 && pm2Y >= 0) {
4420 drawHighlight(pm2X, pm2Y, prelineGC);
4422 if (hi1X >= 0 && hi1Y >= 0) {
4423 drawHighlight(hi1X, hi1Y, highlineGC);
4425 if (hi2X >= 0 && hi2Y >= 0) {
4426 drawHighlight(hi2X, hi2Y, highlineGC);
4429 /* If piece being dragged around board, must redraw that too */
4432 XSync(xDisplay, False);
4437 * event handler for redrawing the board
4439 void DrawPositionProc(w, event, prms, nprms)
4445 XDrawPosition(w, True, NULL);
4450 * event handler for parsing user moves
4452 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4453 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4454 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4455 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4456 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4457 // and at the end FinishMove() to perform the move after optional promotion popups.
4458 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4459 void HandleUserMove(w, event, prms, nprms)
4465 if (w != boardWidget || errorExitStatus != -1) return;
4468 if (event->type == ButtonPress) {
4469 XtPopdown(promotionShell);
4470 XtDestroyWidget(promotionShell);
4471 promotionUp = False;
4479 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4480 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4481 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4484 void AnimateUserMove (Widget w, XEvent * event,
4485 String * params, Cardinal * nParams)
4487 DragPieceMove(event->xmotion.x, event->xmotion.y);
4490 void HandlePV (Widget w, XEvent * event,
4491 String * params, Cardinal * nParams)
4492 { // [HGM] pv: walk PV
4493 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4496 Widget CommentCreate(name, text, mutable, callback, lines)
4498 int /*Boolean*/ mutable;
4499 XtCallbackProc callback;
4503 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4508 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4509 XtGetValues(boardWidget, args, j);
4512 XtSetArg(args[j], XtNresizable, True); j++;
4515 XtCreatePopupShell(name, topLevelShellWidgetClass,
4516 shellWidget, args, j);
4519 XtCreatePopupShell(name, transientShellWidgetClass,
4520 shellWidget, args, j);
4523 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4524 layoutArgs, XtNumber(layoutArgs));
4526 XtCreateManagedWidget("form", formWidgetClass, layout,
4527 formArgs, XtNumber(formArgs));
4531 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4532 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4534 XtSetArg(args[j], XtNstring, text); j++;
4535 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4536 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4537 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4538 XtSetArg(args[j], XtNright, XtChainRight); j++;
4539 XtSetArg(args[j], XtNresizable, True); j++;
4540 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4541 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4542 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4543 XtSetArg(args[j], XtNautoFill, True); j++;
4544 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4546 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4550 XtSetArg(args[j], XtNfromVert, edit); j++;
4551 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4552 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4553 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4554 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4556 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4557 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4560 XtSetArg(args[j], XtNfromVert, edit); j++;
4561 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4562 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4563 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4564 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4565 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4567 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4568 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4571 XtSetArg(args[j], XtNfromVert, edit); j++;
4572 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4573 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4574 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4575 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4576 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4578 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4579 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4582 XtSetArg(args[j], XtNfromVert, edit); j++;
4583 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4584 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4585 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4586 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4588 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4589 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4592 XtSetArg(args[j], XtNfromVert, edit); j++;
4593 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4594 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4595 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4596 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4597 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4599 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4600 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4603 XtRealizeWidget(shell);
4605 if (commentX == -1) {
4608 Dimension pw_height;
4609 Dimension ew_height;
4612 XtSetArg(args[j], XtNheight, &ew_height); j++;
4613 XtGetValues(edit, args, j);
4616 XtSetArg(args[j], XtNheight, &pw_height); j++;
4617 XtGetValues(shell, args, j);
4618 commentH = pw_height + (lines - 1) * ew_height;
4619 commentW = bw_width - 16;
4621 XSync(xDisplay, False);
4623 /* This code seems to tickle an X bug if it is executed too soon
4624 after xboard starts up. The coordinates get transformed as if
4625 the main window was positioned at (0, 0).
4627 XtTranslateCoords(shellWidget,
4628 (bw_width - commentW) / 2, 0 - commentH / 2,
4629 &commentX, &commentY);
4631 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4632 RootWindowOfScreen(XtScreen(shellWidget)),
4633 (bw_width - commentW) / 2, 0 - commentH / 2,
4638 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4641 if(wpComment.width > 0) {
4642 commentX = wpComment.x;
4643 commentY = wpComment.y;
4644 commentW = wpComment.width;
4645 commentH = wpComment.height;
4649 XtSetArg(args[j], XtNheight, commentH); j++;
4650 XtSetArg(args[j], XtNwidth, commentW); j++;
4651 XtSetArg(args[j], XtNx, commentX); j++;
4652 XtSetArg(args[j], XtNy, commentY); j++;
4653 XtSetValues(shell, args, j);
4654 XtSetKeyboardFocus(shell, edit);
4659 /* Used for analysis window and ICS input window */
4660 Widget MiscCreate(name, text, mutable, callback, lines)
4662 int /*Boolean*/ mutable;
4663 XtCallbackProc callback;
4667 Widget shell, layout, form, edit;
4669 Dimension bw_width, pw_height, ew_height, w, h;
4675 XtSetArg(args[j], XtNresizable, True); j++;
4678 XtCreatePopupShell(name, topLevelShellWidgetClass,
4679 shellWidget, args, j);
4682 XtCreatePopupShell(name, transientShellWidgetClass,
4683 shellWidget, args, j);
4686 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4687 layoutArgs, XtNumber(layoutArgs));
4689 XtCreateManagedWidget("form", formWidgetClass, layout,
4690 formArgs, XtNumber(formArgs));
4694 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4695 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4697 XtSetArg(args[j], XtNstring, text); j++;
4698 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4699 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4700 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4701 XtSetArg(args[j], XtNright, XtChainRight); j++;
4702 XtSetArg(args[j], XtNresizable, True); j++;
4703 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4704 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4705 XtSetArg(args[j], XtNautoFill, True); j++;
4706 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4708 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4710 XtRealizeWidget(shell);
4713 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4714 XtGetValues(boardWidget, args, j);
4717 XtSetArg(args[j], XtNheight, &ew_height); j++;
4718 XtGetValues(edit, args, j);
4721 XtSetArg(args[j], XtNheight, &pw_height); j++;
4722 XtGetValues(shell, args, j);
4723 h = pw_height + (lines - 1) * ew_height;
4726 XSync(xDisplay, False);
4728 /* This code seems to tickle an X bug if it is executed too soon
4729 after xboard starts up. The coordinates get transformed as if
4730 the main window was positioned at (0, 0).
4732 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4734 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4735 RootWindowOfScreen(XtScreen(shellWidget)),
4736 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4740 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4743 XtSetArg(args[j], XtNheight, h); j++;
4744 XtSetArg(args[j], XtNwidth, w); j++;
4745 XtSetArg(args[j], XtNx, x); j++;
4746 XtSetArg(args[j], XtNy, y); j++;
4747 XtSetValues(shell, args, j);
4753 static int savedIndex; /* gross that this is global */
4755 void EditCommentPopUp(index, title, text)
4764 if (text == NULL) text = "";
4766 if (editShell == NULL) {
4768 CommentCreate(title, text, True, EditCommentCallback, 4);
4769 XtRealizeWidget(editShell);
4770 CatchDeleteWindow(editShell, "EditCommentPopDown");
4772 edit = XtNameToWidget(editShell, "*form.text");
4774 XtSetArg(args[j], XtNstring, text); j++;
4775 XtSetValues(edit, args, j);
4777 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4778 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4779 XtSetValues(editShell, args, j);
4782 XtPopup(editShell, XtGrabNone);
4786 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4787 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4791 void EditCommentCallback(w, client_data, call_data)
4793 XtPointer client_data, call_data;
4801 XtSetArg(args[j], XtNlabel, &name); j++;
4802 XtGetValues(w, args, j);
4804 if (strcmp(name, _("ok")) == 0) {
4805 edit = XtNameToWidget(editShell, "*form.text");
4807 XtSetArg(args[j], XtNstring, &val); j++;
4808 XtGetValues(edit, args, j);
4809 ReplaceComment(savedIndex, val);
4810 EditCommentPopDown();
4811 } else if (strcmp(name, _("cancel")) == 0) {
4812 EditCommentPopDown();
4813 } else if (strcmp(name, _("clear")) == 0) {
4814 edit = XtNameToWidget(editShell, "*form.text");
4815 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4816 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4820 void EditCommentPopDown()
4825 if (!editUp) return;
4827 XtSetArg(args[j], XtNx, &commentX); j++;
4828 XtSetArg(args[j], XtNy, &commentY); j++;
4829 XtSetArg(args[j], XtNheight, &commentH); j++;
4830 XtSetArg(args[j], XtNwidth, &commentW); j++;
4831 XtGetValues(editShell, args, j);
4832 XtPopdown(editShell);
4835 XtSetArg(args[j], XtNleftBitmap, None); j++;
4836 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4840 void ICSInputBoxPopUp()
4845 char *title = _("ICS Input");
4848 if (ICSInputShell == NULL) {
4849 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4850 tr = XtParseTranslationTable(ICSInputTranslations);
4851 edit = XtNameToWidget(ICSInputShell, "*form.text");
4852 XtOverrideTranslations(edit, tr);
4853 XtRealizeWidget(ICSInputShell);
4854 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4857 edit = XtNameToWidget(ICSInputShell, "*form.text");
4859 XtSetArg(args[j], XtNstring, ""); j++;
4860 XtSetValues(edit, args, j);
4862 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4863 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4864 XtSetValues(ICSInputShell, args, j);
4867 XtPopup(ICSInputShell, XtGrabNone);
4868 XtSetKeyboardFocus(ICSInputShell, edit);
4870 ICSInputBoxUp = True;
4872 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4873 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4877 void ICSInputSendText()
4884 edit = XtNameToWidget(ICSInputShell, "*form.text");
4886 XtSetArg(args[j], XtNstring, &val); j++;
4887 XtGetValues(edit, args, j);
4888 SendMultiLineToICS(val);
4889 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4890 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4893 void ICSInputBoxPopDown()
4898 if (!ICSInputBoxUp) return;
4900 XtPopdown(ICSInputShell);
4901 ICSInputBoxUp = False;
4903 XtSetArg(args[j], XtNleftBitmap, None); j++;
4904 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4908 void CommentPopUp(title, text)
4915 if (commentShell == NULL) {
4917 CommentCreate(title, text, False, CommentCallback, 4);
4918 XtRealizeWidget(commentShell);
4919 CatchDeleteWindow(commentShell, "CommentPopDown");
4921 edit = XtNameToWidget(commentShell, "*form.text");
4923 XtSetArg(args[j], XtNstring, text); j++;
4924 XtSetValues(edit, args, j);
4926 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4927 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4928 XtSetValues(commentShell, args, j);
4931 XtPopup(commentShell, XtGrabNone);
4932 XSync(xDisplay, False);
4937 void CommentCallback(w, client_data, call_data)
4939 XtPointer client_data, call_data;
4946 XtSetArg(args[j], XtNlabel, &name); j++;
4947 XtGetValues(w, args, j);
4949 if (strcmp(name, _("close")) == 0) {
4951 } else if (strcmp(name, _("edit")) == 0) {
4958 void CommentPopDown()
4963 if (!commentUp) return;
4965 XtSetArg(args[j], XtNx, &commentX); j++;
4966 XtSetArg(args[j], XtNy, &commentY); j++;
4967 XtSetArg(args[j], XtNwidth, &commentW); j++;
4968 XtSetArg(args[j], XtNheight, &commentH); j++;
4969 XtGetValues(commentShell, args, j);
4970 XtPopdown(commentShell);
4971 XSync(xDisplay, False);
4975 void FileNamePopUp(label, def, proc, openMode)
4982 Widget popup, layout, dialog, edit;
4988 fileProc = proc; /* I can't see a way not */
4989 fileOpenMode = openMode; /* to use globals here */
4992 XtSetArg(args[i], XtNresizable, True); i++;
4993 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4994 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4995 fileNameShell = popup =
4996 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4997 shellWidget, args, i);
5000 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
5001 layoutArgs, XtNumber(layoutArgs));
5004 XtSetArg(args[i], XtNlabel, label); i++;
5005 XtSetArg(args[i], XtNvalue, def); i++;
5006 XtSetArg(args[i], XtNborderWidth, 0); i++;
5007 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
5010 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
5011 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
5012 (XtPointer) dialog);
5014 XtRealizeWidget(popup);
5015 CatchDeleteWindow(popup, "FileNamePopDown");
5017 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
5018 &x, &y, &win_x, &win_y, &mask);
5020 XtSetArg(args[0], XtNx, x - 10);
5021 XtSetArg(args[1], XtNy, y - 30);
5022 XtSetValues(popup, args, 2);
5024 XtPopup(popup, XtGrabExclusive);
5027 edit = XtNameToWidget(dialog, "*value");
5028 XtSetKeyboardFocus(popup, edit);
5031 void FileNamePopDown()
5033 if (!filenameUp) return;
5034 XtPopdown(fileNameShell);
5035 XtDestroyWidget(fileNameShell);
5040 void FileNameCallback(w, client_data, call_data)
5042 XtPointer client_data, call_data;
5047 XtSetArg(args[0], XtNlabel, &name);
5048 XtGetValues(w, args, 1);
5050 if (strcmp(name, _("cancel")) == 0) {
5055 FileNameAction(w, NULL, NULL, NULL);
5058 void FileNameAction(w, event, prms, nprms)
5070 name = XawDialogGetValueString(w = XtParent(w));
5072 if ((name != NULL) && (*name != NULLCHAR)) {
5074 XtPopdown(w = XtParent(XtParent(w)));
5078 p = strrchr(buf, ' ');
5085 fullname = ExpandPathName(buf);
5087 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5090 f = fopen(fullname, fileOpenMode);
5092 DisplayError(_("Failed to open file"), errno);
5094 (void) (*fileProc)(f, index, buf);
5101 XtPopdown(w = XtParent(XtParent(w)));
5107 void PromotionPopUp()
5110 Widget dialog, layout;
5112 Dimension bw_width, pw_width;
5116 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5117 XtGetValues(boardWidget, args, j);
5120 XtSetArg(args[j], XtNresizable, True); j++;
5121 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5123 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5124 shellWidget, args, j);
5126 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5127 layoutArgs, XtNumber(layoutArgs));
5130 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5131 XtSetArg(args[j], XtNborderWidth, 0); j++;
5132 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5135 if(gameInfo.variant != VariantShogi) {
5136 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5137 (XtPointer) dialog);
5138 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5139 (XtPointer) dialog);
5140 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5141 (XtPointer) dialog);
5142 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5143 (XtPointer) dialog);
5144 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5145 gameInfo.variant == VariantGiveaway) {
5146 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5147 (XtPointer) dialog);
5149 if(gameInfo.variant == VariantCapablanca ||
5150 gameInfo.variant == VariantGothic ||
5151 gameInfo.variant == VariantCapaRandom) {
5152 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5153 (XtPointer) dialog);
5154 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5155 (XtPointer) dialog);
5157 } else // [HGM] shogi
5159 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5160 (XtPointer) dialog);
5161 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5162 (XtPointer) dialog);
5164 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5165 (XtPointer) dialog);
5167 XtRealizeWidget(promotionShell);
5168 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5171 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5172 XtGetValues(promotionShell, args, j);
5174 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5175 lineGap + squareSize/3 +
5176 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5177 0 : 6*(squareSize + lineGap)), &x, &y);
5180 XtSetArg(args[j], XtNx, x); j++;
5181 XtSetArg(args[j], XtNy, y); j++;
5182 XtSetValues(promotionShell, args, j);
5184 XtPopup(promotionShell, XtGrabNone);
5189 void PromotionPopDown()
5191 if (!promotionUp) return;
5192 XtPopdown(promotionShell);
5193 XtDestroyWidget(promotionShell);
5194 promotionUp = False;
5197 void PromotionCallback(w, client_data, call_data)
5199 XtPointer client_data, call_data;
5205 XtSetArg(args[0], XtNlabel, &name);
5206 XtGetValues(w, args, 1);
5210 if (fromX == -1) return;
5212 if (strcmp(name, _("cancel")) == 0) {
5216 } else if (strcmp(name, _("Knight")) == 0) {
5218 } else if (strcmp(name, _("Promote")) == 0) {
5220 } else if (strcmp(name, _("Defer")) == 0) {
5223 promoChar = ToLower(name[0]);
5226 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5228 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5229 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5234 void ErrorCallback(w, client_data, call_data)
5236 XtPointer client_data, call_data;
5239 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5241 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5247 if (!errorUp) return;
5249 XtPopdown(errorShell);
5250 XtDestroyWidget(errorShell);
5251 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5254 void ErrorPopUp(title, label, modal)
5255 char *title, *label;
5259 Widget dialog, layout;
5263 Dimension bw_width, pw_width;
5264 Dimension pw_height;
5268 XtSetArg(args[i], XtNresizable, True); i++;
5269 XtSetArg(args[i], XtNtitle, title); i++;
5271 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5272 shellWidget, args, i);
5274 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5275 layoutArgs, XtNumber(layoutArgs));
5278 XtSetArg(args[i], XtNlabel, label); i++;
5279 XtSetArg(args[i], XtNborderWidth, 0); i++;
5280 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5283 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5285 XtRealizeWidget(errorShell);
5286 CatchDeleteWindow(errorShell, "ErrorPopDown");
5289 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5290 XtGetValues(boardWidget, args, i);
5292 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5293 XtSetArg(args[i], XtNheight, &pw_height); i++;
5294 XtGetValues(errorShell, args, i);
5297 /* This code seems to tickle an X bug if it is executed too soon
5298 after xboard starts up. The coordinates get transformed as if
5299 the main window was positioned at (0, 0).
5301 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5302 0 - pw_height + squareSize / 3, &x, &y);
5304 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5305 RootWindowOfScreen(XtScreen(boardWidget)),
5306 (bw_width - pw_width) / 2,
5307 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5311 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5314 XtSetArg(args[i], XtNx, x); i++;
5315 XtSetArg(args[i], XtNy, y); i++;
5316 XtSetValues(errorShell, args, i);
5319 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5322 /* Disable all user input other than deleting the window */
5323 static int frozen = 0;
5327 /* Grab by a widget that doesn't accept input */
5328 XtAddGrab(messageWidget, TRUE, FALSE);
5332 /* Undo a FreezeUI */
5335 if (!frozen) return;
5336 XtRemoveGrab(messageWidget);
5340 char *ModeToWidgetName(mode)
5344 case BeginningOfGame:
5345 if (appData.icsActive)
5346 return "menuMode.ICS Client";
5347 else if (appData.noChessProgram ||
5348 *appData.cmailGameName != NULLCHAR)
5349 return "menuMode.Edit Game";
5351 return "menuMode.Machine Black";
5352 case MachinePlaysBlack:
5353 return "menuMode.Machine Black";
5354 case MachinePlaysWhite:
5355 return "menuMode.Machine White";
5357 return "menuMode.Analysis Mode";
5359 return "menuMode.Analyze File";
5360 case TwoMachinesPlay:
5361 return "menuMode.Two Machines";
5363 return "menuMode.Edit Game";
5364 case PlayFromGameFile:
5365 return "menuFile.Load Game";
5367 return "menuMode.Edit Position";
5369 return "menuMode.Training";
5370 case IcsPlayingWhite:
5371 case IcsPlayingBlack:
5375 return "menuMode.ICS Client";
5382 void ModeHighlight()
5385 static int oldPausing = FALSE;
5386 static GameMode oldmode = (GameMode) -1;
5389 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5391 if (pausing != oldPausing) {
5392 oldPausing = pausing;
5394 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5396 XtSetArg(args[0], XtNleftBitmap, None);
5398 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5401 if (appData.showButtonBar) {
5402 /* Always toggle, don't set. Previous code messes up when
5403 invoked while the button is pressed, as releasing it
5404 toggles the state again. */
5407 XtSetArg(args[0], XtNbackground, &oldbg);
5408 XtSetArg(args[1], XtNforeground, &oldfg);
5409 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5411 XtSetArg(args[0], XtNbackground, oldfg);
5412 XtSetArg(args[1], XtNforeground, oldbg);
5414 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5418 wname = ModeToWidgetName(oldmode);
5419 if (wname != NULL) {
5420 XtSetArg(args[0], XtNleftBitmap, None);
5421 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5423 wname = ModeToWidgetName(gameMode);
5424 if (wname != NULL) {
5425 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5426 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5430 /* Maybe all the enables should be handled here, not just this one */
5431 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5432 gameMode == Training || gameMode == PlayFromGameFile);
5437 * Button/menu procedures
5439 void ResetProc(w, event, prms, nprms)
5448 int LoadGamePopUp(f, gameNumber, title)
5453 cmailMsgLoaded = FALSE;
5454 if (gameNumber == 0) {
5455 int error = GameListBuild(f);
5457 DisplayError(_("Cannot build game list"), error);
5458 } else if (!ListEmpty(&gameList) &&
5459 ((ListGame *) gameList.tailPred)->number > 1) {
5460 GameListPopUp(f, title);
5466 return LoadGame(f, gameNumber, title, FALSE);
5469 void LoadGameProc(w, event, prms, nprms)
5475 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5478 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5481 void LoadNextGameProc(w, event, prms, nprms)
5490 void LoadPrevGameProc(w, event, prms, nprms)
5499 void ReloadGameProc(w, event, prms, nprms)
5508 void LoadNextPositionProc(w, event, prms, nprms)
5517 void LoadPrevPositionProc(w, event, prms, nprms)
5526 void ReloadPositionProc(w, event, prms, nprms)
5535 void LoadPositionProc(w, event, prms, nprms)
5541 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5544 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5547 void SaveGameProc(w, event, prms, nprms)
5553 FileNamePopUp(_("Save game file name?"),
5554 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5558 void SavePositionProc(w, event, prms, nprms)
5564 FileNamePopUp(_("Save position file name?"),
5565 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5569 void ReloadCmailMsgProc(w, event, prms, nprms)
5575 ReloadCmailMsgEvent(FALSE);
5578 void MailMoveProc(w, event, prms, nprms)
5587 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5588 char *selected_fen_position=NULL;
5591 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5592 Atom *type_return, XtPointer *value_return,
5593 unsigned long *length_return, int *format_return)
5595 char *selection_tmp;
5597 if (!selected_fen_position) return False; /* should never happen */
5598 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5599 /* note: since no XtSelectionDoneProc was registered, Xt will
5600 * automatically call XtFree on the value returned. So have to
5601 * make a copy of it allocated with XtMalloc */
5602 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5603 strcpy(selection_tmp, selected_fen_position);
5605 *value_return=selection_tmp;
5606 *length_return=strlen(selection_tmp);
5607 *type_return=*target;
5608 *format_return = 8; /* bits per byte */
5610 } else if (*target == XA_TARGETS(xDisplay)) {
5611 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5612 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5613 targets_tmp[1] = XA_STRING;
5614 *value_return = targets_tmp;
5615 *type_return = XA_ATOM;
5617 *format_return = 8 * sizeof(Atom);
5618 if (*format_return > 32) {
5619 *length_return *= *format_return / 32;
5620 *format_return = 32;
5628 /* note: when called from menu all parameters are NULL, so no clue what the
5629 * Widget which was clicked on was, or what the click event was
5631 void CopyPositionProc(w, event, prms, nprms)
5638 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5639 * have a notion of a position that is selected but not copied.
5640 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5642 if(gameMode == EditPosition) EditPositionDone(TRUE);
5643 if (selected_fen_position) free(selected_fen_position);
5644 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5645 if (!selected_fen_position) return;
5646 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5648 SendPositionSelection,
5649 NULL/* lose_ownership_proc */ ,
5650 NULL/* transfer_done_proc */);
5651 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5653 SendPositionSelection,
5654 NULL/* lose_ownership_proc */ ,
5655 NULL/* transfer_done_proc */);
5658 /* function called when the data to Paste is ready */
5660 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5661 Atom *type, XtPointer value, unsigned long *len, int *format)
5664 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5665 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5666 EditPositionPasteFEN(fenstr);
5670 /* called when Paste Position button is pressed,
5671 * all parameters will be NULL */
5672 void PastePositionProc(w, event, prms, nprms)
5678 XtGetSelectionValue(menuBarWidget,
5679 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5680 /* (XtSelectionCallbackProc) */ PastePositionCB,
5681 NULL, /* client_data passed to PastePositionCB */
5683 /* better to use the time field from the event that triggered the
5684 * call to this function, but that isn't trivial to get
5692 SendGameSelection(Widget w, Atom *selection, Atom *target,
5693 Atom *type_return, XtPointer *value_return,
5694 unsigned long *length_return, int *format_return)
5696 char *selection_tmp;
5698 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5699 FILE* f = fopen(gameCopyFilename, "r");
5702 if (f == NULL) return False;
5706 selection_tmp = XtMalloc(len + 1);
5707 count = fread(selection_tmp, 1, len, f);
5709 XtFree(selection_tmp);
5712 selection_tmp[len] = NULLCHAR;
5713 *value_return = selection_tmp;
5714 *length_return = len;
5715 *type_return = *target;
5716 *format_return = 8; /* bits per byte */
5718 } else if (*target == XA_TARGETS(xDisplay)) {
5719 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5720 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5721 targets_tmp[1] = XA_STRING;
5722 *value_return = targets_tmp;
5723 *type_return = XA_ATOM;
5725 *format_return = 8 * sizeof(Atom);
5726 if (*format_return > 32) {
5727 *length_return *= *format_return / 32;
5728 *format_return = 32;
5736 /* note: when called from menu all parameters are NULL, so no clue what the
5737 * Widget which was clicked on was, or what the click event was
5739 void CopyGameProc(w, event, prms, nprms)
5747 ret = SaveGameToFile(gameCopyFilename, FALSE);
5751 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5752 * have a notion of a game that is selected but not copied.
5753 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5755 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5758 NULL/* lose_ownership_proc */ ,
5759 NULL/* transfer_done_proc */);
5760 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5763 NULL/* lose_ownership_proc */ ,
5764 NULL/* transfer_done_proc */);
5767 /* function called when the data to Paste is ready */
5769 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5770 Atom *type, XtPointer value, unsigned long *len, int *format)
5773 if (value == NULL || *len == 0) {
5774 return; /* nothing had been selected to copy */
5776 f = fopen(gamePasteFilename, "w");
5778 DisplayError(_("Can't open temp file"), errno);
5781 fwrite(value, 1, *len, f);
5784 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5787 /* called when Paste Game button is pressed,
5788 * all parameters will be NULL */
5789 void PasteGameProc(w, event, prms, nprms)
5795 XtGetSelectionValue(menuBarWidget,
5796 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5797 /* (XtSelectionCallbackProc) */ PasteGameCB,
5798 NULL, /* client_data passed to PasteGameCB */
5800 /* better to use the time field from the event that triggered the
5801 * call to this function, but that isn't trivial to get
5811 SaveGameProc(NULL, NULL, NULL, NULL);
5815 void QuitProc(w, event, prms, nprms)
5824 void PauseProc(w, event, prms, nprms)
5834 void MachineBlackProc(w, event, prms, nprms)
5840 MachineBlackEvent();
5843 void MachineWhiteProc(w, event, prms, nprms)
5849 MachineWhiteEvent();
5852 void AnalyzeModeProc(w, event, prms, nprms)
5860 if (!first.analysisSupport) {
5861 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5862 DisplayError(buf, 0);
5865 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5866 if (appData.icsActive) {
5867 if (gameMode != IcsObserving) {
5868 sprintf(buf,_("You are not observing a game"));
5869 DisplayError(buf, 0);
5871 if (appData.icsEngineAnalyze) {
5872 if (appData.debugMode)
5873 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5879 /* if enable, use want disable icsEngineAnalyze */
5880 if (appData.icsEngineAnalyze) {
5885 appData.icsEngineAnalyze = TRUE;
5886 if (appData.debugMode)
5887 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5889 if (!appData.showThinking)
5890 ShowThinkingProc(w,event,prms,nprms);
5895 void AnalyzeFileProc(w, event, prms, nprms)
5901 if (!first.analysisSupport) {
5903 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5904 DisplayError(buf, 0);
5909 if (!appData.showThinking)
5910 ShowThinkingProc(w,event,prms,nprms);
5913 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5914 AnalysisPeriodicEvent(1);
5917 void TwoMachinesProc(w, event, prms, nprms)
5926 void IcsClientProc(w, event, prms, nprms)
5935 void EditGameProc(w, event, prms, nprms)
5944 void EditPositionProc(w, event, prms, nprms)
5950 EditPositionEvent();
5953 void TrainingProc(w, event, prms, nprms)
5962 void EditCommentProc(w, event, prms, nprms)
5969 EditCommentPopDown();
5975 void IcsInputBoxProc(w, event, prms, nprms)
5981 if (ICSInputBoxUp) {
5982 ICSInputBoxPopDown();
5988 void AcceptProc(w, event, prms, nprms)
5997 void DeclineProc(w, event, prms, nprms)
6006 void RematchProc(w, event, prms, nprms)
6015 void CallFlagProc(w, event, prms, nprms)
6024 void DrawProc(w, event, prms, nprms)
6033 void AbortProc(w, event, prms, nprms)
6042 void AdjournProc(w, event, prms, nprms)
6051 void ResignProc(w, event, prms, nprms)
6060 void AdjuWhiteProc(w, event, prms, nprms)
6066 UserAdjudicationEvent(+1);
6069 void AdjuBlackProc(w, event, prms, nprms)
6075 UserAdjudicationEvent(-1);
6078 void AdjuDrawProc(w, event, prms, nprms)
6084 UserAdjudicationEvent(0);
6087 void EnterKeyProc(w, event, prms, nprms)
6093 if (ICSInputBoxUp == True)
6097 void StopObservingProc(w, event, prms, nprms)
6103 StopObservingEvent();
6106 void StopExaminingProc(w, event, prms, nprms)
6112 StopExaminingEvent();
6116 void ForwardProc(w, event, prms, nprms)
6126 void BackwardProc(w, event, prms, nprms)
6135 void ToStartProc(w, event, prms, nprms)
6144 void ToEndProc(w, event, prms, nprms)
6153 void RevertProc(w, event, prms, nprms)
6162 void TruncateGameProc(w, event, prms, nprms)
6168 TruncateGameEvent();
6170 void RetractMoveProc(w, event, prms, nprms)
6179 void MoveNowProc(w, event, prms, nprms)
6189 void AlwaysQueenProc(w, event, prms, nprms)
6197 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6199 if (appData.alwaysPromoteToQueen) {
6200 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6202 XtSetArg(args[0], XtNleftBitmap, None);
6204 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6208 void AnimateDraggingProc(w, event, prms, nprms)
6216 appData.animateDragging = !appData.animateDragging;
6218 if (appData.animateDragging) {
6219 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6222 XtSetArg(args[0], XtNleftBitmap, None);
6224 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6228 void AnimateMovingProc(w, event, prms, nprms)
6236 appData.animate = !appData.animate;
6238 if (appData.animate) {
6239 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6242 XtSetArg(args[0], XtNleftBitmap, None);
6244 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6248 void AutocommProc(w, event, prms, nprms)
6256 appData.autoComment = !appData.autoComment;
6258 if (appData.autoComment) {
6259 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6261 XtSetArg(args[0], XtNleftBitmap, None);
6263 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6268 void AutoflagProc(w, event, prms, nprms)
6276 appData.autoCallFlag = !appData.autoCallFlag;
6278 if (appData.autoCallFlag) {
6279 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6281 XtSetArg(args[0], XtNleftBitmap, None);
6283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6287 void AutoflipProc(w, event, prms, nprms)
6295 appData.autoFlipView = !appData.autoFlipView;
6297 if (appData.autoFlipView) {
6298 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6300 XtSetArg(args[0], XtNleftBitmap, None);
6302 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6306 void AutobsProc(w, event, prms, nprms)
6314 appData.autoObserve = !appData.autoObserve;
6316 if (appData.autoObserve) {
6317 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6319 XtSetArg(args[0], XtNleftBitmap, None);
6321 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6325 void AutoraiseProc(w, event, prms, nprms)
6333 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6335 if (appData.autoRaiseBoard) {
6336 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6338 XtSetArg(args[0], XtNleftBitmap, None);
6340 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6344 void AutosaveProc(w, event, prms, nprms)
6352 appData.autoSaveGames = !appData.autoSaveGames;
6354 if (appData.autoSaveGames) {
6355 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6357 XtSetArg(args[0], XtNleftBitmap, None);
6359 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6363 void BlindfoldProc(w, event, prms, nprms)
6371 appData.blindfold = !appData.blindfold;
6373 if (appData.blindfold) {
6374 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6376 XtSetArg(args[0], XtNleftBitmap, None);
6378 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6381 DrawPosition(True, NULL);
6384 void TestLegalityProc(w, event, prms, nprms)
6392 appData.testLegality = !appData.testLegality;
6394 if (appData.testLegality) {
6395 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6397 XtSetArg(args[0], XtNleftBitmap, None);
6399 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6404 void FlashMovesProc(w, event, prms, nprms)
6412 if (appData.flashCount == 0) {
6413 appData.flashCount = 3;
6415 appData.flashCount = -appData.flashCount;
6418 if (appData.flashCount > 0) {
6419 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6421 XtSetArg(args[0], XtNleftBitmap, None);
6423 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6427 void FlipViewProc(w, event, prms, nprms)
6433 flipView = !flipView;
6434 DrawPosition(True, NULL);
6437 void GetMoveListProc(w, event, prms, nprms)
6445 appData.getMoveList = !appData.getMoveList;
6447 if (appData.getMoveList) {
6448 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6451 XtSetArg(args[0], XtNleftBitmap, None);
6453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6458 void HighlightDraggingProc(w, event, prms, nprms)
6466 appData.highlightDragging = !appData.highlightDragging;
6468 if (appData.highlightDragging) {
6469 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6471 XtSetArg(args[0], XtNleftBitmap, None);
6473 XtSetValues(XtNameToWidget(menuBarWidget,
6474 "menuOptions.Highlight Dragging"), args, 1);
6478 void HighlightLastMoveProc(w, event, prms, nprms)
6486 appData.highlightLastMove = !appData.highlightLastMove;
6488 if (appData.highlightLastMove) {
6489 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6491 XtSetArg(args[0], XtNleftBitmap, None);
6493 XtSetValues(XtNameToWidget(menuBarWidget,
6494 "menuOptions.Highlight Last Move"), args, 1);
6497 void IcsAlarmProc(w, event, prms, nprms)
6505 appData.icsAlarm = !appData.icsAlarm;
6507 if (appData.icsAlarm) {
6508 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6510 XtSetArg(args[0], XtNleftBitmap, None);
6512 XtSetValues(XtNameToWidget(menuBarWidget,
6513 "menuOptions.ICS Alarm"), args, 1);
6516 void MoveSoundProc(w, event, prms, nprms)
6524 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6526 if (appData.ringBellAfterMoves) {
6527 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6529 XtSetArg(args[0], XtNleftBitmap, None);
6531 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6536 void OldSaveStyleProc(w, event, prms, nprms)
6544 appData.oldSaveStyle = !appData.oldSaveStyle;
6546 if (appData.oldSaveStyle) {
6547 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6549 XtSetArg(args[0], XtNleftBitmap, None);
6551 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6555 void PeriodicUpdatesProc(w, event, prms, nprms)
6563 PeriodicUpdatesEvent(!appData.periodicUpdates);
6565 if (appData.periodicUpdates) {
6566 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6568 XtSetArg(args[0], XtNleftBitmap, None);
6570 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6574 void PonderNextMoveProc(w, event, prms, nprms)
6582 PonderNextMoveEvent(!appData.ponderNextMove);
6584 if (appData.ponderNextMove) {
6585 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6587 XtSetArg(args[0], XtNleftBitmap, None);
6589 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6593 void PopupExitMessageProc(w, event, prms, nprms)
6601 appData.popupExitMessage = !appData.popupExitMessage;
6603 if (appData.popupExitMessage) {
6604 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6606 XtSetArg(args[0], XtNleftBitmap, None);
6608 XtSetValues(XtNameToWidget(menuBarWidget,
6609 "menuOptions.Popup Exit Message"), args, 1);
6612 void PopupMoveErrorsProc(w, event, prms, nprms)
6620 appData.popupMoveErrors = !appData.popupMoveErrors;
6622 if (appData.popupMoveErrors) {
6623 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6625 XtSetArg(args[0], XtNleftBitmap, None);
6627 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6631 void PremoveProc(w, event, prms, nprms)
6639 appData.premove = !appData.premove;
6641 if (appData.premove) {
6642 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6644 XtSetArg(args[0], XtNleftBitmap, None);
6646 XtSetValues(XtNameToWidget(menuBarWidget,
6647 "menuOptions.Premove"), args, 1);
6650 void QuietPlayProc(w, event, prms, nprms)
6658 appData.quietPlay = !appData.quietPlay;
6660 if (appData.quietPlay) {
6661 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6663 XtSetArg(args[0], XtNleftBitmap, None);
6665 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6669 void ShowCoordsProc(w, event, prms, nprms)
6677 appData.showCoords = !appData.showCoords;
6679 if (appData.showCoords) {
6680 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6682 XtSetArg(args[0], XtNleftBitmap, None);
6684 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6687 DrawPosition(True, NULL);
6690 void ShowThinkingProc(w, event, prms, nprms)
6696 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6697 ShowThinkingEvent();
6700 void HideThinkingProc(w, event, prms, nprms)
6708 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6709 ShowThinkingEvent();
6711 if (appData.hideThinkingFromHuman) {
6712 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6714 XtSetArg(args[0], XtNleftBitmap, None);
6716 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6720 void SaveOnExitProc(w, event, prms, nprms)
6728 saveSettingsOnExit = !saveSettingsOnExit;
6730 if (saveSettingsOnExit) {
6731 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6733 XtSetArg(args[0], XtNleftBitmap, None);
6735 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6739 void SaveSettingsProc(w, event, prms, nprms)
6745 SaveSettings(settingsFileName);
6748 void InfoProc(w, event, prms, nprms)
6755 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6760 void ManProc(w, event, prms, nprms)
6768 if (nprms && *nprms > 0)
6772 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6776 void HintProc(w, event, prms, nprms)
6785 void BookProc(w, event, prms, nprms)
6794 void AboutProc(w, event, prms, nprms)
6802 char *zippy = " (with Zippy code)";
6806 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6807 programVersion, zippy,
6808 "Copyright 1991 Digital Equipment Corporation",
6809 "Enhancements Copyright 1992-2009 Free Software Foundation",
6810 "Enhancements Copyright 2005 Alessandro Scotti",
6811 PACKAGE, " is free software and carries NO WARRANTY;",
6812 "see the file COPYING for more information.");
6813 ErrorPopUp(_("About XBoard"), buf, FALSE);
6816 void DebugProc(w, event, prms, nprms)
6822 appData.debugMode = !appData.debugMode;
6825 void AboutGameProc(w, event, prms, nprms)
6834 void NothingProc(w, event, prms, nprms)
6843 void Iconify(w, event, prms, nprms)
6852 XtSetArg(args[0], XtNiconic, True);
6853 XtSetValues(shellWidget, args, 1);
6856 void DisplayMessage(message, extMessage)
6857 char *message, *extMessage;
6859 /* display a message in the message widget */
6868 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6873 message = extMessage;
6877 /* need to test if messageWidget already exists, since this function
6878 can also be called during the startup, if for example a Xresource
6879 is not set up correctly */
6882 XtSetArg(arg, XtNlabel, message);
6883 XtSetValues(messageWidget, &arg, 1);
6889 void DisplayTitle(text)
6894 char title[MSG_SIZ];
6897 if (text == NULL) text = "";
6899 if (appData.titleInWindow) {
6901 XtSetArg(args[i], XtNlabel, text); i++;
6902 XtSetValues(titleWidget, args, i);
6905 if (*text != NULLCHAR) {
6907 strcpy(title, text);
6908 } else if (appData.icsActive) {
6909 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6910 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6911 } else if (appData.cmailGameName[0] != NULLCHAR) {
6912 snprintf(icon, sizeof(icon), "%s", "CMail");
6913 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6915 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6916 } else if (gameInfo.variant == VariantGothic) {
6917 strcpy(icon, programName);
6918 strcpy(title, GOTHIC);
6921 } else if (gameInfo.variant == VariantFalcon) {
6922 strcpy(icon, programName);
6923 strcpy(title, FALCON);
6925 } else if (appData.noChessProgram) {
6926 strcpy(icon, programName);
6927 strcpy(title, programName);
6929 strcpy(icon, first.tidy);
6930 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6933 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6934 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6935 XtSetValues(shellWidget, args, i);
6939 void DisplayError(message, error)
6946 if (appData.debugMode || appData.matchMode) {
6947 fprintf(stderr, "%s: %s\n", programName, message);
6950 if (appData.debugMode || appData.matchMode) {
6951 fprintf(stderr, "%s: %s: %s\n",
6952 programName, message, strerror(error));
6954 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6957 ErrorPopUp(_("Error"), message, FALSE);
6961 void DisplayMoveError(message)
6966 DrawPosition(FALSE, NULL);
6967 if (appData.debugMode || appData.matchMode) {
6968 fprintf(stderr, "%s: %s\n", programName, message);
6970 if (appData.popupMoveErrors) {
6971 ErrorPopUp(_("Error"), message, FALSE);
6973 DisplayMessage(message, "");
6978 void DisplayFatalError(message, error, status)
6984 errorExitStatus = status;
6986 fprintf(stderr, "%s: %s\n", programName, message);
6988 fprintf(stderr, "%s: %s: %s\n",
6989 programName, message, strerror(error));
6990 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6993 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6994 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7000 void DisplayInformation(message)
7004 ErrorPopUp(_("Information"), message, TRUE);
7007 void DisplayNote(message)
7011 ErrorPopUp(_("Note"), message, FALSE);
7015 NullXErrorCheck(dpy, error_event)
7017 XErrorEvent *error_event;
7022 void DisplayIcsInteractionTitle(message)
7025 if (oldICSInteractionTitle == NULL) {
7026 /* Magic to find the old window title, adapted from vim */
7027 char *wina = getenv("WINDOWID");
7029 Window win = (Window) atoi(wina);
7030 Window root, parent, *children;
7031 unsigned int nchildren;
7032 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7034 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7035 if (!XQueryTree(xDisplay, win, &root, &parent,
7036 &children, &nchildren)) break;
7037 if (children) XFree((void *)children);
7038 if (parent == root || parent == 0) break;
7041 XSetErrorHandler(oldHandler);
7043 if (oldICSInteractionTitle == NULL) {
7044 oldICSInteractionTitle = "xterm";
7047 printf("\033]0;%s\007", message);
7051 char pendingReplyPrefix[MSG_SIZ];
7052 ProcRef pendingReplyPR;
7054 void AskQuestionProc(w, event, prms, nprms)
7061 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7065 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7068 void AskQuestionPopDown()
7070 if (!askQuestionUp) return;
7071 XtPopdown(askQuestionShell);
7072 XtDestroyWidget(askQuestionShell);
7073 askQuestionUp = False;
7076 void AskQuestionReplyAction(w, event, prms, nprms)
7086 reply = XawDialogGetValueString(w = XtParent(w));
7087 strcpy(buf, pendingReplyPrefix);
7088 if (*buf) strcat(buf, " ");
7091 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7092 AskQuestionPopDown();
7094 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7097 void AskQuestionCallback(w, client_data, call_data)
7099 XtPointer client_data, call_data;
7104 XtSetArg(args[0], XtNlabel, &name);
7105 XtGetValues(w, args, 1);
7107 if (strcmp(name, _("cancel")) == 0) {
7108 AskQuestionPopDown();
7110 AskQuestionReplyAction(w, NULL, NULL, NULL);
7114 void AskQuestion(title, question, replyPrefix, pr)
7115 char *title, *question, *replyPrefix;
7119 Widget popup, layout, dialog, edit;
7125 strcpy(pendingReplyPrefix, replyPrefix);
7126 pendingReplyPR = pr;
7129 XtSetArg(args[i], XtNresizable, True); i++;
7130 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7131 askQuestionShell = popup =
7132 XtCreatePopupShell(title, transientShellWidgetClass,
7133 shellWidget, args, i);
7136 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7137 layoutArgs, XtNumber(layoutArgs));
7140 XtSetArg(args[i], XtNlabel, question); i++;
7141 XtSetArg(args[i], XtNvalue, ""); i++;
7142 XtSetArg(args[i], XtNborderWidth, 0); i++;
7143 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7146 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7147 (XtPointer) dialog);
7148 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7149 (XtPointer) dialog);
7151 XtRealizeWidget(popup);
7152 CatchDeleteWindow(popup, "AskQuestionPopDown");
7154 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7155 &x, &y, &win_x, &win_y, &mask);
7157 XtSetArg(args[0], XtNx, x - 10);
7158 XtSetArg(args[1], XtNy, y - 30);
7159 XtSetValues(popup, args, 2);
7161 XtPopup(popup, XtGrabExclusive);
7162 askQuestionUp = True;
7164 edit = XtNameToWidget(dialog, "*value");
7165 XtSetKeyboardFocus(popup, edit);
7173 if (*name == NULLCHAR) {
7175 } else if (strcmp(name, "$") == 0) {
7176 putc(BELLCHAR, stderr);
7179 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7187 PlaySound(appData.soundMove);
7193 PlaySound(appData.soundIcsWin);
7199 PlaySound(appData.soundIcsLoss);
7205 PlaySound(appData.soundIcsDraw);
7209 PlayIcsUnfinishedSound()
7211 PlaySound(appData.soundIcsUnfinished);
7217 PlaySound(appData.soundIcsAlarm);
7223 system("stty echo");
7229 system("stty -echo");
7233 Colorize(cc, continuation)
7238 int count, outCount, error;
7240 if (textColors[(int)cc].bg > 0) {
7241 if (textColors[(int)cc].fg > 0) {
7242 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7243 textColors[(int)cc].fg, textColors[(int)cc].bg);
7245 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7246 textColors[(int)cc].bg);
7249 if (textColors[(int)cc].fg > 0) {
7250 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7251 textColors[(int)cc].fg);
7253 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7256 count = strlen(buf);
7257 outCount = OutputToProcess(NoProc, buf, count, &error);
7258 if (outCount < count) {
7259 DisplayFatalError(_("Error writing to display"), error, 1);
7262 if (continuation) return;
7265 PlaySound(appData.soundShout);
7268 PlaySound(appData.soundSShout);
7271 PlaySound(appData.soundChannel1);
7274 PlaySound(appData.soundChannel);
7277 PlaySound(appData.soundKibitz);
7280 PlaySound(appData.soundTell);
7282 case ColorChallenge:
7283 PlaySound(appData.soundChallenge);
7286 PlaySound(appData.soundRequest);
7289 PlaySound(appData.soundSeek);
7300 return getpwuid(getuid())->pw_name;
7303 static char *ExpandPathName(path)
7306 static char static_buf[2000];
7307 char *d, *s, buf[2000];
7313 while (*s && isspace(*s))
7322 if (*(s+1) == '/') {
7323 strcpy(d, getpwuid(getuid())->pw_dir);
7328 *strchr(buf, '/') = 0;
7329 pwd = getpwnam(buf);
7332 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7336 strcpy(d, pwd->pw_dir);
7337 strcat(d, strchr(s+1, '/'));
7348 static char host_name[MSG_SIZ];
7350 #if HAVE_GETHOSTNAME
7351 gethostname(host_name, MSG_SIZ);
7353 #else /* not HAVE_GETHOSTNAME */
7354 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7355 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7357 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7359 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7360 #endif /* not HAVE_GETHOSTNAME */
7363 XtIntervalId delayedEventTimerXID = 0;
7364 DelayedEventCallback delayedEventCallback = 0;
7369 delayedEventTimerXID = 0;
7370 delayedEventCallback();
7374 ScheduleDelayedEvent(cb, millisec)
7375 DelayedEventCallback cb; long millisec;
7377 if(delayedEventTimerXID && delayedEventCallback == cb)
7378 // [HGM] alive: replace, rather than add or flush identical event
7379 XtRemoveTimeOut(delayedEventTimerXID);
7380 delayedEventCallback = cb;
7381 delayedEventTimerXID =
7382 XtAppAddTimeOut(appContext, millisec,
7383 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7386 DelayedEventCallback
7389 if (delayedEventTimerXID) {
7390 return delayedEventCallback;
7397 CancelDelayedEvent()
7399 if (delayedEventTimerXID) {
7400 XtRemoveTimeOut(delayedEventTimerXID);
7401 delayedEventTimerXID = 0;
7405 XtIntervalId loadGameTimerXID = 0;
7407 int LoadGameTimerRunning()
7409 return loadGameTimerXID != 0;
7412 int StopLoadGameTimer()
7414 if (loadGameTimerXID != 0) {
7415 XtRemoveTimeOut(loadGameTimerXID);
7416 loadGameTimerXID = 0;
7424 LoadGameTimerCallback(arg, id)
7428 loadGameTimerXID = 0;
7433 StartLoadGameTimer(millisec)
7437 XtAppAddTimeOut(appContext, millisec,
7438 (XtTimerCallbackProc) LoadGameTimerCallback,
7442 XtIntervalId analysisClockXID = 0;
7445 AnalysisClockCallback(arg, id)
7449 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7450 || appData.icsEngineAnalyze) { // [DM]
7451 AnalysisPeriodicEvent(0);
7452 StartAnalysisClock();
7457 StartAnalysisClock()
7460 XtAppAddTimeOut(appContext, 2000,
7461 (XtTimerCallbackProc) AnalysisClockCallback,
7465 XtIntervalId clockTimerXID = 0;
7467 int ClockTimerRunning()
7469 return clockTimerXID != 0;
7472 int StopClockTimer()
7474 if (clockTimerXID != 0) {
7475 XtRemoveTimeOut(clockTimerXID);
7484 ClockTimerCallback(arg, id)
7493 StartClockTimer(millisec)
7497 XtAppAddTimeOut(appContext, millisec,
7498 (XtTimerCallbackProc) ClockTimerCallback,
7503 DisplayTimerLabel(w, color, timer, highlight)
7512 /* check for low time warning */
7513 Pixel foregroundOrWarningColor = timerForegroundPixel;
7516 appData.lowTimeWarning &&
7517 (timer / 1000) < appData.icsAlarmTime)
7518 foregroundOrWarningColor = lowTimeWarningColor;
7520 if (appData.clockMode) {
7521 sprintf(buf, "%s: %s", color, TimeString(timer));
7522 XtSetArg(args[0], XtNlabel, buf);
7524 sprintf(buf, "%s ", color);
7525 XtSetArg(args[0], XtNlabel, buf);
7530 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7531 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7533 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7534 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7537 XtSetValues(w, args, 3);
7541 DisplayWhiteClock(timeRemaining, highlight)
7547 if(appData.noGUI) return;
7548 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7549 if (highlight && iconPixmap == bIconPixmap) {
7550 iconPixmap = wIconPixmap;
7551 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7552 XtSetValues(shellWidget, args, 1);
7557 DisplayBlackClock(timeRemaining, highlight)
7563 if(appData.noGUI) return;
7564 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7565 if (highlight && iconPixmap == wIconPixmap) {
7566 iconPixmap = bIconPixmap;
7567 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7568 XtSetValues(shellWidget, args, 1);
7586 int StartChildProcess(cmdLine, dir, pr)
7593 int to_prog[2], from_prog[2];
7597 if (appData.debugMode) {
7598 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7601 /* We do NOT feed the cmdLine to the shell; we just
7602 parse it into blank-separated arguments in the
7603 most simple-minded way possible.
7606 strcpy(buf, cmdLine);
7609 while(*p == ' ') p++;
7611 if(*p == '"' || *p == '\'')
7612 p = strchr(++argv[i-1], *p);
7613 else p = strchr(p, ' ');
7614 if (p == NULL) break;
7619 SetUpChildIO(to_prog, from_prog);
7621 if ((pid = fork()) == 0) {
7623 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7624 close(to_prog[1]); // first close the unused pipe ends
7625 close(from_prog[0]);
7626 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7627 dup2(from_prog[1], 1);
7628 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7629 close(from_prog[1]); // and closing again loses one of the pipes!
7630 if(fileno(stderr) >= 2) // better safe than sorry...
7631 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7633 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7638 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7640 execvp(argv[0], argv);
7642 /* If we get here, exec failed */
7647 /* Parent process */
7649 close(from_prog[1]);
7651 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7654 cp->fdFrom = from_prog[0];
7655 cp->fdTo = to_prog[1];
7660 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7661 static RETSIGTYPE AlarmCallBack(int n)
7667 DestroyChildProcess(pr, signalType)
7671 ChildProc *cp = (ChildProc *) pr;
7673 if (cp->kind != CPReal) return;
7675 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7676 signal(SIGALRM, AlarmCallBack);
7678 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7679 kill(cp->pid, SIGKILL); // kill it forcefully
7680 wait((int *) 0); // and wait again
7684 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7686 /* Process is exiting either because of the kill or because of
7687 a quit command sent by the backend; either way, wait for it to die.
7696 InterruptChildProcess(pr)
7699 ChildProc *cp = (ChildProc *) pr;
7701 if (cp->kind != CPReal) return;
7702 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7705 int OpenTelnet(host, port, pr)
7710 char cmdLine[MSG_SIZ];
7712 if (port[0] == NULLCHAR) {
7713 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7715 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7717 return StartChildProcess(cmdLine, "", pr);
7720 int OpenTCP(host, port, pr)
7726 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7727 #else /* !OMIT_SOCKETS */
7729 struct sockaddr_in sa;
7731 unsigned short uport;
7734 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7738 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7739 sa.sin_family = AF_INET;
7740 sa.sin_addr.s_addr = INADDR_ANY;
7741 uport = (unsigned short) 0;
7742 sa.sin_port = htons(uport);
7743 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7747 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7748 if (!(hp = gethostbyname(host))) {
7750 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7751 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7752 hp->h_addrtype = AF_INET;
7754 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7755 hp->h_addr_list[0] = (char *) malloc(4);
7756 hp->h_addr_list[0][0] = b0;
7757 hp->h_addr_list[0][1] = b1;
7758 hp->h_addr_list[0][2] = b2;
7759 hp->h_addr_list[0][3] = b3;
7764 sa.sin_family = hp->h_addrtype;
7765 uport = (unsigned short) atoi(port);
7766 sa.sin_port = htons(uport);
7767 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7769 if (connect(s, (struct sockaddr *) &sa,
7770 sizeof(struct sockaddr_in)) < 0) {
7774 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7781 #endif /* !OMIT_SOCKETS */
7786 int OpenCommPort(name, pr)
7793 fd = open(name, 2, 0);
7794 if (fd < 0) return errno;
7796 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7806 int OpenLoopback(pr)
7812 SetUpChildIO(to, from);
7814 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7817 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7824 int OpenRcmd(host, user, cmd, pr)
7825 char *host, *user, *cmd;
7828 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7832 #define INPUT_SOURCE_BUF_SIZE 8192
7841 char buf[INPUT_SOURCE_BUF_SIZE];
7846 DoInputCallback(closure, source, xid)
7851 InputSource *is = (InputSource *) closure;
7856 if (is->lineByLine) {
7857 count = read(is->fd, is->unused,
7858 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7860 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7863 is->unused += count;
7865 while (p < is->unused) {
7866 q = memchr(p, '\n', is->unused - p);
7867 if (q == NULL) break;
7869 (is->func)(is, is->closure, p, q - p, 0);
7873 while (p < is->unused) {
7878 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7883 (is->func)(is, is->closure, is->buf, count, error);
7887 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7894 ChildProc *cp = (ChildProc *) pr;
7896 is = (InputSource *) calloc(1, sizeof(InputSource));
7897 is->lineByLine = lineByLine;
7901 is->fd = fileno(stdin);
7903 is->kind = cp->kind;
7904 is->fd = cp->fdFrom;
7907 is->unused = is->buf;
7910 is->xid = XtAppAddInput(appContext, is->fd,
7911 (XtPointer) (XtInputReadMask),
7912 (XtInputCallbackProc) DoInputCallback,
7914 is->closure = closure;
7915 return (InputSourceRef) is;
7919 RemoveInputSource(isr)
7922 InputSource *is = (InputSource *) isr;
7924 if (is->xid == 0) return;
7925 XtRemoveInput(is->xid);
7929 int OutputToProcess(pr, message, count, outError)
7935 static int line = 0;
7936 ChildProc *cp = (ChildProc *) pr;
7941 if (appData.noJoin || !appData.useInternalWrap)
7942 outCount = fwrite(message, 1, count, stdout);
7945 int width = get_term_width();
7946 int len = wrap(NULL, message, count, width, &line);
7947 char *msg = malloc(len);
7951 outCount = fwrite(message, 1, count, stdout);
7954 dbgchk = wrap(msg, message, count, width, &line);
7955 if (dbgchk != len && appData.debugMode)
7956 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7957 outCount = fwrite(msg, 1, dbgchk, stdout);
7963 outCount = write(cp->fdTo, message, count);
7973 /* Output message to process, with "ms" milliseconds of delay
7974 between each character. This is needed when sending the logon
7975 script to ICC, which for some reason doesn't like the
7976 instantaneous send. */
7977 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7984 ChildProc *cp = (ChildProc *) pr;
7989 r = write(cp->fdTo, message++, 1);
8002 /**** Animation code by Hugh Fisher, DCS, ANU.
8004 Known problem: if a window overlapping the board is
8005 moved away while a piece is being animated underneath,
8006 the newly exposed area won't be updated properly.
8007 I can live with this.
8009 Known problem: if you look carefully at the animation
8010 of pieces in mono mode, they are being drawn as solid
8011 shapes without interior detail while moving. Fixing
8012 this would be a major complication for minimal return.
8015 /* Masks for XPM pieces. Black and white pieces can have
8016 different shapes, but in the interest of retaining my
8017 sanity pieces must have the same outline on both light
8018 and dark squares, and all pieces must use the same
8019 background square colors/images. */
8021 static int xpmDone = 0;
8024 CreateAnimMasks (pieceDepth)
8031 unsigned long plane;
8034 /* Need a bitmap just to get a GC with right depth */
8035 buf = XCreatePixmap(xDisplay, xBoardWindow,
8037 values.foreground = 1;
8038 values.background = 0;
8039 /* Don't use XtGetGC, not read only */
8040 maskGC = XCreateGC(xDisplay, buf,
8041 GCForeground | GCBackground, &values);
8042 XFreePixmap(xDisplay, buf);
8044 buf = XCreatePixmap(xDisplay, xBoardWindow,
8045 squareSize, squareSize, pieceDepth);
8046 values.foreground = XBlackPixel(xDisplay, xScreen);
8047 values.background = XWhitePixel(xDisplay, xScreen);
8048 bufGC = XCreateGC(xDisplay, buf,
8049 GCForeground | GCBackground, &values);
8051 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8052 /* Begin with empty mask */
8053 if(!xpmDone) // [HGM] pieces: keep using existing
8054 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8055 squareSize, squareSize, 1);
8056 XSetFunction(xDisplay, maskGC, GXclear);
8057 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8058 0, 0, squareSize, squareSize);
8060 /* Take a copy of the piece */
8065 XSetFunction(xDisplay, bufGC, GXcopy);
8066 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8068 0, 0, squareSize, squareSize, 0, 0);
8070 /* XOR the background (light) over the piece */
8071 XSetFunction(xDisplay, bufGC, GXxor);
8073 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8074 0, 0, squareSize, squareSize, 0, 0);
8076 XSetForeground(xDisplay, bufGC, lightSquareColor);
8077 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8080 /* We now have an inverted piece image with the background
8081 erased. Construct mask by just selecting all the non-zero
8082 pixels - no need to reconstruct the original image. */
8083 XSetFunction(xDisplay, maskGC, GXor);
8085 /* Might be quicker to download an XImage and create bitmap
8086 data from it rather than this N copies per piece, but it
8087 only takes a fraction of a second and there is a much
8088 longer delay for loading the pieces. */
8089 for (n = 0; n < pieceDepth; n ++) {
8090 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8091 0, 0, squareSize, squareSize,
8097 XFreePixmap(xDisplay, buf);
8098 XFreeGC(xDisplay, bufGC);
8099 XFreeGC(xDisplay, maskGC);
8103 InitAnimState (anim, info)
8105 XWindowAttributes * info;
8110 /* Each buffer is square size, same depth as window */
8111 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8112 squareSize, squareSize, info->depth);
8113 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8114 squareSize, squareSize, info->depth);
8116 /* Create a plain GC for blitting */
8117 mask = GCForeground | GCBackground | GCFunction |
8118 GCPlaneMask | GCGraphicsExposures;
8119 values.foreground = XBlackPixel(xDisplay, xScreen);
8120 values.background = XWhitePixel(xDisplay, xScreen);
8121 values.function = GXcopy;
8122 values.plane_mask = AllPlanes;
8123 values.graphics_exposures = False;
8124 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8126 /* Piece will be copied from an existing context at
8127 the start of each new animation/drag. */
8128 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8130 /* Outline will be a read-only copy of an existing */
8131 anim->outlineGC = None;
8137 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8138 XWindowAttributes info;
8140 if (xpmDone && gameInfo.variant == old) return;
8141 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8142 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8144 InitAnimState(&game, &info);
8145 InitAnimState(&player, &info);
8147 /* For XPM pieces, we need bitmaps to use as masks. */
8149 CreateAnimMasks(info.depth);
8155 static Boolean frameWaiting;
8157 static RETSIGTYPE FrameAlarm (sig)
8160 frameWaiting = False;
8161 /* In case System-V style signals. Needed?? */
8162 signal(SIGALRM, FrameAlarm);
8169 struct itimerval delay;
8171 XSync(xDisplay, False);
8174 frameWaiting = True;
8175 signal(SIGALRM, FrameAlarm);
8176 delay.it_interval.tv_sec =
8177 delay.it_value.tv_sec = time / 1000;
8178 delay.it_interval.tv_usec =
8179 delay.it_value.tv_usec = (time % 1000) * 1000;
8180 setitimer(ITIMER_REAL, &delay, NULL);
8181 while (frameWaiting) pause();
8182 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8183 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8184 setitimer(ITIMER_REAL, &delay, NULL);
8194 XSync(xDisplay, False);
8196 usleep(time * 1000);
8201 /* Convert board position to corner of screen rect and color */
8204 ScreenSquare(column, row, pt, color)
8205 int column; int row; XPoint * pt; int * color;
8208 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8209 pt->y = lineGap + row * (squareSize + lineGap);
8211 pt->x = lineGap + column * (squareSize + lineGap);
8212 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8214 *color = SquareColor(row, column);
8217 /* Convert window coords to square */
8220 BoardSquare(x, y, column, row)
8221 int x; int y; int * column; int * row;
8223 *column = EventToSquare(x, BOARD_WIDTH);
8224 if (flipView && *column >= 0)
8225 *column = BOARD_WIDTH - 1 - *column;
8226 *row = EventToSquare(y, BOARD_HEIGHT);
8227 if (!flipView && *row >= 0)
8228 *row = BOARD_HEIGHT - 1 - *row;
8233 #undef Max /* just in case */
8235 #define Max(a, b) ((a) > (b) ? (a) : (b))
8236 #define Min(a, b) ((a) < (b) ? (a) : (b))
8239 SetRect(rect, x, y, width, height)
8240 XRectangle * rect; int x; int y; int width; int height;
8244 rect->width = width;
8245 rect->height = height;
8248 /* Test if two frames overlap. If they do, return
8249 intersection rect within old and location of
8250 that rect within new. */
8253 Intersect(old, new, size, area, pt)
8254 XPoint * old; XPoint * new;
8255 int size; XRectangle * area; XPoint * pt;
8257 if (old->x > new->x + size || new->x > old->x + size ||
8258 old->y > new->y + size || new->y > old->y + size) {
8261 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8262 size - abs(old->x - new->x), size - abs(old->y - new->y));
8263 pt->x = Max(old->x - new->x, 0);
8264 pt->y = Max(old->y - new->y, 0);
8269 /* For two overlapping frames, return the rect(s)
8270 in the old that do not intersect with the new. */
8273 CalcUpdateRects(old, new, size, update, nUpdates)
8274 XPoint * old; XPoint * new; int size;
8275 XRectangle update[]; int * nUpdates;
8279 /* If old = new (shouldn't happen) then nothing to draw */
8280 if (old->x == new->x && old->y == new->y) {
8284 /* Work out what bits overlap. Since we know the rects
8285 are the same size we don't need a full intersect calc. */
8287 /* Top or bottom edge? */
8288 if (new->y > old->y) {
8289 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8291 } else if (old->y > new->y) {
8292 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8293 size, old->y - new->y);
8296 /* Left or right edge - don't overlap any update calculated above. */
8297 if (new->x > old->x) {
8298 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8299 new->x - old->x, size - abs(new->y - old->y));
8301 } else if (old->x > new->x) {
8302 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8303 old->x - new->x, size - abs(new->y - old->y));
8310 /* Generate a series of frame coords from start->mid->finish.
8311 The movement rate doubles until the half way point is
8312 reached, then halves back down to the final destination,
8313 which gives a nice slow in/out effect. The algorithmn
8314 may seem to generate too many intermediates for short
8315 moves, but remember that the purpose is to attract the
8316 viewers attention to the piece about to be moved and
8317 then to where it ends up. Too few frames would be less
8321 Tween(start, mid, finish, factor, frames, nFrames)
8322 XPoint * start; XPoint * mid;
8323 XPoint * finish; int factor;
8324 XPoint frames[]; int * nFrames;
8326 int fraction, n, count;
8330 /* Slow in, stepping 1/16th, then 1/8th, ... */
8332 for (n = 0; n < factor; n++)
8334 for (n = 0; n < factor; n++) {
8335 frames[count].x = start->x + (mid->x - start->x) / fraction;
8336 frames[count].y = start->y + (mid->y - start->y) / fraction;
8338 fraction = fraction / 2;
8342 frames[count] = *mid;
8345 /* Slow out, stepping 1/2, then 1/4, ... */
8347 for (n = 0; n < factor; n++) {
8348 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8349 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8351 fraction = fraction * 2;
8356 /* Draw a piece on the screen without disturbing what's there */
8359 SelectGCMask(piece, clip, outline, mask)
8360 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8364 /* Bitmap for piece being moved. */
8365 if (appData.monoMode) {
8366 *mask = *pieceToSolid(piece);
8367 } else if (useImages) {
8369 *mask = xpmMask[piece];
8371 *mask = ximMaskPm[piece];
8374 *mask = *pieceToSolid(piece);
8377 /* GC for piece being moved. Square color doesn't matter, but
8378 since it gets modified we make a copy of the original. */
8380 if (appData.monoMode)
8385 if (appData.monoMode)
8390 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8392 /* Outline only used in mono mode and is not modified */
8394 *outline = bwPieceGC;
8396 *outline = wbPieceGC;
8400 OverlayPiece(piece, clip, outline, dest)
8401 ChessSquare piece; GC clip; GC outline; Drawable dest;
8406 /* Draw solid rectangle which will be clipped to shape of piece */
8407 XFillRectangle(xDisplay, dest, clip,
8408 0, 0, squareSize, squareSize);
8409 if (appData.monoMode)
8410 /* Also draw outline in contrasting color for black
8411 on black / white on white cases */
8412 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8413 0, 0, squareSize, squareSize, 0, 0, 1);
8415 /* Copy the piece */
8420 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8422 0, 0, squareSize, squareSize,
8427 /* Animate the movement of a single piece */
8430 BeginAnimation(anim, piece, startColor, start)
8438 /* The old buffer is initialised with the start square (empty) */
8439 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8440 anim->prevFrame = *start;
8442 /* The piece will be drawn using its own bitmap as a matte */
8443 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8444 XSetClipMask(xDisplay, anim->pieceGC, mask);
8448 AnimationFrame(anim, frame, piece)
8453 XRectangle updates[4];
8458 /* Save what we are about to draw into the new buffer */
8459 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8460 frame->x, frame->y, squareSize, squareSize,
8463 /* Erase bits of the previous frame */
8464 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8465 /* Where the new frame overlapped the previous,
8466 the contents in newBuf are wrong. */
8467 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8468 overlap.x, overlap.y,
8469 overlap.width, overlap.height,
8471 /* Repaint the areas in the old that don't overlap new */
8472 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8473 for (i = 0; i < count; i++)
8474 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8475 updates[i].x - anim->prevFrame.x,
8476 updates[i].y - anim->prevFrame.y,
8477 updates[i].width, updates[i].height,
8478 updates[i].x, updates[i].y);
8480 /* Easy when no overlap */
8481 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8482 0, 0, squareSize, squareSize,
8483 anim->prevFrame.x, anim->prevFrame.y);
8486 /* Save this frame for next time round */
8487 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8488 0, 0, squareSize, squareSize,
8490 anim->prevFrame = *frame;
8492 /* Draw piece over original screen contents, not current,
8493 and copy entire rect. Wipes out overlapping piece images. */
8494 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8495 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8496 0, 0, squareSize, squareSize,
8497 frame->x, frame->y);
8501 EndAnimation (anim, finish)
8505 XRectangle updates[4];
8510 /* The main code will redraw the final square, so we
8511 only need to erase the bits that don't overlap. */
8512 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8513 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8514 for (i = 0; i < count; i++)
8515 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8516 updates[i].x - anim->prevFrame.x,
8517 updates[i].y - anim->prevFrame.y,
8518 updates[i].width, updates[i].height,
8519 updates[i].x, updates[i].y);
8521 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8522 0, 0, squareSize, squareSize,
8523 anim->prevFrame.x, anim->prevFrame.y);
8528 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8530 ChessSquare piece; int startColor;
8531 XPoint * start; XPoint * finish;
8532 XPoint frames[]; int nFrames;
8536 BeginAnimation(anim, piece, startColor, start);
8537 for (n = 0; n < nFrames; n++) {
8538 AnimationFrame(anim, &(frames[n]), piece);
8539 FrameDelay(appData.animSpeed);
8541 EndAnimation(anim, finish);
8544 /* Main control logic for deciding what to animate and how */
8547 AnimateMove(board, fromX, fromY, toX, toY)
8556 XPoint start, finish, mid;
8557 XPoint frames[kFactor * 2 + 1];
8558 int nFrames, startColor, endColor;
8560 /* Are we animating? */
8561 if (!appData.animate || appData.blindfold)
8564 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8565 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8566 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8568 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8569 piece = board[fromY][fromX];
8570 if (piece >= EmptySquare) return;
8575 hop = (piece == WhiteKnight || piece == BlackKnight);
8578 if (appData.debugMode) {
8579 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8580 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8581 piece, fromX, fromY, toX, toY); }
8583 ScreenSquare(fromX, fromY, &start, &startColor);
8584 ScreenSquare(toX, toY, &finish, &endColor);
8587 /* Knight: make diagonal movement then straight */
8588 if (abs(toY - fromY) < abs(toX - fromX)) {
8589 mid.x = start.x + (finish.x - start.x) / 2;
8593 mid.y = start.y + (finish.y - start.y) / 2;
8596 mid.x = start.x + (finish.x - start.x) / 2;
8597 mid.y = start.y + (finish.y - start.y) / 2;
8600 /* Don't use as many frames for very short moves */
8601 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8602 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8604 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8605 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8607 /* Be sure end square is redrawn */
8608 damage[toY][toX] = True;
8612 DragPieceBegin(x, y)
8615 int boardX, boardY, color;
8618 /* Are we animating? */
8619 if (!appData.animateDragging || appData.blindfold)
8622 /* Figure out which square we start in and the
8623 mouse position relative to top left corner. */
8624 BoardSquare(x, y, &boardX, &boardY);
8625 player.startBoardX = boardX;
8626 player.startBoardY = boardY;
8627 ScreenSquare(boardX, boardY, &corner, &color);
8628 player.startSquare = corner;
8629 player.startColor = color;
8630 /* As soon as we start dragging, the piece will jump slightly to
8631 be centered over the mouse pointer. */
8632 player.mouseDelta.x = squareSize/2;
8633 player.mouseDelta.y = squareSize/2;
8634 /* Initialise animation */
8635 player.dragPiece = PieceForSquare(boardX, boardY);
8637 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8638 player.dragActive = True;
8639 BeginAnimation(&player, player.dragPiece, color, &corner);
8640 /* Mark this square as needing to be redrawn. Note that
8641 we don't remove the piece though, since logically (ie
8642 as seen by opponent) the move hasn't been made yet. */
8643 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8644 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8645 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8646 corner.x, corner.y, squareSize, squareSize,
8647 0, 0); // [HGM] zh: unstack in stead of grab
8648 damage[boardY][boardX] = True;
8650 player.dragActive = False;
8660 /* Are we animating? */
8661 if (!appData.animateDragging || appData.blindfold)
8665 if (! player.dragActive)
8667 /* Move piece, maintaining same relative position
8668 of mouse within square */
8669 corner.x = x - player.mouseDelta.x;
8670 corner.y = y - player.mouseDelta.y;
8671 AnimationFrame(&player, &corner, player.dragPiece);
8673 if (appData.highlightDragging) {
8675 BoardSquare(x, y, &boardX, &boardY);
8676 SetHighlights(fromX, fromY, boardX, boardY);
8685 int boardX, boardY, color;
8688 /* Are we animating? */
8689 if (!appData.animateDragging || appData.blindfold)
8693 if (! player.dragActive)
8695 /* Last frame in sequence is square piece is
8696 placed on, which may not match mouse exactly. */
8697 BoardSquare(x, y, &boardX, &boardY);
8698 ScreenSquare(boardX, boardY, &corner, &color);
8699 EndAnimation(&player, &corner);
8701 /* Be sure end square is redrawn */
8702 damage[boardY][boardX] = True;
8704 /* This prevents weird things happening with fast successive
8705 clicks which on my Sun at least can cause motion events
8706 without corresponding press/release. */
8707 player.dragActive = False;
8710 /* Handle expose event while piece being dragged */
8715 if (!player.dragActive || appData.blindfold)
8718 /* What we're doing: logically, the move hasn't been made yet,
8719 so the piece is still in it's original square. But visually
8720 it's being dragged around the board. So we erase the square
8721 that the piece is on and draw it at the last known drag point. */
8722 BlankSquare(player.startSquare.x, player.startSquare.y,
8723 player.startColor, EmptySquare, xBoardWindow);
8724 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8725 damage[player.startBoardY][player.startBoardX] = TRUE;
8728 #include <sys/ioctl.h>
8729 int get_term_width()
8731 int fd, default_width;
8734 default_width = 79; // this is FICS default anyway...
8736 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8738 if (!ioctl(fd, TIOCGSIZE, &win))
8739 default_width = win.ts_cols;
8740 #elif defined(TIOCGWINSZ)
8742 if (!ioctl(fd, TIOCGWINSZ, &win))
8743 default_width = win.ws_col;
8745 return default_width;
8748 void update_ics_width()
8750 static int old_width = 0;
8751 int new_width = get_term_width();
8753 if (old_width != new_width)
8754 ics_printf("set width %d\n", new_width);
8755 old_width = new_width;
8758 void NotifyFrontendLogin()