2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
236 int main P((int argc, char **argv));
237 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
238 char *init_path, char *mode, int (*show_entry)(), char **name_return));
239 RETSIGTYPE CmailSigHandler P((int sig));
240 RETSIGTYPE IntSigHandler P((int sig));
241 RETSIGTYPE TermSizeSigHandler P((int sig));
242 void CreateGCs P((void));
243 void CreateXIMPieces P((void));
244 void CreateXPMPieces P((void));
245 void CreatePieces P((void));
246 void CreatePieceMenus P((void));
247 Widget CreateMenuBar P((Menu *mb));
248 Widget CreateButtonBar P ((MenuItem *mi));
249 char *FindFont P((char *pattern, int targetPxlSize));
250 void PieceMenuPopup P((Widget w, XEvent *event,
251 String *params, Cardinal *num_params));
252 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
254 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
255 u_int wreq, u_int hreq));
256 void CreateGrid P((void));
257 int EventToSquare P((int x, int limit));
258 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
259 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
260 void HandleUserMove P((Widget w, XEvent *event,
261 String *prms, Cardinal *nprms));
262 void AnimateUserMove P((Widget w, XEvent * event,
263 String * params, Cardinal * nParams));
264 void HandlePV P((Widget w, XEvent * event,
265 String * params, Cardinal * nParams));
266 void SelectPV P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void StopPV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void WhiteClock P((Widget w, XEvent *event,
271 String *prms, Cardinal *nprms));
272 void BlackClock P((Widget w, XEvent *event,
273 String *prms, Cardinal *nprms));
274 void DrawPositionProc P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
278 void CommentClick P((Widget w, XEvent * event,
279 String * params, Cardinal * nParams));
280 void CommentPopUp P((char *title, char *label));
281 void CommentPopDown P((void));
282 void CommentCallback P((Widget w, XtPointer client_data,
283 XtPointer call_data));
284 void ICSInputBoxPopUp P((void));
285 void ICSInputBoxPopDown P((void));
286 void FileNamePopUp P((char *label, char *def,
287 FileProc proc, char *openMode));
288 void FileNamePopDown P((void));
289 void FileNameCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void FileNameAction P((Widget w, XEvent *event,
292 String *prms, Cardinal *nprms));
293 void AskQuestionReplyAction P((Widget w, XEvent *event,
294 String *prms, Cardinal *nprms));
295 void AskQuestionProc P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionPopDown P((void));
298 void PromotionPopDown P((void));
299 void PromotionCallback P((Widget w, XtPointer client_data,
300 XtPointer call_data));
301 void EditCommentPopDown P((void));
302 void EditCommentCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
305 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
307 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
309 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
311 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPositionProc P((Widget w, XEvent *event,
314 String *prms, Cardinal *nprms));
315 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
317 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
319 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
321 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
323 void PastePositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void SavePositionProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
333 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
337 void MachineWhiteProc P((Widget w, XEvent *event,
338 String *prms, Cardinal *nprms));
339 void AnalyzeModeProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void AnalyzeFileProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
345 void IcsClientProc P((Widget w, XEvent *event, String *prms,
347 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void EditPositionProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EditCommentProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void IcsInputBoxProc P((Widget w, XEvent *event,
354 String *prms, Cardinal *nprms));
355 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void StopObservingProc P((Widget w, XEvent *event, String *prms,
371 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
373 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
382 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
384 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
387 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
389 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
391 void AutocommProc P((Widget w, XEvent *event, String *prms,
393 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void AutobsProc P((Widget w, XEvent *event, String *prms,
397 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
402 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
405 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
407 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
409 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
413 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
415 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
417 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
419 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
421 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
425 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
427 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
429 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
431 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void DisplayMove P((int moveNumber));
443 void DisplayTitle P((char *title));
444 void ICSInitScript P((void));
445 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
446 void ErrorPopUp P((char *title, char *text, int modal));
447 void ErrorPopDown P((void));
448 static char *ExpandPathName P((char *path));
449 static void CreateAnimVars P((void));
450 static void DragPieceMove P((int x, int y));
451 static void DrawDragPiece P((void));
452 char *ModeToWidgetName P((GameMode mode));
453 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopDown P(());
462 void ShufflePopDown P(());
463 void EnginePopDown P(());
464 void UciPopDown P(());
465 void TimeControlPopDown P(());
466 void NewVariantPopDown P(());
467 void SettingsPopDown P(());
468 void update_ics_width P(());
469 int get_term_width P(());
470 int CopyMemoProc P(());
472 * XBoard depends on Xt R4 or higher
474 int xtVersion = XtSpecificationRelease;
479 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
480 jailSquareColor, highlightSquareColor, premoveHighlightColor;
481 Pixel lowTimeWarningColor;
482 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
483 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
484 wjPieceGC, bjPieceGC, prelineGC, countGC;
485 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
486 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
487 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
488 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
489 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
490 ICSInputShell, fileNameShell, askQuestionShell;
491 Widget historyShell, evalGraphShell, gameListShell;
492 int hOffset; // [HGM] dual
493 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
496 Font clockFontID, coordFontID, countFontID;
497 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
498 XtAppContext appContext;
500 char *oldICSInteractionTitle;
504 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
506 Position commentX = -1, commentY = -1;
507 Dimension commentW, commentH;
508 typedef unsigned int BoardSize;
510 Boolean chessProgram;
512 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
513 int squareSize, smallLayout = 0, tinyLayout = 0,
514 marginW, marginH, // [HGM] for run-time resizing
515 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
516 ICSInputBoxUp = False, askQuestionUp = False,
517 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
518 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
519 Pixel timerForegroundPixel, timerBackgroundPixel;
520 Pixel buttonForegroundPixel, buttonBackgroundPixel;
521 char *chessDir, *programName, *programVersion,
522 *gameCopyFilename, *gamePasteFilename;
523 Boolean alwaysOnTop = False;
524 Boolean saveSettingsOnExit;
525 char *settingsFileName;
526 char *icsTextMenuString;
528 char *firstChessProgramNames;
529 char *secondChessProgramNames;
531 WindowPlacement wpMain;
532 WindowPlacement wpConsole;
533 WindowPlacement wpComment;
534 WindowPlacement wpMoveHistory;
535 WindowPlacement wpEvalGraph;
536 WindowPlacement wpEngineOutput;
537 WindowPlacement wpGameList;
538 WindowPlacement wpTags;
542 Pixmap pieceBitmap[2][(int)BlackPawn];
543 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
544 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
545 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
546 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
547 int useImages, useImageSqs;
548 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
549 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
550 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
551 XImage *ximLightSquare, *ximDarkSquare;
554 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
555 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
557 #define White(piece) ((int)(piece) < (int)BlackPawn)
559 /* Variables for doing smooth animation. This whole thing
560 would be much easier if the board was double-buffered,
561 but that would require a fairly major rewrite. */
566 GC blitGC, pieceGC, outlineGC;
567 XPoint startSquare, prevFrame, mouseDelta;
571 int startBoardX, startBoardY;
574 /* There can be two pieces being animated at once: a player
575 can begin dragging a piece before the remote opponent has moved. */
577 static AnimState game, player;
579 /* Bitmaps for use as masks when drawing XPM pieces.
580 Need one for each black and white piece. */
581 static Pixmap xpmMask[BlackKing + 1];
583 /* This magic number is the number of intermediate frames used
584 in each half of the animation. For short moves it's reduced
585 by 1. The total number of frames will be factor * 2 + 1. */
588 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
590 MenuItem fileMenu[] = {
591 {N_("New Game"), ResetProc},
592 {N_("New Shuffle Game ..."), ShuffleMenuProc},
593 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
594 {"----", NothingProc},
595 {N_("Load Game"), LoadGameProc},
596 {N_("Load Next Game"), LoadNextGameProc},
597 {N_("Load Previous Game"), LoadPrevGameProc},
598 {N_("Reload Same Game"), ReloadGameProc},
599 {N_("Save Game"), SaveGameProc},
600 {"----", NothingProc},
601 {N_("Copy Game"), CopyGameProc},
602 {N_("Paste Game"), PasteGameProc},
603 {"----", NothingProc},
604 {N_("Load Position"), LoadPositionProc},
605 {N_("Load Next Position"), LoadNextPositionProc},
606 {N_("Load Previous Position"), LoadPrevPositionProc},
607 {N_("Reload Same Position"), ReloadPositionProc},
608 {N_("Save Position"), SavePositionProc},
609 {"----", NothingProc},
610 {N_("Copy Position"), CopyPositionProc},
611 {N_("Paste Position"), PastePositionProc},
612 {"----", NothingProc},
613 {N_("Mail Move"), MailMoveProc},
614 {N_("Reload CMail Message"), ReloadCmailMsgProc},
615 {"----", NothingProc},
616 {N_("Exit"), QuitProc},
620 MenuItem modeMenu[] = {
621 {N_("Machine White"), MachineWhiteProc},
622 {N_("Machine Black"), MachineBlackProc},
623 {N_("Two Machines"), TwoMachinesProc},
624 {N_("Analysis Mode"), AnalyzeModeProc},
625 {N_("Analyze File"), AnalyzeFileProc },
626 {N_("ICS Client"), IcsClientProc},
627 {N_("Edit Game"), EditGameProc},
628 {N_("Edit Position"), EditPositionProc},
629 {N_("Training"), TrainingProc},
630 {"----", NothingProc},
631 {N_("Show Engine Output"), EngineOutputProc},
632 {N_("Show Evaluation Graph"), EvalGraphProc},
633 {N_("Show Game List"), ShowGameListProc},
634 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
635 {"----", NothingProc},
636 {N_("Edit Tags"), EditTagsProc},
637 {N_("Edit Comment"), EditCommentProc},
638 {N_("ICS Input Box"), IcsInputBoxProc},
639 {N_("Pause"), PauseProc},
643 MenuItem actionMenu[] = {
644 {N_("Accept"), AcceptProc},
645 {N_("Decline"), DeclineProc},
646 {N_("Rematch"), RematchProc},
647 {"----", NothingProc},
648 {N_("Call Flag"), CallFlagProc},
649 {N_("Draw"), DrawProc},
650 {N_("Adjourn"), AdjournProc},
651 {N_("Abort"), AbortProc},
652 {N_("Resign"), ResignProc},
653 {"----", NothingProc},
654 {N_("Stop Observing"), StopObservingProc},
655 {N_("Stop Examining"), StopExaminingProc},
656 {N_("Upload to Examine"), UploadProc},
657 {"----", NothingProc},
658 {N_("Adjudicate to White"), AdjuWhiteProc},
659 {N_("Adjudicate to Black"), AdjuBlackProc},
660 {N_("Adjudicate Draw"), AdjuDrawProc},
664 MenuItem stepMenu[] = {
665 {N_("Backward"), BackwardProc},
666 {N_("Forward"), ForwardProc},
667 {N_("Back to Start"), ToStartProc},
668 {N_("Forward to End"), ToEndProc},
669 {N_("Revert"), RevertProc},
670 {N_("Annotate"), AnnotateProc},
671 {N_("Truncate Game"), TruncateGameProc},
672 {"----", NothingProc},
673 {N_("Move Now"), MoveNowProc},
674 {N_("Retract Move"), RetractMoveProc},
678 MenuItem optionsMenu[] = {
679 {N_("Flip View"), FlipViewProc},
680 {"----", NothingProc},
681 {N_("Adjudications ..."), EngineMenuProc},
682 {N_("General Settings ..."), UciMenuProc},
683 {N_("Engine #1 Settings ..."), FirstSettingsProc},
684 {N_("Engine #2 Settings ..."), SecondSettingsProc},
685 {N_("Time Control ..."), TimeControlProc},
686 {N_("Game List ..."), GameListOptionsPopUp},
687 {"----", NothingProc},
688 {N_("Always Queen"), AlwaysQueenProc},
689 {N_("Animate Dragging"), AnimateDraggingProc},
690 {N_("Animate Moving"), AnimateMovingProc},
691 {N_("Auto Comment"), AutocommProc},
692 {N_("Auto Flag"), AutoflagProc},
693 {N_("Auto Flip View"), AutoflipProc},
694 {N_("Auto Observe"), AutobsProc},
695 {N_("Auto Raise Board"), AutoraiseProc},
696 {N_("Auto Save"), AutosaveProc},
697 {N_("Blindfold"), BlindfoldProc},
698 {N_("Flash Moves"), FlashMovesProc},
699 {N_("Get Move List"), GetMoveListProc},
701 {N_("Highlight Dragging"), HighlightDraggingProc},
703 {N_("Highlight Last Move"), HighlightLastMoveProc},
704 {N_("Move Sound"), MoveSoundProc},
705 {N_("ICS Alarm"), IcsAlarmProc},
706 {N_("Old Save Style"), OldSaveStyleProc},
707 {N_("Periodic Updates"), PeriodicUpdatesProc},
708 {N_("Ponder Next Move"), PonderNextMoveProc},
709 {N_("Popup Exit Message"), PopupExitMessageProc},
710 {N_("Popup Move Errors"), PopupMoveErrorsProc},
711 {N_("Premove"), PremoveProc},
712 {N_("Quiet Play"), QuietPlayProc},
713 {N_("Show Coords"), ShowCoordsProc},
714 {N_("Hide Thinking"), HideThinkingProc},
715 {N_("Test Legality"), TestLegalityProc},
716 {"----", NothingProc},
717 {N_("Save Settings Now"), SaveSettingsProc},
718 {N_("Save Settings on Exit"), SaveOnExitProc},
722 MenuItem helpMenu[] = {
723 {N_("Info XBoard"), InfoProc},
724 {N_("Man XBoard"), ManProc},
725 {"----", NothingProc},
726 {N_("Hint"), HintProc},
727 {N_("Book"), BookProc},
728 {"----", NothingProc},
729 {N_("About XBoard"), AboutProc},
734 {N_("File"), fileMenu},
735 {N_("Mode"), modeMenu},
736 {N_("Action"), actionMenu},
737 {N_("Step"), stepMenu},
738 {N_("Options"), optionsMenu},
739 {N_("Help"), helpMenu},
743 #define PAUSE_BUTTON N_("P")
744 MenuItem buttonBar[] = {
747 {PAUSE_BUTTON, PauseProc},
753 #define PIECE_MENU_SIZE 18
754 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
755 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
756 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
757 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
758 N_("Empty square"), N_("Clear board") },
759 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
760 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
761 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
762 N_("Empty square"), N_("Clear board") }
764 /* must be in same order as PieceMenuStrings! */
765 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
766 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
767 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
768 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
769 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
770 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
771 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
772 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
773 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
776 #define DROP_MENU_SIZE 6
777 String dropMenuStrings[DROP_MENU_SIZE] = {
778 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
780 /* must be in same order as PieceMenuStrings! */
781 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
782 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
783 WhiteRook, WhiteQueen
791 DropMenuEnables dmEnables[] = {
809 { XtNborderWidth, 0 },
810 { XtNdefaultDistance, 0 },
814 { XtNborderWidth, 0 },
815 { XtNresizable, (XtArgVal) True },
819 { XtNborderWidth, 0 },
825 { XtNjustify, (XtArgVal) XtJustifyRight },
826 { XtNlabel, (XtArgVal) "..." },
827 { XtNresizable, (XtArgVal) True },
828 { XtNresize, (XtArgVal) False }
831 Arg messageArgs[] = {
832 { XtNjustify, (XtArgVal) XtJustifyLeft },
833 { XtNlabel, (XtArgVal) "..." },
834 { XtNresizable, (XtArgVal) True },
835 { XtNresize, (XtArgVal) False }
839 { XtNborderWidth, 0 },
840 { XtNjustify, (XtArgVal) XtJustifyLeft }
843 XtResource clientResources[] = {
844 { "flashCount", "flashCount", XtRInt, sizeof(int),
845 XtOffset(AppDataPtr, flashCount), XtRImmediate,
846 (XtPointer) FLASH_COUNT },
849 XrmOptionDescRec shellOptions[] = {
850 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
851 { "-flash", "flashCount", XrmoptionNoArg, "3" },
852 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
855 XtActionsRec boardActions[] = {
856 { "DrawPosition", DrawPositionProc },
857 { "HandleUserMove", HandleUserMove },
858 { "AnimateUserMove", AnimateUserMove },
859 { "HandlePV", HandlePV },
860 { "SelectPV", SelectPV },
861 { "StopPV", StopPV },
862 { "FileNameAction", FileNameAction },
863 { "AskQuestionProc", AskQuestionProc },
864 { "AskQuestionReplyAction", AskQuestionReplyAction },
865 { "PieceMenuPopup", PieceMenuPopup },
866 { "WhiteClock", WhiteClock },
867 { "BlackClock", BlackClock },
868 { "Iconify", Iconify },
869 { "ResetProc", ResetProc },
870 { "NewVariantProc", NewVariantProc },
871 { "LoadGameProc", LoadGameProc },
872 { "LoadNextGameProc", LoadNextGameProc },
873 { "LoadPrevGameProc", LoadPrevGameProc },
874 { "LoadSelectedProc", LoadSelectedProc },
875 { "SetFilterProc", SetFilterProc },
876 { "ReloadGameProc", ReloadGameProc },
877 { "LoadPositionProc", LoadPositionProc },
878 { "LoadNextPositionProc", LoadNextPositionProc },
879 { "LoadPrevPositionProc", LoadPrevPositionProc },
880 { "ReloadPositionProc", ReloadPositionProc },
881 { "CopyPositionProc", CopyPositionProc },
882 { "PastePositionProc", PastePositionProc },
883 { "CopyGameProc", CopyGameProc },
884 { "PasteGameProc", PasteGameProc },
885 { "SaveGameProc", SaveGameProc },
886 { "SavePositionProc", SavePositionProc },
887 { "MailMoveProc", MailMoveProc },
888 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
889 { "QuitProc", QuitProc },
890 { "MachineWhiteProc", MachineWhiteProc },
891 { "MachineBlackProc", MachineBlackProc },
892 { "AnalysisModeProc", AnalyzeModeProc },
893 { "AnalyzeFileProc", AnalyzeFileProc },
894 { "TwoMachinesProc", TwoMachinesProc },
895 { "IcsClientProc", IcsClientProc },
896 { "EditGameProc", EditGameProc },
897 { "EditPositionProc", EditPositionProc },
898 { "TrainingProc", EditPositionProc },
899 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
900 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
901 { "ShowGameListProc", ShowGameListProc },
902 { "ShowMoveListProc", HistoryShowProc},
903 { "EditTagsProc", EditCommentProc },
904 { "EditCommentProc", EditCommentProc },
905 { "IcsAlarmProc", IcsAlarmProc },
906 { "IcsInputBoxProc", IcsInputBoxProc },
907 { "PauseProc", PauseProc },
908 { "AcceptProc", AcceptProc },
909 { "DeclineProc", DeclineProc },
910 { "RematchProc", RematchProc },
911 { "CallFlagProc", CallFlagProc },
912 { "DrawProc", DrawProc },
913 { "AdjournProc", AdjournProc },
914 { "AbortProc", AbortProc },
915 { "ResignProc", ResignProc },
916 { "AdjuWhiteProc", AdjuWhiteProc },
917 { "AdjuBlackProc", AdjuBlackProc },
918 { "AdjuDrawProc", AdjuDrawProc },
919 { "EnterKeyProc", EnterKeyProc },
920 { "UpKeyProc", UpKeyProc },
921 { "DownKeyProc", DownKeyProc },
922 { "StopObservingProc", StopObservingProc },
923 { "StopExaminingProc", StopExaminingProc },
924 { "UploadProc", UploadProc },
925 { "BackwardProc", BackwardProc },
926 { "ForwardProc", ForwardProc },
927 { "ToStartProc", ToStartProc },
928 { "ToEndProc", ToEndProc },
929 { "RevertProc", RevertProc },
930 { "AnnotateProc", AnnotateProc },
931 { "TruncateGameProc", TruncateGameProc },
932 { "MoveNowProc", MoveNowProc },
933 { "RetractMoveProc", RetractMoveProc },
934 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
935 { "UciMenuProc", (XtActionProc) UciMenuProc },
936 { "TimeControlProc", (XtActionProc) TimeControlProc },
937 { "AlwaysQueenProc", AlwaysQueenProc },
938 { "AnimateDraggingProc", AnimateDraggingProc },
939 { "AnimateMovingProc", AnimateMovingProc },
940 { "AutoflagProc", AutoflagProc },
941 { "AutoflipProc", AutoflipProc },
942 { "AutobsProc", AutobsProc },
943 { "AutoraiseProc", AutoraiseProc },
944 { "AutosaveProc", AutosaveProc },
945 { "BlindfoldProc", BlindfoldProc },
946 { "FlashMovesProc", FlashMovesProc },
947 { "FlipViewProc", FlipViewProc },
948 { "GetMoveListProc", GetMoveListProc },
950 { "HighlightDraggingProc", HighlightDraggingProc },
952 { "HighlightLastMoveProc", HighlightLastMoveProc },
953 { "IcsAlarmProc", IcsAlarmProc },
954 { "MoveSoundProc", MoveSoundProc },
955 { "OldSaveStyleProc", OldSaveStyleProc },
956 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
957 { "PonderNextMoveProc", PonderNextMoveProc },
958 { "PopupExitMessageProc", PopupExitMessageProc },
959 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
960 { "PremoveProc", PremoveProc },
961 { "QuietPlayProc", QuietPlayProc },
962 { "ShowCoordsProc", ShowCoordsProc },
963 { "ShowThinkingProc", ShowThinkingProc },
964 { "HideThinkingProc", HideThinkingProc },
965 { "TestLegalityProc", TestLegalityProc },
966 { "SaveSettingsProc", SaveSettingsProc },
967 { "SaveOnExitProc", SaveOnExitProc },
968 { "InfoProc", InfoProc },
969 { "ManProc", ManProc },
970 { "HintProc", HintProc },
971 { "BookProc", BookProc },
972 { "AboutGameProc", AboutGameProc },
973 { "AboutProc", AboutProc },
974 { "DebugProc", DebugProc },
975 { "NothingProc", NothingProc },
976 { "CommentClick", (XtActionProc) CommentClick },
977 { "CommentPopDown", (XtActionProc) CommentPopDown },
978 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
979 { "TagsPopDown", (XtActionProc) TagsPopDown },
980 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
981 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
982 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
983 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
984 { "GameListPopDown", (XtActionProc) GameListPopDown },
985 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
986 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
987 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
988 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
989 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
990 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
991 { "EnginePopDown", (XtActionProc) EnginePopDown },
992 { "UciPopDown", (XtActionProc) UciPopDown },
993 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
994 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
995 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
996 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
999 char globalTranslations[] =
1000 ":<Key>F9: ResignProc() \n \
1001 :Ctrl<Key>n: ResetProc() \n \
1002 :Meta<Key>V: NewVariantProc() \n \
1003 :Ctrl<Key>o: LoadGameProc() \n \
1004 :Meta<Key>Next: LoadNextGameProc() \n \
1005 :Meta<Key>Prior: LoadPrevGameProc() \n \
1006 :Ctrl<Key>s: SaveGameProc() \n \
1007 :Ctrl<Key>c: CopyGameProc() \n \
1008 :Ctrl<Key>v: PasteGameProc() \n \
1009 :Ctrl<Key>O: LoadPositionProc() \n \
1010 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1011 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1012 :Ctrl<Key>S: SavePositionProc() \n \
1013 :Ctrl<Key>C: CopyPositionProc() \n \
1014 :Ctrl<Key>V: PastePositionProc() \n \
1015 :Ctrl<Key>q: QuitProc() \n \
1016 :Ctrl<Key>w: MachineWhiteProc() \n \
1017 :Ctrl<Key>b: MachineBlackProc() \n \
1018 :Ctrl<Key>t: TwoMachinesProc() \n \
1019 :Ctrl<Key>a: AnalysisModeProc() \n \
1020 :Ctrl<Key>f: AnalyzeFileProc() \n \
1021 :Ctrl<Key>e: EditGameProc() \n \
1022 :Ctrl<Key>E: EditPositionProc() \n \
1023 :Meta<Key>O: EngineOutputProc() \n \
1024 :Meta<Key>E: EvalGraphProc() \n \
1025 :Meta<Key>G: ShowGameListProc() \n \
1026 :Meta<Key>H: ShowMoveListProc() \n \
1027 :<Key>Pause: PauseProc() \n \
1028 :<Key>F3: AcceptProc() \n \
1029 :<Key>F4: DeclineProc() \n \
1030 :<Key>F12: RematchProc() \n \
1031 :<Key>F5: CallFlagProc() \n \
1032 :<Key>F6: DrawProc() \n \
1033 :<Key>F7: AdjournProc() \n \
1034 :<Key>F8: AbortProc() \n \
1035 :<Key>F10: StopObservingProc() \n \
1036 :<Key>F11: StopExaminingProc() \n \
1037 :Meta Ctrl<Key>F12: DebugProc() \n \
1038 :Meta<Key>End: ToEndProc() \n \
1039 :Meta<Key>Right: ForwardProc() \n \
1040 :Meta<Key>Home: ToStartProc() \n \
1041 :Meta<Key>Left: BackwardProc() \n \
1042 :Ctrl<Key>m: MoveNowProc() \n \
1043 :Ctrl<Key>x: RetractMoveProc() \n \
1044 :Meta<Key>J: EngineMenuProc() \n \
1045 :Meta<Key>U: UciMenuProc() \n \
1046 :Meta<Key>T: TimeControlProc() \n \
1047 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1048 :Ctrl<Key>F: AutoflagProc() \n \
1049 :Ctrl<Key>A: AnimateMovingProc() \n \
1050 :Ctrl<Key>P: PonderNextMoveProc() \n \
1051 :Ctrl<Key>L: TestLegalityProc() \n \
1052 :Ctrl<Key>H: HideThinkingProc() \n \
1053 :<Key>-: Iconify() \n \
1054 :<Key>F1: ManProc() \n \
1055 :<Key>F2: FlipViewProc() \n \
1056 <KeyDown>.: BackwardProc() \n \
1057 <KeyUp>.: ForwardProc() \n \
1058 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1059 \"Send to chess program:\",,1) \n \
1060 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1061 \"Send to second chess program:\",,2) \n";
1063 char boardTranslations[] =
1064 "<Btn1Down>: HandleUserMove() \n \
1065 <Btn1Up>: HandleUserMove() \n \
1066 <Btn1Motion>: AnimateUserMove() \n \
1067 <Btn3Motion>: HandlePV() \n \
1068 <Btn3Up>: PieceMenuPopup(menuB) \n \
1069 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1070 PieceMenuPopup(menuB) \n \
1071 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1072 PieceMenuPopup(menuW) \n \
1073 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1074 PieceMenuPopup(menuW) \n \
1075 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1076 PieceMenuPopup(menuB) \n";
1078 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1079 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1081 char ICSInputTranslations[] =
1082 "<Key>Up: UpKeyProc() \n "
1083 "<Key>Down: DownKeyProc() \n "
1084 "<Key>Return: EnterKeyProc() \n";
1086 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1087 // as the widget is destroyed before the up-click can call extend-end
1088 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1090 String xboardResources[] = {
1091 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1092 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1093 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1098 /* Max possible square size */
1099 #define MAXSQSIZE 256
1101 static int xpm_avail[MAXSQSIZE];
1103 #ifdef HAVE_DIR_STRUCT
1105 /* Extract piece size from filename */
1107 xpm_getsize(name, len, ext)
1118 if ((p=strchr(name, '.')) == NULL ||
1119 StrCaseCmp(p+1, ext) != 0)
1125 while (*p && isdigit(*p))
1132 /* Setup xpm_avail */
1134 xpm_getavail(dirname, ext)
1142 for (i=0; i<MAXSQSIZE; ++i)
1145 if (appData.debugMode)
1146 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1148 dir = opendir(dirname);
1151 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1152 programName, dirname);
1156 while ((ent=readdir(dir)) != NULL) {
1157 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1158 if (i > 0 && i < MAXSQSIZE)
1168 xpm_print_avail(fp, ext)
1174 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1175 for (i=1; i<MAXSQSIZE; ++i) {
1181 /* Return XPM piecesize closest to size */
1183 xpm_closest_to(dirname, size, ext)
1189 int sm_diff = MAXSQSIZE;
1193 xpm_getavail(dirname, ext);
1195 if (appData.debugMode)
1196 xpm_print_avail(stderr, ext);
1198 for (i=1; i<MAXSQSIZE; ++i) {
1201 diff = (diff<0) ? -diff : diff;
1202 if (diff < sm_diff) {
1210 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1216 #else /* !HAVE_DIR_STRUCT */
1217 /* If we are on a system without a DIR struct, we can't
1218 read the directory, so we can't collect a list of
1219 filenames, etc., so we can't do any size-fitting. */
1221 xpm_closest_to(dirname, size, ext)
1226 fprintf(stderr, _("\
1227 Warning: No DIR structure found on this system --\n\
1228 Unable to autosize for XPM/XIM pieces.\n\
1229 Please report this error to frankm@hiwaay.net.\n\
1230 Include system type & operating system in message.\n"));
1233 #endif /* HAVE_DIR_STRUCT */
1235 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1236 "magenta", "cyan", "white" };
1240 TextColors textColors[(int)NColorClasses];
1242 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1244 parse_color(str, which)
1248 char *p, buf[100], *d;
1251 if (strlen(str) > 99) /* watch bounds on buf */
1256 for (i=0; i<which; ++i) {
1263 /* Could be looking at something like:
1265 .. in which case we want to stop on a comma also */
1266 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1270 return -1; /* Use default for empty field */
1273 if (which == 2 || isdigit(*p))
1276 while (*p && isalpha(*p))
1281 for (i=0; i<8; ++i) {
1282 if (!StrCaseCmp(buf, cnames[i]))
1283 return which? (i+40) : (i+30);
1285 if (!StrCaseCmp(buf, "default")) return -1;
1287 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1292 parse_cpair(cc, str)
1296 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1297 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1302 /* bg and attr are optional */
1303 textColors[(int)cc].bg = parse_color(str, 1);
1304 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1305 textColors[(int)cc].attr = 0;
1311 /* Arrange to catch delete-window events */
1312 Atom wm_delete_window;
1314 CatchDeleteWindow(Widget w, String procname)
1317 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1318 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1319 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1326 XtSetArg(args[0], XtNiconic, False);
1327 XtSetValues(shellWidget, args, 1);
1329 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1332 //---------------------------------------------------------------------------------------------------------
1333 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1336 #define CW_USEDEFAULT (1<<31)
1337 #define ICS_TEXT_MENU_SIZE 90
1338 #define DEBUG_FILE "xboard.debug"
1339 #define SetCurrentDirectory chdir
1340 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1344 // these two must some day move to frontend.h, when they are implemented
1345 Boolean GameListIsUp();
1347 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1350 // front-end part of option handling
1352 // [HGM] This platform-dependent table provides the location for storing the color info
1353 extern char *crWhite, * crBlack;
1357 &appData.whitePieceColor,
1358 &appData.blackPieceColor,
1359 &appData.lightSquareColor,
1360 &appData.darkSquareColor,
1361 &appData.highlightSquareColor,
1362 &appData.premoveHighlightColor,
1363 &appData.lowTimeWarningColor,
1374 // [HGM] font: keep a font for each square size, even non-stndard ones
1375 #define NUM_SIZES 18
1376 #define MAX_SIZE 130
1377 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1378 char *fontTable[NUM_FONTS][MAX_SIZE];
1381 ParseFont(char *name, int number)
1382 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1384 if(sscanf(name, "size%d:", &size)) {
1385 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1386 // defer processing it until we know if it matches our board size
1387 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1388 fontTable[number][size] = strdup(strchr(name, ':')+1);
1389 fontValid[number][size] = True;
1394 case 0: // CLOCK_FONT
1395 appData.clockFont = strdup(name);
1397 case 1: // MESSAGE_FONT
1398 appData.font = strdup(name);
1400 case 2: // COORD_FONT
1401 appData.coordFont = strdup(name);
1406 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1411 { // only 2 fonts currently
1412 appData.clockFont = CLOCK_FONT_NAME;
1413 appData.coordFont = COORD_FONT_NAME;
1414 appData.font = DEFAULT_FONT_NAME;
1419 { // no-op, until we identify the code for this already in XBoard and move it here
1423 ParseColor(int n, char *name)
1424 { // in XBoard, just copy the color-name string
1425 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1429 ParseTextAttribs(ColorClass cc, char *s)
1431 (&appData.colorShout)[cc] = strdup(s);
1435 ParseBoardSize(void *addr, char *name)
1437 appData.boardSize = strdup(name);
1442 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1446 SetCommPortDefaults()
1447 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1450 // [HGM] args: these three cases taken out to stay in front-end
1452 SaveFontArg(FILE *f, ArgDescriptor *ad)
1455 int i, n = (int)ad->argLoc;
1457 case 0: // CLOCK_FONT
1458 name = appData.clockFont;
1460 case 1: // MESSAGE_FONT
1461 name = appData.font;
1463 case 2: // COORD_FONT
1464 name = appData.coordFont;
1469 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1470 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1471 fontTable[n][squareSize] = strdup(name);
1472 fontValid[n][squareSize] = True;
1475 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1476 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1481 { // nothing to do, as the sounds are at all times represented by their text-string names already
1485 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1486 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1487 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1491 SaveColor(FILE *f, ArgDescriptor *ad)
1492 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1493 if(colorVariable[(int)ad->argLoc])
1494 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1498 SaveBoardSize(FILE *f, char *name, void *addr)
1499 { // wrapper to shield back-end from BoardSize & sizeInfo
1500 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1504 ParseCommPortSettings(char *s)
1505 { // no such option in XBoard (yet)
1508 extern Widget engineOutputShell;
1509 extern Widget tagsShell, editTagsShell;
1511 GetActualPlacement(Widget wg, WindowPlacement *wp)
1521 XtSetArg(args[i], XtNx, &x); i++;
1522 XtSetArg(args[i], XtNy, &y); i++;
1523 XtSetArg(args[i], XtNwidth, &w); i++;
1524 XtSetArg(args[i], XtNheight, &h); i++;
1525 XtGetValues(wg, args, i);
1534 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1535 // In XBoard this will have to wait until awareness of window parameters is implemented
1536 GetActualPlacement(shellWidget, &wpMain);
1537 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1538 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1539 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1540 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1541 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1542 else GetActualPlacement(editShell, &wpComment);
1543 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1544 else GetActualPlacement(editTagsShell, &wpTags);
1548 PrintCommPortSettings(FILE *f, char *name)
1549 { // This option does not exist in XBoard
1553 MySearchPath(char *installDir, char *name, char *fullname)
1554 { // just append installDir and name. Perhaps ExpandPath should be used here?
1555 name = ExpandPathName(name);
1556 if(name && name[0] == '/')
1557 safeStrCpy(fullname, name, MSG_SIZ );
1559 sprintf(fullname, "%s%c%s", installDir, '/', name);
1565 MyGetFullPathName(char *name, char *fullname)
1566 { // should use ExpandPath?
1567 name = ExpandPathName(name);
1568 safeStrCpy(fullname, name, MSG_SIZ );
1573 EnsureOnScreen(int *x, int *y, int minX, int minY)
1580 { // [HGM] args: allows testing if main window is realized from back-end
1581 return xBoardWindow != 0;
1585 PopUpStartupDialog()
1586 { // start menu not implemented in XBoard
1590 ConvertToLine(int argc, char **argv)
1592 static char line[128*1024], buf[1024];
1596 for(i=1; i<argc; i++)
1598 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1599 && argv[i][0] != '{' )
1600 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1602 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1603 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1606 line[strlen(line)-1] = NULLCHAR;
1610 //--------------------------------------------------------------------------------------------
1612 extern Boolean twoBoards, partnerUp;
1615 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1617 #define BoardSize int
1618 void InitDrawingSizes(BoardSize boardSize, int flags)
1619 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1620 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1622 XtGeometryResult gres;
1625 if(!formWidget) return;
1628 * Enable shell resizing.
1630 shellArgs[0].value = (XtArgVal) &w;
1631 shellArgs[1].value = (XtArgVal) &h;
1632 XtGetValues(shellWidget, shellArgs, 2);
1634 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1635 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1636 XtSetValues(shellWidget, &shellArgs[2], 4);
1638 XtSetArg(args[0], XtNdefaultDistance, &sep);
1639 XtGetValues(formWidget, args, 1);
1641 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1642 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1644 hOffset = boardWidth + 10;
1645 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1646 secondSegments[i] = gridSegments[i];
1647 secondSegments[i].x1 += hOffset;
1648 secondSegments[i].x2 += hOffset;
1651 XtSetArg(args[0], XtNwidth, boardWidth);
1652 XtSetArg(args[1], XtNheight, boardHeight);
1653 XtSetValues(boardWidget, args, 2);
1655 timerWidth = (boardWidth - sep) / 2;
1656 XtSetArg(args[0], XtNwidth, timerWidth);
1657 XtSetValues(whiteTimerWidget, args, 1);
1658 XtSetValues(blackTimerWidget, args, 1);
1660 XawFormDoLayout(formWidget, False);
1662 if (appData.titleInWindow) {
1664 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1665 XtSetArg(args[i], XtNheight, &h); i++;
1666 XtGetValues(titleWidget, args, i);
1668 w = boardWidth - 2*bor;
1670 XtSetArg(args[0], XtNwidth, &w);
1671 XtGetValues(menuBarWidget, args, 1);
1672 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1675 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1676 if (gres != XtGeometryYes && appData.debugMode) {
1678 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1679 programName, gres, w, h, wr, hr);
1683 XawFormDoLayout(formWidget, True);
1686 * Inhibit shell resizing.
1688 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1689 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1690 shellArgs[4].value = shellArgs[2].value = w;
1691 shellArgs[5].value = shellArgs[3].value = h;
1692 XtSetValues(shellWidget, &shellArgs[0], 6);
1694 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1697 for(i=0; i<4; i++) {
1699 for(p=0; p<=(int)WhiteKing; p++)
1700 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1701 if(gameInfo.variant == VariantShogi) {
1702 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1703 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1704 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1705 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1706 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1709 if(gameInfo.variant == VariantGothic) {
1710 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1714 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1715 for(p=0; p<=(int)WhiteKing; p++)
1716 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1717 if(gameInfo.variant == VariantShogi) {
1718 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1719 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1720 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1721 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1722 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1725 if(gameInfo.variant == VariantGothic) {
1726 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1732 for(i=0; i<2; i++) {
1734 for(p=0; p<=(int)WhiteKing; p++)
1735 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1736 if(gameInfo.variant == VariantShogi) {
1737 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1738 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1739 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1740 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1741 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1744 if(gameInfo.variant == VariantGothic) {
1745 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1761 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1762 XSetWindowAttributes window_attributes;
1764 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1765 XrmValue vFrom, vTo;
1766 XtGeometryResult gres;
1769 int forceMono = False;
1771 srandom(time(0)); // [HGM] book: make random truly random
1773 setbuf(stdout, NULL);
1774 setbuf(stderr, NULL);
1777 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1778 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1782 programName = strrchr(argv[0], '/');
1783 if (programName == NULL)
1784 programName = argv[0];
1789 XtSetLanguageProc(NULL, NULL, NULL);
1790 bindtextdomain(PACKAGE, LOCALEDIR);
1791 textdomain(PACKAGE);
1795 XtAppInitialize(&appContext, "XBoard", shellOptions,
1796 XtNumber(shellOptions),
1797 &argc, argv, xboardResources, NULL, 0);
1798 appData.boardSize = "";
1799 InitAppData(ConvertToLine(argc, argv));
1801 if (p == NULL) p = "/tmp";
1802 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1803 gameCopyFilename = (char*) malloc(i);
1804 gamePasteFilename = (char*) malloc(i);
1805 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1806 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1808 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1809 clientResources, XtNumber(clientResources),
1812 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1813 static char buf[MSG_SIZ];
1814 EscapeExpand(buf, appData.initString);
1815 appData.initString = strdup(buf);
1816 EscapeExpand(buf, appData.secondInitString);
1817 appData.secondInitString = strdup(buf);
1818 EscapeExpand(buf, appData.firstComputerString);
1819 appData.firstComputerString = strdup(buf);
1820 EscapeExpand(buf, appData.secondComputerString);
1821 appData.secondComputerString = strdup(buf);
1824 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1827 if (chdir(chessDir) != 0) {
1828 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1834 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1835 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1836 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1837 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1840 setbuf(debugFP, NULL);
1843 /* [HGM,HR] make sure board size is acceptable */
1844 if(appData.NrFiles > BOARD_FILES ||
1845 appData.NrRanks > BOARD_RANKS )
1846 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1849 /* This feature does not work; animation needs a rewrite */
1850 appData.highlightDragging = FALSE;
1854 xDisplay = XtDisplay(shellWidget);
1855 xScreen = DefaultScreen(xDisplay);
1856 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1858 gameInfo.variant = StringToVariant(appData.variant);
1859 InitPosition(FALSE);
1862 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1864 if (isdigit(appData.boardSize[0])) {
1865 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1866 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1867 &fontPxlSize, &smallLayout, &tinyLayout);
1869 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1870 programName, appData.boardSize);
1874 /* Find some defaults; use the nearest known size */
1875 SizeDefaults *szd, *nearest;
1876 int distance = 99999;
1877 nearest = szd = sizeDefaults;
1878 while (szd->name != NULL) {
1879 if (abs(szd->squareSize - squareSize) < distance) {
1881 distance = abs(szd->squareSize - squareSize);
1882 if (distance == 0) break;
1886 if (i < 2) lineGap = nearest->lineGap;
1887 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1888 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1889 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1890 if (i < 6) smallLayout = nearest->smallLayout;
1891 if (i < 7) tinyLayout = nearest->tinyLayout;
1894 SizeDefaults *szd = sizeDefaults;
1895 if (*appData.boardSize == NULLCHAR) {
1896 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1897 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1900 if (szd->name == NULL) szd--;
1901 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1903 while (szd->name != NULL &&
1904 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1905 if (szd->name == NULL) {
1906 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1907 programName, appData.boardSize);
1911 squareSize = szd->squareSize;
1912 lineGap = szd->lineGap;
1913 clockFontPxlSize = szd->clockFontPxlSize;
1914 coordFontPxlSize = szd->coordFontPxlSize;
1915 fontPxlSize = szd->fontPxlSize;
1916 smallLayout = szd->smallLayout;
1917 tinyLayout = szd->tinyLayout;
1918 // [HGM] font: use defaults from settings file if available and not overruled
1920 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1921 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1922 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1923 appData.font = fontTable[MESSAGE_FONT][squareSize];
1924 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1925 appData.coordFont = fontTable[COORD_FONT][squareSize];
1927 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1928 if (strlen(appData.pixmapDirectory) > 0) {
1929 p = ExpandPathName(appData.pixmapDirectory);
1931 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1932 appData.pixmapDirectory);
1935 if (appData.debugMode) {
1936 fprintf(stderr, _("\
1937 XBoard square size (hint): %d\n\
1938 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1940 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1941 if (appData.debugMode) {
1942 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1946 /* [HR] height treated separately (hacked) */
1947 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1948 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1949 if (appData.showJail == 1) {
1950 /* Jail on top and bottom */
1951 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1952 XtSetArg(boardArgs[2], XtNheight,
1953 boardHeight + 2*(lineGap + squareSize));
1954 } else if (appData.showJail == 2) {
1956 XtSetArg(boardArgs[1], XtNwidth,
1957 boardWidth + 2*(lineGap + squareSize));
1958 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1961 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1962 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1966 * Determine what fonts to use.
1968 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1969 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1970 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1971 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1972 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1973 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1974 appData.font = FindFont(appData.font, fontPxlSize);
1975 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1976 countFontStruct = XQueryFont(xDisplay, countFontID);
1977 // appData.font = FindFont(appData.font, fontPxlSize);
1979 xdb = XtDatabase(xDisplay);
1980 XrmPutStringResource(&xdb, "*font", appData.font);
1983 * Detect if there are not enough colors available and adapt.
1985 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1986 appData.monoMode = True;
1989 if (!appData.monoMode) {
1990 vFrom.addr = (caddr_t) appData.lightSquareColor;
1991 vFrom.size = strlen(appData.lightSquareColor);
1992 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1993 if (vTo.addr == NULL) {
1994 appData.monoMode = True;
1997 lightSquareColor = *(Pixel *) vTo.addr;
2000 if (!appData.monoMode) {
2001 vFrom.addr = (caddr_t) appData.darkSquareColor;
2002 vFrom.size = strlen(appData.darkSquareColor);
2003 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2004 if (vTo.addr == NULL) {
2005 appData.monoMode = True;
2008 darkSquareColor = *(Pixel *) vTo.addr;
2011 if (!appData.monoMode) {
2012 vFrom.addr = (caddr_t) appData.whitePieceColor;
2013 vFrom.size = strlen(appData.whitePieceColor);
2014 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2015 if (vTo.addr == NULL) {
2016 appData.monoMode = True;
2019 whitePieceColor = *(Pixel *) vTo.addr;
2022 if (!appData.monoMode) {
2023 vFrom.addr = (caddr_t) appData.blackPieceColor;
2024 vFrom.size = strlen(appData.blackPieceColor);
2025 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2026 if (vTo.addr == NULL) {
2027 appData.monoMode = True;
2030 blackPieceColor = *(Pixel *) vTo.addr;
2034 if (!appData.monoMode) {
2035 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2036 vFrom.size = strlen(appData.highlightSquareColor);
2037 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2038 if (vTo.addr == NULL) {
2039 appData.monoMode = True;
2042 highlightSquareColor = *(Pixel *) vTo.addr;
2046 if (!appData.monoMode) {
2047 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2048 vFrom.size = strlen(appData.premoveHighlightColor);
2049 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2050 if (vTo.addr == NULL) {
2051 appData.monoMode = True;
2054 premoveHighlightColor = *(Pixel *) vTo.addr;
2059 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2062 if (appData.bitmapDirectory == NULL ||
2063 appData.bitmapDirectory[0] == NULLCHAR)
2064 appData.bitmapDirectory = DEF_BITMAP_DIR;
2067 if (appData.lowTimeWarning && !appData.monoMode) {
2068 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2069 vFrom.size = strlen(appData.lowTimeWarningColor);
2070 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2071 if (vTo.addr == NULL)
2072 appData.monoMode = True;
2074 lowTimeWarningColor = *(Pixel *) vTo.addr;
2077 if (appData.monoMode && appData.debugMode) {
2078 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2079 (unsigned long) XWhitePixel(xDisplay, xScreen),
2080 (unsigned long) XBlackPixel(xDisplay, xScreen));
2083 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2084 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2085 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2086 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2087 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2088 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2089 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2090 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2091 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2092 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2094 if (appData.colorize) {
2096 _("%s: can't parse color names; disabling colorization\n"),
2099 appData.colorize = FALSE;
2101 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2102 textColors[ColorNone].attr = 0;
2104 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2110 layoutName = "tinyLayout";
2111 } else if (smallLayout) {
2112 layoutName = "smallLayout";
2114 layoutName = "normalLayout";
2116 /* Outer layoutWidget is there only to provide a name for use in
2117 resources that depend on the layout style */
2119 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2120 layoutArgs, XtNumber(layoutArgs));
2122 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2123 formArgs, XtNumber(formArgs));
2124 XtSetArg(args[0], XtNdefaultDistance, &sep);
2125 XtGetValues(formWidget, args, 1);
2128 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2129 XtSetArg(args[0], XtNtop, XtChainTop);
2130 XtSetArg(args[1], XtNbottom, XtChainTop);
2131 XtSetArg(args[2], XtNright, XtChainLeft);
2132 XtSetValues(menuBarWidget, args, 3);
2134 widgetList[j++] = whiteTimerWidget =
2135 XtCreateWidget("whiteTime", labelWidgetClass,
2136 formWidget, timerArgs, XtNumber(timerArgs));
2137 XtSetArg(args[0], XtNfont, clockFontStruct);
2138 XtSetArg(args[1], XtNtop, XtChainTop);
2139 XtSetArg(args[2], XtNbottom, XtChainTop);
2140 XtSetValues(whiteTimerWidget, args, 3);
2142 widgetList[j++] = blackTimerWidget =
2143 XtCreateWidget("blackTime", labelWidgetClass,
2144 formWidget, timerArgs, XtNumber(timerArgs));
2145 XtSetArg(args[0], XtNfont, clockFontStruct);
2146 XtSetArg(args[1], XtNtop, XtChainTop);
2147 XtSetArg(args[2], XtNbottom, XtChainTop);
2148 XtSetValues(blackTimerWidget, args, 3);
2150 if (appData.titleInWindow) {
2151 widgetList[j++] = titleWidget =
2152 XtCreateWidget("title", labelWidgetClass, formWidget,
2153 titleArgs, XtNumber(titleArgs));
2154 XtSetArg(args[0], XtNtop, XtChainTop);
2155 XtSetArg(args[1], XtNbottom, XtChainTop);
2156 XtSetValues(titleWidget, args, 2);
2159 if (appData.showButtonBar) {
2160 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2161 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2162 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2163 XtSetArg(args[2], XtNtop, XtChainTop);
2164 XtSetArg(args[3], XtNbottom, XtChainTop);
2165 XtSetValues(buttonBarWidget, args, 4);
2168 widgetList[j++] = messageWidget =
2169 XtCreateWidget("message", labelWidgetClass, formWidget,
2170 messageArgs, XtNumber(messageArgs));
2171 XtSetArg(args[0], XtNtop, XtChainTop);
2172 XtSetArg(args[1], XtNbottom, XtChainTop);
2173 XtSetValues(messageWidget, args, 2);
2175 widgetList[j++] = boardWidget =
2176 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2177 XtNumber(boardArgs));
2179 XtManageChildren(widgetList, j);
2181 timerWidth = (boardWidth - sep) / 2;
2182 XtSetArg(args[0], XtNwidth, timerWidth);
2183 XtSetValues(whiteTimerWidget, args, 1);
2184 XtSetValues(blackTimerWidget, args, 1);
2186 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2187 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2188 XtGetValues(whiteTimerWidget, args, 2);
2190 if (appData.showButtonBar) {
2191 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2192 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2193 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2197 * formWidget uses these constraints but they are stored
2201 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2202 XtSetValues(menuBarWidget, args, i);
2203 if (appData.titleInWindow) {
2206 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2207 XtSetValues(whiteTimerWidget, args, i);
2209 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2210 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2211 XtSetValues(blackTimerWidget, args, i);
2213 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2214 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2215 XtSetValues(titleWidget, args, i);
2217 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2218 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2219 XtSetValues(messageWidget, args, i);
2220 if (appData.showButtonBar) {
2222 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2223 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2224 XtSetValues(buttonBarWidget, args, i);
2228 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2229 XtSetValues(whiteTimerWidget, args, i);
2231 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2232 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2233 XtSetValues(blackTimerWidget, args, i);
2235 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2236 XtSetValues(titleWidget, args, i);
2238 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2239 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2240 XtSetValues(messageWidget, args, i);
2241 if (appData.showButtonBar) {
2243 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2244 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2245 XtSetValues(buttonBarWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2251 XtSetValues(whiteTimerWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2254 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2255 XtSetValues(blackTimerWidget, args, i);
2257 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2258 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2259 XtSetValues(messageWidget, args, i);
2260 if (appData.showButtonBar) {
2262 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2263 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2264 XtSetValues(buttonBarWidget, args, i);
2268 XtSetArg(args[0], XtNfromVert, messageWidget);
2269 XtSetArg(args[1], XtNtop, XtChainTop);
2270 XtSetArg(args[2], XtNbottom, XtChainBottom);
2271 XtSetArg(args[3], XtNleft, XtChainLeft);
2272 XtSetArg(args[4], XtNright, XtChainRight);
2273 XtSetValues(boardWidget, args, 5);
2275 XtRealizeWidget(shellWidget);
2278 XtSetArg(args[0], XtNx, wpMain.x);
2279 XtSetArg(args[1], XtNy, wpMain.y);
2280 XtSetValues(shellWidget, args, 2);
2284 * Correct the width of the message and title widgets.
2285 * It is not known why some systems need the extra fudge term.
2286 * The value "2" is probably larger than needed.
2288 XawFormDoLayout(formWidget, False);
2290 #define WIDTH_FUDGE 2
2292 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2293 XtSetArg(args[i], XtNheight, &h); i++;
2294 XtGetValues(messageWidget, args, i);
2295 if (appData.showButtonBar) {
2297 XtSetArg(args[i], XtNwidth, &w); i++;
2298 XtGetValues(buttonBarWidget, args, i);
2299 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2301 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2304 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2305 if (gres != XtGeometryYes && appData.debugMode) {
2306 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2307 programName, gres, w, h, wr, hr);
2310 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2311 /* The size used for the child widget in layout lags one resize behind
2312 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2314 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2315 if (gres != XtGeometryYes && appData.debugMode) {
2316 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2317 programName, gres, w, h, wr, hr);
2320 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2321 XtSetArg(args[1], XtNright, XtChainRight);
2322 XtSetValues(messageWidget, args, 2);
2324 if (appData.titleInWindow) {
2326 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2327 XtSetArg(args[i], XtNheight, &h); i++;
2328 XtGetValues(titleWidget, args, i);
2330 w = boardWidth - 2*bor;
2332 XtSetArg(args[0], XtNwidth, &w);
2333 XtGetValues(menuBarWidget, args, 1);
2334 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2337 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2338 if (gres != XtGeometryYes && appData.debugMode) {
2340 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2341 programName, gres, w, h, wr, hr);
2344 XawFormDoLayout(formWidget, True);
2346 xBoardWindow = XtWindow(boardWidget);
2348 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2349 // not need to go into InitDrawingSizes().
2353 * Create X checkmark bitmap and initialize option menu checks.
2355 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2356 checkmark_bits, checkmark_width, checkmark_height);
2357 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2358 if (appData.alwaysPromoteToQueen) {
2359 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2362 if (appData.animateDragging) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,
2364 "menuOptions.Animate Dragging"),
2367 if (appData.animate) {
2368 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2371 if (appData.autoComment) {
2372 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2375 if (appData.autoCallFlag) {
2376 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2379 if (appData.autoFlipView) {
2380 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2383 if (appData.autoObserve) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2387 if (appData.autoRaiseBoard) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Auto Raise Board"), args, 1);
2391 if (appData.autoSaveGames) {
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2395 if (appData.saveGameFile[0] != NULLCHAR) {
2396 /* Can't turn this off from menu */
2397 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2399 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2403 if (appData.blindfold) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Blindfold"), args, 1);
2407 if (appData.flashCount > 0) {
2408 XtSetValues(XtNameToWidget(menuBarWidget,
2409 "menuOptions.Flash Moves"),
2412 if (appData.getMoveList) {
2413 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2417 if (appData.highlightDragging) {
2418 XtSetValues(XtNameToWidget(menuBarWidget,
2419 "menuOptions.Highlight Dragging"),
2423 if (appData.highlightLastMove) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,
2425 "menuOptions.Highlight Last Move"),
2428 if (appData.icsAlarm) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2432 if (appData.ringBellAfterMoves) {
2433 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2436 if (appData.oldSaveStyle) {
2437 XtSetValues(XtNameToWidget(menuBarWidget,
2438 "menuOptions.Old Save Style"), args, 1);
2440 if (appData.periodicUpdates) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,
2442 "menuOptions.Periodic Updates"), args, 1);
2444 if (appData.ponderNextMove) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Ponder Next Move"), args, 1);
2448 if (appData.popupExitMessage) {
2449 XtSetValues(XtNameToWidget(menuBarWidget,
2450 "menuOptions.Popup Exit Message"), args, 1);
2452 if (appData.popupMoveErrors) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Popup Move Errors"), args, 1);
2456 if (appData.premove) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Premove"), args, 1);
2460 if (appData.quietPlay) {
2461 XtSetValues(XtNameToWidget(menuBarWidget,
2462 "menuOptions.Quiet Play"), args, 1);
2464 if (appData.showCoords) {
2465 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2468 if (appData.hideThinkingFromHuman) {
2469 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2472 if (appData.testLegality) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2476 if (saveSettingsOnExit) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2484 ReadBitmap(&wIconPixmap, "icon_white.bm",
2485 icon_white_bits, icon_white_width, icon_white_height);
2486 ReadBitmap(&bIconPixmap, "icon_black.bm",
2487 icon_black_bits, icon_black_width, icon_black_height);
2488 iconPixmap = wIconPixmap;
2490 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2491 XtSetValues(shellWidget, args, i);
2494 * Create a cursor for the board widget.
2496 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2497 XChangeWindowAttributes(xDisplay, xBoardWindow,
2498 CWCursor, &window_attributes);
2501 * Inhibit shell resizing.
2503 shellArgs[0].value = (XtArgVal) &w;
2504 shellArgs[1].value = (XtArgVal) &h;
2505 XtGetValues(shellWidget, shellArgs, 2);
2506 shellArgs[4].value = shellArgs[2].value = w;
2507 shellArgs[5].value = shellArgs[3].value = h;
2508 XtSetValues(shellWidget, &shellArgs[2], 4);
2509 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2510 marginH = h - boardHeight;
2512 CatchDeleteWindow(shellWidget, "QuitProc");
2517 if (appData.bitmapDirectory[0] != NULLCHAR) {
2524 /* Create regular pieces */
2525 if (!useImages) CreatePieces();
2530 if (appData.animate || appData.animateDragging)
2533 XtAugmentTranslations(formWidget,
2534 XtParseTranslationTable(globalTranslations));
2535 XtAugmentTranslations(boardWidget,
2536 XtParseTranslationTable(boardTranslations));
2537 XtAugmentTranslations(whiteTimerWidget,
2538 XtParseTranslationTable(whiteTranslations));
2539 XtAugmentTranslations(blackTimerWidget,
2540 XtParseTranslationTable(blackTranslations));
2542 /* Why is the following needed on some versions of X instead
2543 * of a translation? */
2544 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2545 (XtEventHandler) EventProc, NULL);
2548 /* [AS] Restore layout */
2549 if( wpMoveHistory.visible ) {
2553 if( wpEvalGraph.visible )
2558 if( wpEngineOutput.visible ) {
2559 EngineOutputPopUp();
2564 if (errorExitStatus == -1) {
2565 if (appData.icsActive) {
2566 /* We now wait until we see "login:" from the ICS before
2567 sending the logon script (problems with timestamp otherwise) */
2568 /*ICSInitScript();*/
2569 if (appData.icsInputBox) ICSInputBoxPopUp();
2573 signal(SIGWINCH, TermSizeSigHandler);
2575 signal(SIGINT, IntSigHandler);
2576 signal(SIGTERM, IntSigHandler);
2577 if (*appData.cmailGameName != NULLCHAR) {
2578 signal(SIGUSR1, CmailSigHandler);
2581 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2583 XtSetKeyboardFocus(shellWidget, formWidget);
2585 XtAppMainLoop(appContext);
2586 if (appData.debugMode) fclose(debugFP); // [DM] debug
2593 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2594 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2596 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2597 unlink(gameCopyFilename);
2598 unlink(gamePasteFilename);
2601 RETSIGTYPE TermSizeSigHandler(int sig)
2614 CmailSigHandler(sig)
2620 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2622 /* Activate call-back function CmailSigHandlerCallBack() */
2623 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2625 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2629 CmailSigHandlerCallBack(isr, closure, message, count, error)
2637 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2639 /**** end signal code ****/
2645 /* try to open the icsLogon script, either in the location given
2646 * or in the users HOME directory
2653 f = fopen(appData.icsLogon, "r");
2656 homedir = getenv("HOME");
2657 if (homedir != NULL)
2659 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2660 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2661 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2662 f = fopen(buf, "r");
2667 ProcessICSInitScript(f);
2669 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2678 EditCommentPopDown();
2693 if (!menuBarWidget) return;
2694 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2696 DisplayError("menuStep.Revert", 0);
2698 XtSetSensitive(w, !grey);
2700 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2702 DisplayError("menuStep.Annotate", 0);
2704 XtSetSensitive(w, !grey);
2709 SetMenuEnables(enab)
2713 if (!menuBarWidget) return;
2714 while (enab->name != NULL) {
2715 w = XtNameToWidget(menuBarWidget, enab->name);
2717 DisplayError(enab->name, 0);
2719 XtSetSensitive(w, enab->value);
2725 Enables icsEnables[] = {
2726 { "menuFile.Mail Move", False },
2727 { "menuFile.Reload CMail Message", False },
2728 { "menuMode.Machine Black", False },
2729 { "menuMode.Machine White", False },
2730 { "menuMode.Analysis Mode", False },
2731 { "menuMode.Analyze File", False },
2732 { "menuMode.Two Machines", False },
2734 { "menuHelp.Hint", False },
2735 { "menuHelp.Book", False },
2736 { "menuStep.Move Now", False },
2737 { "menuOptions.Periodic Updates", False },
2738 { "menuOptions.Hide Thinking", False },
2739 { "menuOptions.Ponder Next Move", False },
2741 { "menuStep.Annotate", False },
2745 Enables ncpEnables[] = {
2746 { "menuFile.Mail Move", False },
2747 { "menuFile.Reload CMail Message", False },
2748 { "menuMode.Machine White", False },
2749 { "menuMode.Machine Black", False },
2750 { "menuMode.Analysis Mode", False },
2751 { "menuMode.Analyze File", False },
2752 { "menuMode.Two Machines", False },
2753 { "menuMode.ICS Client", False },
2754 { "menuMode.ICS Input Box", False },
2755 { "Action", False },
2756 { "menuStep.Revert", False },
2757 { "menuStep.Annotate", False },
2758 { "menuStep.Move Now", False },
2759 { "menuStep.Retract Move", False },
2760 { "menuOptions.Auto Comment", False },
2761 { "menuOptions.Auto Flag", False },
2762 { "menuOptions.Auto Flip View", False },
2763 { "menuOptions.Auto Observe", False },
2764 { "menuOptions.Auto Raise Board", False },
2765 { "menuOptions.Get Move List", False },
2766 { "menuOptions.ICS Alarm", False },
2767 { "menuOptions.Move Sound", False },
2768 { "menuOptions.Quiet Play", False },
2769 { "menuOptions.Hide Thinking", False },
2770 { "menuOptions.Periodic Updates", False },
2771 { "menuOptions.Ponder Next Move", False },
2772 { "menuHelp.Hint", False },
2773 { "menuHelp.Book", False },
2777 Enables gnuEnables[] = {
2778 { "menuMode.ICS Client", False },
2779 { "menuMode.ICS Input Box", False },
2780 { "menuAction.Accept", False },
2781 { "menuAction.Decline", False },
2782 { "menuAction.Rematch", False },
2783 { "menuAction.Adjourn", False },
2784 { "menuAction.Stop Examining", False },
2785 { "menuAction.Stop Observing", False },
2786 { "menuAction.Upload to Examine", False },
2787 { "menuStep.Revert", False },
2788 { "menuStep.Annotate", False },
2789 { "menuOptions.Auto Comment", False },
2790 { "menuOptions.Auto Observe", False },
2791 { "menuOptions.Auto Raise Board", False },
2792 { "menuOptions.Get Move List", False },
2793 { "menuOptions.Premove", False },
2794 { "menuOptions.Quiet Play", False },
2796 /* The next two options rely on SetCmailMode being called *after* */
2797 /* SetGNUMode so that when GNU is being used to give hints these */
2798 /* menu options are still available */
2800 { "menuFile.Mail Move", False },
2801 { "menuFile.Reload CMail Message", False },
2805 Enables cmailEnables[] = {
2807 { "menuAction.Call Flag", False },
2808 { "menuAction.Draw", True },
2809 { "menuAction.Adjourn", False },
2810 { "menuAction.Abort", False },
2811 { "menuAction.Stop Observing", False },
2812 { "menuAction.Stop Examining", False },
2813 { "menuFile.Mail Move", True },
2814 { "menuFile.Reload CMail Message", True },
2818 Enables trainingOnEnables[] = {
2819 { "menuMode.Edit Comment", False },
2820 { "menuMode.Pause", False },
2821 { "menuStep.Forward", False },
2822 { "menuStep.Backward", False },
2823 { "menuStep.Forward to End", False },
2824 { "menuStep.Back to Start", False },
2825 { "menuStep.Move Now", False },
2826 { "menuStep.Truncate Game", False },
2830 Enables trainingOffEnables[] = {
2831 { "menuMode.Edit Comment", True },
2832 { "menuMode.Pause", True },
2833 { "menuStep.Forward", True },
2834 { "menuStep.Backward", True },
2835 { "menuStep.Forward to End", True },
2836 { "menuStep.Back to Start", True },
2837 { "menuStep.Move Now", True },
2838 { "menuStep.Truncate Game", True },
2842 Enables machineThinkingEnables[] = {
2843 { "menuFile.Load Game", False },
2844 { "menuFile.Load Next Game", False },
2845 { "menuFile.Load Previous Game", False },
2846 { "menuFile.Reload Same Game", False },
2847 { "menuFile.Paste Game", False },
2848 { "menuFile.Load Position", False },
2849 { "menuFile.Load Next Position", False },
2850 { "menuFile.Load Previous Position", False },
2851 { "menuFile.Reload Same Position", False },
2852 { "menuFile.Paste Position", False },
2853 { "menuMode.Machine White", False },
2854 { "menuMode.Machine Black", False },
2855 { "menuMode.Two Machines", False },
2856 { "menuStep.Retract Move", False },
2860 Enables userThinkingEnables[] = {
2861 { "menuFile.Load Game", True },
2862 { "menuFile.Load Next Game", True },
2863 { "menuFile.Load Previous Game", True },
2864 { "menuFile.Reload Same Game", True },
2865 { "menuFile.Paste Game", True },
2866 { "menuFile.Load Position", True },
2867 { "menuFile.Load Next Position", True },
2868 { "menuFile.Load Previous Position", True },
2869 { "menuFile.Reload Same Position", True },
2870 { "menuFile.Paste Position", True },
2871 { "menuMode.Machine White", True },
2872 { "menuMode.Machine Black", True },
2873 { "menuMode.Two Machines", True },
2874 { "menuStep.Retract Move", True },
2880 SetMenuEnables(icsEnables);
2883 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2884 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2891 SetMenuEnables(ncpEnables);
2897 SetMenuEnables(gnuEnables);
2903 SetMenuEnables(cmailEnables);
2909 SetMenuEnables(trainingOnEnables);
2910 if (appData.showButtonBar) {
2911 XtSetSensitive(buttonBarWidget, False);
2917 SetTrainingModeOff()
2919 SetMenuEnables(trainingOffEnables);
2920 if (appData.showButtonBar) {
2921 XtSetSensitive(buttonBarWidget, True);
2926 SetUserThinkingEnables()
2928 if (appData.noChessProgram) return;
2929 SetMenuEnables(userThinkingEnables);
2933 SetMachineThinkingEnables()
2935 if (appData.noChessProgram) return;
2936 SetMenuEnables(machineThinkingEnables);
2938 case MachinePlaysBlack:
2939 case MachinePlaysWhite:
2940 case TwoMachinesPlay:
2941 XtSetSensitive(XtNameToWidget(menuBarWidget,
2942 ModeToWidgetName(gameMode)), True);
2949 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2950 #define HISTORY_SIZE 64
\r
2951 static char *history[HISTORY_SIZE];
\r
2952 int histIn = 0, histP = 0;
\r
2955 SaveInHistory(char *cmd)
\r
2957 if (history[histIn] != NULL) {
\r
2958 free(history[histIn]);
\r
2959 history[histIn] = NULL;
\r
2961 if (*cmd == NULLCHAR) return;
\r
2962 history[histIn] = StrSave(cmd);
\r
2963 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2964 if (history[histIn] != NULL) {
\r
2965 free(history[histIn]);
\r
2966 history[histIn] = NULL;
\r
2972 PrevInHistory(char *cmd)
\r
2975 if (histP == histIn) {
\r
2976 if (history[histIn] != NULL) free(history[histIn]);
\r
2977 history[histIn] = StrSave(cmd);
\r
2979 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2980 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2982 return history[histP];
\r
2988 if (histP == histIn) return NULL;
\r
2989 histP = (histP + 1) % HISTORY_SIZE;
\r
2990 return history[histP];
\r
2992 // end of borrowed code
\r
2994 #define Abs(n) ((n)<0 ? -(n) : (n))
2997 * Find a font that matches "pattern" that is as close as
2998 * possible to the targetPxlSize. Prefer fonts that are k
2999 * pixels smaller to fonts that are k pixels larger. The
3000 * pattern must be in the X Consortium standard format,
3001 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3002 * The return value should be freed with XtFree when no
3006 FindFont(pattern, targetPxlSize)
3010 char **fonts, *p, *best, *scalable, *scalableTail;
3011 int i, j, nfonts, minerr, err, pxlSize;
3014 char **missing_list;
3016 char *def_string, *base_fnt_lst, strInt[3];
3018 XFontStruct **fnt_list;
3020 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3021 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3022 p = strstr(pattern, "--");
3023 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3024 strcat(base_fnt_lst, strInt);
3025 strcat(base_fnt_lst, strchr(p + 2, '-'));
3027 if ((fntSet = XCreateFontSet(xDisplay,
3031 &def_string)) == NULL) {
3033 fprintf(stderr, _("Unable to create font set.\n"));
3037 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3039 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3041 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3042 programName, pattern);
3050 for (i=0; i<nfonts; i++) {
3053 if (*p != '-') continue;
3055 if (*p == NULLCHAR) break;
3056 if (*p++ == '-') j++;
3058 if (j < 7) continue;
3061 scalable = fonts[i];
3064 err = pxlSize - targetPxlSize;
3065 if (Abs(err) < Abs(minerr) ||
3066 (minerr > 0 && err < 0 && -err == minerr)) {
3072 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3073 /* If the error is too big and there is a scalable font,
3074 use the scalable font. */
3075 int headlen = scalableTail - scalable;
3076 p = (char *) XtMalloc(strlen(scalable) + 10);
3077 while (isdigit(*scalableTail)) scalableTail++;
3078 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3080 p = (char *) XtMalloc(strlen(best) + 2);
3081 safeStrCpy(p, best, strlen(best)+1 );
3083 if (appData.debugMode) {
3084 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3085 pattern, targetPxlSize, p);
3088 if (missing_count > 0)
3089 XFreeStringList(missing_list);
3090 XFreeFontSet(xDisplay, fntSet);
3092 XFreeFontNames(fonts);
3099 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3100 | GCBackground | GCFunction | GCPlaneMask;
3101 XGCValues gc_values;
3104 gc_values.plane_mask = AllPlanes;
3105 gc_values.line_width = lineGap;
3106 gc_values.line_style = LineSolid;
3107 gc_values.function = GXcopy;
3109 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3110 gc_values.background = XBlackPixel(xDisplay, xScreen);
3111 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3113 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3114 gc_values.background = XWhitePixel(xDisplay, xScreen);
3115 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3116 XSetFont(xDisplay, coordGC, coordFontID);
3118 // [HGM] make font for holdings counts (white on black0
3119 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3120 gc_values.background = XBlackPixel(xDisplay, xScreen);
3121 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3122 XSetFont(xDisplay, countGC, countFontID);
3124 if (appData.monoMode) {
3125 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3126 gc_values.background = XWhitePixel(xDisplay, xScreen);
3127 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3129 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3130 gc_values.background = XBlackPixel(xDisplay, xScreen);
3131 lightSquareGC = wbPieceGC
3132 = XtGetGC(shellWidget, value_mask, &gc_values);
3134 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3135 gc_values.background = XWhitePixel(xDisplay, xScreen);
3136 darkSquareGC = bwPieceGC
3137 = XtGetGC(shellWidget, value_mask, &gc_values);
3139 if (DefaultDepth(xDisplay, xScreen) == 1) {
3140 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3141 gc_values.function = GXcopyInverted;
3142 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3143 gc_values.function = GXcopy;
3144 if (XBlackPixel(xDisplay, xScreen) == 1) {
3145 bwPieceGC = darkSquareGC;
3146 wbPieceGC = copyInvertedGC;
3148 bwPieceGC = copyInvertedGC;
3149 wbPieceGC = lightSquareGC;
3153 gc_values.foreground = highlightSquareColor;
3154 gc_values.background = highlightSquareColor;
3155 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3157 gc_values.foreground = premoveHighlightColor;
3158 gc_values.background = premoveHighlightColor;
3159 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 gc_values.foreground = lightSquareColor;
3162 gc_values.background = darkSquareColor;
3163 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 gc_values.foreground = darkSquareColor;
3166 gc_values.background = lightSquareColor;
3167 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3169 gc_values.foreground = jailSquareColor;
3170 gc_values.background = jailSquareColor;
3171 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3173 gc_values.foreground = whitePieceColor;
3174 gc_values.background = darkSquareColor;
3175 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3177 gc_values.foreground = whitePieceColor;
3178 gc_values.background = lightSquareColor;
3179 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3181 gc_values.foreground = whitePieceColor;
3182 gc_values.background = jailSquareColor;
3183 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3185 gc_values.foreground = blackPieceColor;
3186 gc_values.background = darkSquareColor;
3187 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3189 gc_values.foreground = blackPieceColor;
3190 gc_values.background = lightSquareColor;
3191 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3193 gc_values.foreground = blackPieceColor;
3194 gc_values.background = jailSquareColor;
3195 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3199 void loadXIM(xim, xmask, filename, dest, mask)
3212 fp = fopen(filename, "rb");
3214 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3221 for (y=0; y<h; ++y) {
3222 for (x=0; x<h; ++x) {
3227 XPutPixel(xim, x, y, blackPieceColor);
3229 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3232 XPutPixel(xim, x, y, darkSquareColor);
3234 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3237 XPutPixel(xim, x, y, whitePieceColor);
3239 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3242 XPutPixel(xim, x, y, lightSquareColor);
3244 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3250 /* create Pixmap of piece */
3251 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3253 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3256 /* create Pixmap of clipmask
3257 Note: We assume the white/black pieces have the same
3258 outline, so we make only 6 masks. This is okay
3259 since the XPM clipmask routines do the same. */
3261 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3263 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3266 /* now create the 1-bit version */
3267 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3270 values.foreground = 1;
3271 values.background = 0;
3273 /* Don't use XtGetGC, not read only */
3274 maskGC = XCreateGC(xDisplay, *mask,
3275 GCForeground | GCBackground, &values);
3276 XCopyPlane(xDisplay, temp, *mask, maskGC,
3277 0, 0, squareSize, squareSize, 0, 0, 1);
3278 XFreePixmap(xDisplay, temp);
3283 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3285 void CreateXIMPieces()
3290 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3295 /* The XSynchronize calls were copied from CreatePieces.
3296 Not sure if needed, but can't hurt */
3297 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3300 /* temp needed by loadXIM() */
3301 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3302 0, 0, ss, ss, AllPlanes, XYPixmap);
3304 if (strlen(appData.pixmapDirectory) == 0) {
3308 if (appData.monoMode) {
3309 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3313 fprintf(stderr, _("\nLoading XIMs...\n"));
3315 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3316 fprintf(stderr, "%d", piece+1);
3317 for (kind=0; kind<4; kind++) {
3318 fprintf(stderr, ".");
3319 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3320 ExpandPathName(appData.pixmapDirectory),
3321 piece <= (int) WhiteKing ? "" : "w",
3322 pieceBitmapNames[piece],
3324 ximPieceBitmap[kind][piece] =
3325 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3326 0, 0, ss, ss, AllPlanes, XYPixmap);
3327 if (appData.debugMode)
3328 fprintf(stderr, _("(File:%s:) "), buf);
3329 loadXIM(ximPieceBitmap[kind][piece],
3331 &(xpmPieceBitmap2[kind][piece]),
3332 &(ximMaskPm2[piece]));
3333 if(piece <= (int)WhiteKing)
3334 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3336 fprintf(stderr," ");
3338 /* Load light and dark squares */
3339 /* If the LSQ and DSQ pieces don't exist, we will
3340 draw them with solid squares. */
3341 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3342 if (access(buf, 0) != 0) {
3346 fprintf(stderr, _("light square "));
3348 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3349 0, 0, ss, ss, AllPlanes, XYPixmap);
3350 if (appData.debugMode)
3351 fprintf(stderr, _("(File:%s:) "), buf);
3353 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3354 fprintf(stderr, _("dark square "));
3355 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3356 ExpandPathName(appData.pixmapDirectory), ss);
3357 if (appData.debugMode)
3358 fprintf(stderr, _("(File:%s:) "), buf);
3360 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3361 0, 0, ss, ss, AllPlanes, XYPixmap);
3362 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3363 xpmJailSquare = xpmLightSquare;
3365 fprintf(stderr, _("Done.\n"));
3367 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3371 void CreateXPMPieces()
3375 u_int ss = squareSize;
3377 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3378 XpmColorSymbol symbols[4];
3380 /* The XSynchronize calls were copied from CreatePieces.
3381 Not sure if needed, but can't hurt */
3382 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3384 /* Setup translations so piece colors match square colors */
3385 symbols[0].name = "light_piece";
3386 symbols[0].value = appData.whitePieceColor;
3387 symbols[1].name = "dark_piece";
3388 symbols[1].value = appData.blackPieceColor;
3389 symbols[2].name = "light_square";
3390 symbols[2].value = appData.lightSquareColor;
3391 symbols[3].name = "dark_square";
3392 symbols[3].value = appData.darkSquareColor;
3394 attr.valuemask = XpmColorSymbols;
3395 attr.colorsymbols = symbols;
3396 attr.numsymbols = 4;
3398 if (appData.monoMode) {
3399 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3403 if (strlen(appData.pixmapDirectory) == 0) {
3404 XpmPieces* pieces = builtInXpms;
3407 while (pieces->size != squareSize && pieces->size) pieces++;
3408 if (!pieces->size) {
3409 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3412 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3413 for (kind=0; kind<4; kind++) {
3415 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3416 pieces->xpm[piece][kind],
3417 &(xpmPieceBitmap2[kind][piece]),
3418 NULL, &attr)) != 0) {
3419 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3423 if(piece <= (int) WhiteKing)
3424 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3428 xpmJailSquare = xpmLightSquare;
3432 fprintf(stderr, _("\nLoading XPMs...\n"));
3435 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3436 fprintf(stderr, "%d ", piece+1);
3437 for (kind=0; kind<4; kind++) {
3438 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3439 ExpandPathName(appData.pixmapDirectory),
3440 piece > (int) WhiteKing ? "w" : "",
3441 pieceBitmapNames[piece],
3443 if (appData.debugMode) {
3444 fprintf(stderr, _("(File:%s:) "), buf);
3446 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3447 &(xpmPieceBitmap2[kind][piece]),
3448 NULL, &attr)) != 0) {
3449 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3450 // [HGM] missing: read of unorthodox piece failed; substitute King.
3451 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3452 ExpandPathName(appData.pixmapDirectory),
3454 if (appData.debugMode) {
3455 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3457 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3458 &(xpmPieceBitmap2[kind][piece]),
3462 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3467 if(piece <= (int) WhiteKing)
3468 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3471 /* Load light and dark squares */
3472 /* If the LSQ and DSQ pieces don't exist, we will
3473 draw them with solid squares. */
3474 fprintf(stderr, _("light square "));
3475 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3476 if (access(buf, 0) != 0) {
3480 if (appData.debugMode)
3481 fprintf(stderr, _("(File:%s:) "), buf);
3483 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3484 &xpmLightSquare, NULL, &attr)) != 0) {
3485 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3488 fprintf(stderr, _("dark square "));
3489 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3490 ExpandPathName(appData.pixmapDirectory), ss);
3491 if (appData.debugMode) {
3492 fprintf(stderr, _("(File:%s:) "), buf);
3494 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3495 &xpmDarkSquare, NULL, &attr)) != 0) {
3496 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3500 xpmJailSquare = xpmLightSquare;
3501 fprintf(stderr, _("Done.\n"));
3503 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3506 #endif /* HAVE_LIBXPM */
3509 /* No built-in bitmaps */
3514 u_int ss = squareSize;
3516 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3519 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3520 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3521 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3522 pieceBitmapNames[piece],
3523 ss, kind == SOLID ? 's' : 'o');
3524 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3525 if(piece <= (int)WhiteKing)
3526 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3530 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3534 /* With built-in bitmaps */
3537 BuiltInBits* bib = builtInBits;
3540 u_int ss = squareSize;
3542 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3545 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3547 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3548 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3549 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3550 pieceBitmapNames[piece],
3551 ss, kind == SOLID ? 's' : 'o');
3552 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3553 bib->bits[kind][piece], ss, ss);
3554 if(piece <= (int)WhiteKing)
3555 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3559 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3564 void ReadBitmap(pm, name, bits, wreq, hreq)
3567 unsigned char bits[];
3573 char msg[MSG_SIZ], fullname[MSG_SIZ];
3575 if (*appData.bitmapDirectory != NULLCHAR) {
3576 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3577 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3578 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3579 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3580 &w, &h, pm, &x_hot, &y_hot);
3581 fprintf(stderr, "load %s\n", name);
3582 if (errcode != BitmapSuccess) {
3584 case BitmapOpenFailed:
3585 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3587 case BitmapFileInvalid:
3588 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3590 case BitmapNoMemory:
3591 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3595 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3599 fprintf(stderr, _("%s: %s...using built-in\n"),
3601 } else if (w != wreq || h != hreq) {
3603 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3604 programName, fullname, w, h, wreq, hreq);
3610 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3619 if (lineGap == 0) return;
3621 /* [HR] Split this into 2 loops for non-square boards. */
3623 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3624 gridSegments[i].x1 = 0;
3625 gridSegments[i].x2 =
3626 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3627 gridSegments[i].y1 = gridSegments[i].y2
3628 = lineGap / 2 + (i * (squareSize + lineGap));
3631 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3632 gridSegments[j + i].y1 = 0;
3633 gridSegments[j + i].y2 =
3634 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3635 gridSegments[j + i].x1 = gridSegments[j + i].x2
3636 = lineGap / 2 + (j * (squareSize + lineGap));
3640 static void MenuBarSelect(w, addr, index)
3645 XtActionProc proc = (XtActionProc) addr;
3647 (proc)(NULL, NULL, NULL, NULL);
3650 void CreateMenuBarPopup(parent, name, mb)
3660 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3663 XtSetArg(args[j], XtNleftMargin, 20); j++;
3664 XtSetArg(args[j], XtNrightMargin, 20); j++;
3666 while (mi->string != NULL) {
3667 if (strcmp(mi->string, "----") == 0) {
3668 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3671 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3672 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3674 XtAddCallback(entry, XtNcallback,
3675 (XtCallbackProc) MenuBarSelect,
3676 (caddr_t) mi->proc);
3682 Widget CreateMenuBar(mb)
3686 Widget anchor, menuBar;
3688 char menuName[MSG_SIZ];
3691 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3692 XtSetArg(args[j], XtNvSpace, 0); j++;
3693 XtSetArg(args[j], XtNborderWidth, 0); j++;
3694 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3695 formWidget, args, j);
3697 while (mb->name != NULL) {
3698 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3699 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3701 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3704 shortName[0] = _(mb->name)[0];
3705 shortName[1] = NULLCHAR;
3706 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3709 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3712 XtSetArg(args[j], XtNborderWidth, 0); j++;
3713 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3715 CreateMenuBarPopup(menuBar, menuName, mb);
3721 Widget CreateButtonBar(mi)
3725 Widget button, buttonBar;
3729 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3731 XtSetArg(args[j], XtNhSpace, 0); j++;
3733 XtSetArg(args[j], XtNborderWidth, 0); j++;
3734 XtSetArg(args[j], XtNvSpace, 0); j++;
3735 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3736 formWidget, args, j);
3738 while (mi->string != NULL) {
3741 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3742 XtSetArg(args[j], XtNborderWidth, 0); j++;
3744 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3745 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3746 buttonBar, args, j);
3747 XtAddCallback(button, XtNcallback,
3748 (XtCallbackProc) MenuBarSelect,
3749 (caddr_t) mi->proc);
3756 CreatePieceMenu(name, color)
3763 ChessSquare selection;
3765 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3766 boardWidget, args, 0);
3768 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3769 String item = pieceMenuStrings[color][i];
3771 if (strcmp(item, "----") == 0) {
3772 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3775 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3776 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3778 selection = pieceMenuTranslation[color][i];
3779 XtAddCallback(entry, XtNcallback,
3780 (XtCallbackProc) PieceMenuSelect,
3781 (caddr_t) selection);
3782 if (selection == WhitePawn || selection == BlackPawn) {
3783 XtSetArg(args[0], XtNpopupOnEntry, entry);
3784 XtSetValues(menu, args, 1);
3797 ChessSquare selection;
3799 whitePieceMenu = CreatePieceMenu("menuW", 0);
3800 blackPieceMenu = CreatePieceMenu("menuB", 1);
3802 XtRegisterGrabAction(PieceMenuPopup, True,
3803 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3804 GrabModeAsync, GrabModeAsync);
3806 XtSetArg(args[0], XtNlabel, _("Drop"));
3807 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3808 boardWidget, args, 1);
3809 for (i = 0; i < DROP_MENU_SIZE; i++) {
3810 String item = dropMenuStrings[i];
3812 if (strcmp(item, "----") == 0) {
3813 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3816 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3817 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3819 selection = dropMenuTranslation[i];
3820 XtAddCallback(entry, XtNcallback,
3821 (XtCallbackProc) DropMenuSelect,
3822 (caddr_t) selection);
3827 void SetupDropMenu()
3835 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3836 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3837 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3838 dmEnables[i].piece);
3839 XtSetSensitive(entry, p != NULL || !appData.testLegality
3840 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3841 && !appData.icsActive));
3843 while (p && *p++ == dmEnables[i].piece) count++;
3844 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3846 XtSetArg(args[j], XtNlabel, label); j++;
3847 XtSetValues(entry, args, j);
3851 void PieceMenuPopup(w, event, params, num_params)
3855 Cardinal *num_params;
3857 String whichMenu; int menuNr;
3858 if (event->type == ButtonRelease)
3859 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3860 else if (event->type == ButtonPress)
3861 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3863 case 0: whichMenu = params[0]; break;
3864 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3866 case -1: if (errorUp) ErrorPopDown();
3869 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3872 static void PieceMenuSelect(w, piece, junk)
3877 if (pmFromX < 0 || pmFromY < 0) return;
3878 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3881 static void DropMenuSelect(w, piece, junk)
3886 if (pmFromX < 0 || pmFromY < 0) return;
3887 DropMenuEvent(piece, pmFromX, pmFromY);
3890 void WhiteClock(w, event, prms, nprms)
3896 if (gameMode == EditPosition || gameMode == IcsExamining) {
3897 SetWhiteToPlayEvent();
3898 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3903 void BlackClock(w, event, prms, nprms)
3909 if (gameMode == EditPosition || gameMode == IcsExamining) {
3910 SetBlackToPlayEvent();
3911 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3918 * If the user selects on a border boundary, return -1; if off the board,
3919 * return -2. Otherwise map the event coordinate to the square.
3921 int EventToSquare(x, limit)
3929 if ((x % (squareSize + lineGap)) >= squareSize)
3931 x /= (squareSize + lineGap);
3937 static void do_flash_delay(msec)
3943 static void drawHighlight(file, rank, gc)
3949 if (lineGap == 0 || appData.blindfold) return;
3952 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3953 (squareSize + lineGap);
3954 y = lineGap/2 + rank * (squareSize + lineGap);
3956 x = lineGap/2 + file * (squareSize + lineGap);
3957 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3958 (squareSize + lineGap);
3961 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3962 squareSize+lineGap, squareSize+lineGap);
3965 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3966 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3969 SetHighlights(fromX, fromY, toX, toY)
3970 int fromX, fromY, toX, toY;
3972 if (hi1X != fromX || hi1Y != fromY) {
3973 if (hi1X >= 0 && hi1Y >= 0) {
3974 drawHighlight(hi1X, hi1Y, lineGC);
3976 } // [HGM] first erase both, then draw new!
3977 if (hi2X != toX || hi2Y != toY) {
3978 if (hi2X >= 0 && hi2Y >= 0) {
3979 drawHighlight(hi2X, hi2Y, lineGC);
3982 if (hi1X != fromX || hi1Y != fromY) {
3983 if (fromX >= 0 && fromY >= 0) {
3984 drawHighlight(fromX, fromY, highlineGC);
3987 if (hi2X != toX || hi2Y != toY) {
3988 if (toX >= 0 && toY >= 0) {
3989 drawHighlight(toX, toY, highlineGC);
4001 SetHighlights(-1, -1, -1, -1);
4006 SetPremoveHighlights(fromX, fromY, toX, toY)
4007 int fromX, fromY, toX, toY;
4009 if (pm1X != fromX || pm1Y != fromY) {
4010 if (pm1X >= 0 && pm1Y >= 0) {
4011 drawHighlight(pm1X, pm1Y, lineGC);
4013 if (fromX >= 0 && fromY >= 0) {
4014 drawHighlight(fromX, fromY, prelineGC);
4017 if (pm2X != toX || pm2Y != toY) {
4018 if (pm2X >= 0 && pm2Y >= 0) {
4019 drawHighlight(pm2X, pm2Y, lineGC);
4021 if (toX >= 0 && toY >= 0) {
4022 drawHighlight(toX, toY, prelineGC);
4032 ClearPremoveHighlights()
4034 SetPremoveHighlights(-1, -1, -1, -1);
4037 static void BlankSquare(x, y, color, piece, dest)
4042 if (useImages && useImageSqs) {
4046 pm = xpmLightSquare;
4051 case 2: /* neutral */
4056 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4057 squareSize, squareSize, x, y);
4067 case 2: /* neutral */
4072 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4077 I split out the routines to draw a piece so that I could
4078 make a generic flash routine.
4080 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4082 int square_color, x, y;
4085 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4086 switch (square_color) {
4088 case 2: /* neutral */
4090 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4091 ? *pieceToOutline(piece)
4092 : *pieceToSolid(piece),
4093 dest, bwPieceGC, 0, 0,
4094 squareSize, squareSize, x, y);
4097 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4098 ? *pieceToSolid(piece)
4099 : *pieceToOutline(piece),
4100 dest, wbPieceGC, 0, 0,
4101 squareSize, squareSize, x, y);
4106 static void monoDrawPiece(piece, square_color, x, y, dest)
4108 int square_color, x, y;
4111 switch (square_color) {
4113 case 2: /* neutral */
4115 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4116 ? *pieceToOutline(piece)
4117 : *pieceToSolid(piece),
4118 dest, bwPieceGC, 0, 0,
4119 squareSize, squareSize, x, y, 1);
4122 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4123 ? *pieceToSolid(piece)
4124 : *pieceToOutline(piece),
4125 dest, wbPieceGC, 0, 0,
4126 squareSize, squareSize, x, y, 1);
4131 static void colorDrawPiece(piece, square_color, x, y, dest)
4133 int square_color, x, y;
4136 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4137 switch (square_color) {
4139 XCopyPlane(xDisplay, *pieceToSolid(piece),
4140 dest, (int) piece < (int) BlackPawn
4141 ? wlPieceGC : blPieceGC, 0, 0,
4142 squareSize, squareSize, x, y, 1);
4145 XCopyPlane(xDisplay, *pieceToSolid(piece),
4146 dest, (int) piece < (int) BlackPawn
4147 ? wdPieceGC : bdPieceGC, 0, 0,
4148 squareSize, squareSize, x, y, 1);
4150 case 2: /* neutral */
4152 XCopyPlane(xDisplay, *pieceToSolid(piece),
4153 dest, (int) piece < (int) BlackPawn
4154 ? wjPieceGC : bjPieceGC, 0, 0,
4155 squareSize, squareSize, x, y, 1);
4160 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4162 int square_color, x, y;
4167 switch (square_color) {
4169 case 2: /* neutral */
4171 if ((int)piece < (int) BlackPawn) {
4179 if ((int)piece < (int) BlackPawn) {
4187 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4188 dest, wlPieceGC, 0, 0,
4189 squareSize, squareSize, x, y);
4192 typedef void (*DrawFunc)();
4194 DrawFunc ChooseDrawFunc()
4196 if (appData.monoMode) {
4197 if (DefaultDepth(xDisplay, xScreen) == 1) {
4198 return monoDrawPiece_1bit;
4200 return monoDrawPiece;
4204 return colorDrawPieceImage;
4206 return colorDrawPiece;
4210 /* [HR] determine square color depending on chess variant. */
4211 static int SquareColor(row, column)
4216 if (gameInfo.variant == VariantXiangqi) {
4217 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4219 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4221 } else if (row <= 4) {
4227 square_color = ((column + row) % 2) == 1;
4230 /* [hgm] holdings: next line makes all holdings squares light */
4231 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4233 return square_color;
4236 void DrawSquare(row, column, piece, do_flash)
4237 int row, column, do_flash;
4240 int square_color, x, y, direction, font_ascent, font_descent;
4243 XCharStruct overall;
4247 /* Calculate delay in milliseconds (2-delays per complete flash) */
4248 flash_delay = 500 / appData.flashRate;
4251 x = lineGap + ((BOARD_WIDTH-1)-column) *
4252 (squareSize + lineGap);
4253 y = lineGap + row * (squareSize + lineGap);
4255 x = lineGap + column * (squareSize + lineGap);
4256 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4257 (squareSize + lineGap);
4260 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4262 square_color = SquareColor(row, column);
4264 if ( // [HGM] holdings: blank out area between board and holdings
4265 column == BOARD_LEFT-1 || column == BOARD_RGHT
4266 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4267 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4268 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4270 // [HGM] print piece counts next to holdings
4271 string[1] = NULLCHAR;
4272 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4273 string[0] = '0' + piece;
4274 XTextExtents(countFontStruct, string, 1, &direction,
4275 &font_ascent, &font_descent, &overall);
4276 if (appData.monoMode) {
4277 XDrawImageString(xDisplay, xBoardWindow, countGC,
4278 x + squareSize - overall.width - 2,
4279 y + font_ascent + 1, string, 1);
4281 XDrawString(xDisplay, xBoardWindow, countGC,
4282 x + squareSize - overall.width - 2,
4283 y + font_ascent + 1, string, 1);
4286 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4287 string[0] = '0' + piece;
4288 XTextExtents(countFontStruct, string, 1, &direction,
4289 &font_ascent, &font_descent, &overall);
4290 if (appData.monoMode) {
4291 XDrawImageString(xDisplay, xBoardWindow, countGC,
4292 x + 2, y + font_ascent + 1, string, 1);
4294 XDrawString(xDisplay, xBoardWindow, countGC,
4295 x + 2, y + font_ascent + 1, string, 1);
4299 if (piece == EmptySquare || appData.blindfold) {
4300 BlankSquare(x, y, square_color, piece, xBoardWindow);
4302 drawfunc = ChooseDrawFunc();
4303 if (do_flash && appData.flashCount > 0) {
4304 for (i=0; i<appData.flashCount; ++i) {
4306 drawfunc(piece, square_color, x, y, xBoardWindow);
4307 XSync(xDisplay, False);
4308 do_flash_delay(flash_delay);
4310 BlankSquare(x, y, square_color, piece, xBoardWindow);
4311 XSync(xDisplay, False);
4312 do_flash_delay(flash_delay);
4315 drawfunc(piece, square_color, x, y, xBoardWindow);
4319 string[1] = NULLCHAR;
4320 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4321 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4322 string[0] = 'a' + column - BOARD_LEFT;
4323 XTextExtents(coordFontStruct, string, 1, &direction,
4324 &font_ascent, &font_descent, &overall);
4325 if (appData.monoMode) {
4326 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4327 x + squareSize - overall.width - 2,
4328 y + squareSize - font_descent - 1, string, 1);
4330 XDrawString(xDisplay, xBoardWindow, coordGC,
4331 x + squareSize - overall.width - 2,
4332 y + squareSize - font_descent - 1, string, 1);
4335 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4336 string[0] = ONE + row;
4337 XTextExtents(coordFontStruct, string, 1, &direction,
4338 &font_ascent, &font_descent, &overall);
4339 if (appData.monoMode) {
4340 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4341 x + 2, y + font_ascent + 1, string, 1);
4343 XDrawString(xDisplay, xBoardWindow, coordGC,
4344 x + 2, y + font_ascent + 1, string, 1);
4347 if(!partnerUp && marker[row][column]) {
4348 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4349 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4354 /* Why is this needed on some versions of X? */
4355 void EventProc(widget, unused, event)
4360 if (!XtIsRealized(widget))
4363 switch (event->type) {
4365 if (event->xexpose.count > 0) return; /* no clipping is done */
4366 XDrawPosition(widget, True, NULL);
4367 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4368 flipView = !flipView; partnerUp = !partnerUp;
4369 XDrawPosition(widget, True, NULL);
4370 flipView = !flipView; partnerUp = !partnerUp;
4374 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4381 void DrawPosition(fullRedraw, board)
4382 /*Boolean*/int fullRedraw;
4385 XDrawPosition(boardWidget, fullRedraw, board);
4388 /* Returns 1 if there are "too many" differences between b1 and b2
4389 (i.e. more than 1 move was made) */
4390 static int too_many_diffs(b1, b2)
4396 for (i=0; i<BOARD_HEIGHT; ++i) {
4397 for (j=0; j<BOARD_WIDTH; ++j) {
4398 if (b1[i][j] != b2[i][j]) {
4399 if (++c > 4) /* Castling causes 4 diffs */
4408 /* Matrix describing castling maneuvers */
4409 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4410 static int castling_matrix[4][5] = {
4411 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4412 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4413 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4414 { 7, 7, 4, 5, 6 } /* 0-0, black */
4417 /* Checks whether castling occurred. If it did, *rrow and *rcol
4418 are set to the destination (row,col) of the rook that moved.
4420 Returns 1 if castling occurred, 0 if not.
4422 Note: Only handles a max of 1 castling move, so be sure
4423 to call too_many_diffs() first.
4425 static int check_castle_draw(newb, oldb, rrow, rcol)
4432 /* For each type of castling... */
4433 for (i=0; i<4; ++i) {
4434 r = castling_matrix[i];
4436 /* Check the 4 squares involved in the castling move */
4438 for (j=1; j<=4; ++j) {
4439 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4446 /* All 4 changed, so it must be a castling move */
4455 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4456 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4458 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4461 void DrawSeekBackground( int left, int top, int right, int bottom )
4463 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4466 void DrawSeekText(char *buf, int x, int y)
4468 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4471 void DrawSeekDot(int x, int y, int colorNr)
4473 int square = colorNr & 0x80;
4476 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4478 XFillRectangle(xDisplay, xBoardWindow, color,
4479 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4481 XFillArc(xDisplay, xBoardWindow, color,
4482 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4485 static int damage[2][BOARD_RANKS][BOARD_FILES];
4488 * event handler for redrawing the board
4490 void XDrawPosition(w, repaint, board)
4492 /*Boolean*/int repaint;
4496 static int lastFlipView = 0;
4497 static int lastBoardValid[2] = {0, 0};
4498 static Board lastBoard[2];
4501 int nr = twoBoards*partnerUp;
4503 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4505 if (board == NULL) {
4506 if (!lastBoardValid[nr]) return;
4507 board = lastBoard[nr];
4509 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4510 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4516 * It would be simpler to clear the window with XClearWindow()
4517 * but this causes a very distracting flicker.
4520 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4522 /* If too much changes (begin observing new game, etc.), don't
4524 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4526 /* Special check for castling so we don't flash both the king
4527 and the rook (just flash the king). */
4529 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4530 /* Draw rook with NO flashing. King will be drawn flashing later */
4531 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4532 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4536 /* First pass -- Draw (newly) empty squares and repair damage.
4537 This prevents you from having a piece show up twice while it
4538 is flashing on its new square */
4539 for (i = 0; i < BOARD_HEIGHT; i++)
4540 for (j = 0; j < BOARD_WIDTH; j++)
4541 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4542 || damage[nr][i][j]) {
4543 DrawSquare(i, j, board[i][j], 0);
4544 damage[nr][i][j] = False;
4547 /* Second pass -- Draw piece(s) in new position and flash them */
4548 for (i = 0; i < BOARD_HEIGHT; i++)
4549 for (j = 0; j < BOARD_WIDTH; j++)
4550 if (board[i][j] != lastBoard[nr][i][j]) {
4551 DrawSquare(i, j, board[i][j], do_flash);
4555 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4556 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4557 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4559 for (i = 0; i < BOARD_HEIGHT; i++)
4560 for (j = 0; j < BOARD_WIDTH; j++) {
4561 DrawSquare(i, j, board[i][j], 0);
4562 damage[nr][i][j] = False;
4566 CopyBoard(lastBoard[nr], board);
4567 lastBoardValid[nr] = 1;
4568 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4569 lastFlipView = flipView;
4571 /* Draw highlights */
4572 if (pm1X >= 0 && pm1Y >= 0) {
4573 drawHighlight(pm1X, pm1Y, prelineGC);
4575 if (pm2X >= 0 && pm2Y >= 0) {
4576 drawHighlight(pm2X, pm2Y, prelineGC);
4578 if (hi1X >= 0 && hi1Y >= 0) {
4579 drawHighlight(hi1X, hi1Y, highlineGC);
4581 if (hi2X >= 0 && hi2Y >= 0) {
4582 drawHighlight(hi2X, hi2Y, highlineGC);
4585 /* If piece being dragged around board, must redraw that too */
4588 XSync(xDisplay, False);
4593 * event handler for redrawing the board
4595 void DrawPositionProc(w, event, prms, nprms)
4601 XDrawPosition(w, True, NULL);
4606 * event handler for parsing user moves
4608 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4609 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4610 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4611 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4612 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4613 // and at the end FinishMove() to perform the move after optional promotion popups.
4614 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4615 void HandleUserMove(w, event, prms, nprms)
4621 if (w != boardWidget || errorExitStatus != -1) return;
4624 if (event->type == ButtonPress) {
4625 XtPopdown(promotionShell);
4626 XtDestroyWidget(promotionShell);
4627 promotionUp = False;
4635 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4636 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4637 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4640 void AnimateUserMove (Widget w, XEvent * event,
4641 String * params, Cardinal * nParams)
4643 DragPieceMove(event->xmotion.x, event->xmotion.y);
4646 void HandlePV (Widget w, XEvent * event,
4647 String * params, Cardinal * nParams)
4648 { // [HGM] pv: walk PV
4649 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4652 Widget CommentCreate(name, text, mutable, callback, lines)
4654 int /*Boolean*/ mutable;
4655 XtCallbackProc callback;
4659 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4664 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4665 XtGetValues(boardWidget, args, j);
4668 XtSetArg(args[j], XtNresizable, True); j++;
4671 XtCreatePopupShell(name, topLevelShellWidgetClass,
4672 shellWidget, args, j);
4675 XtCreatePopupShell(name, transientShellWidgetClass,
4676 shellWidget, args, j);
4679 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4680 layoutArgs, XtNumber(layoutArgs));
4682 XtCreateManagedWidget("form", formWidgetClass, layout,
4683 formArgs, XtNumber(formArgs));
4687 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4688 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4690 XtSetArg(args[j], XtNstring, text); j++;
4691 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4692 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4693 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4694 XtSetArg(args[j], XtNright, XtChainRight); j++;
4695 XtSetArg(args[j], XtNresizable, True); j++;
4696 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4697 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4698 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4699 XtSetArg(args[j], XtNautoFill, True); j++;
4700 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4702 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4703 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4707 XtSetArg(args[j], XtNfromVert, edit); j++;
4708 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4709 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4710 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4711 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4713 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4714 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4717 XtSetArg(args[j], XtNfromVert, edit); j++;
4718 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4719 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4720 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4721 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4722 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4724 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4725 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4728 XtSetArg(args[j], XtNfromVert, edit); j++;
4729 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4730 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4731 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4732 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4733 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4735 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4736 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4739 XtSetArg(args[j], XtNfromVert, edit); j++;
4740 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4741 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4742 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4743 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4745 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4746 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4749 XtSetArg(args[j], XtNfromVert, edit); j++;
4750 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4751 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4752 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4753 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4754 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4756 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4757 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4760 XtRealizeWidget(shell);
4762 if (commentX == -1) {
4765 Dimension pw_height;
4766 Dimension ew_height;
4769 XtSetArg(args[j], XtNheight, &ew_height); j++;
4770 XtGetValues(edit, args, j);
4773 XtSetArg(args[j], XtNheight, &pw_height); j++;
4774 XtGetValues(shell, args, j);
4775 commentH = pw_height + (lines - 1) * ew_height;
4776 commentW = bw_width - 16;
4778 XSync(xDisplay, False);
4780 /* This code seems to tickle an X bug if it is executed too soon
4781 after xboard starts up. The coordinates get transformed as if
4782 the main window was positioned at (0, 0).
4784 XtTranslateCoords(shellWidget,
4785 (bw_width - commentW) / 2, 0 - commentH / 2,
4786 &commentX, &commentY);
4788 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4789 RootWindowOfScreen(XtScreen(shellWidget)),
4790 (bw_width - commentW) / 2, 0 - commentH / 2,
4795 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4798 if(wpComment.width > 0) {
4799 commentX = wpComment.x;
4800 commentY = wpComment.y;
4801 commentW = wpComment.width;
4802 commentH = wpComment.height;
4806 XtSetArg(args[j], XtNheight, commentH); j++;
4807 XtSetArg(args[j], XtNwidth, commentW); j++;
4808 XtSetArg(args[j], XtNx, commentX); j++;
4809 XtSetArg(args[j], XtNy, commentY); j++;
4810 XtSetValues(shell, args, j);
4811 XtSetKeyboardFocus(shell, edit);
4816 /* Used for analysis window and ICS input window */
4817 Widget MiscCreate(name, text, mutable, callback, lines)
4819 int /*Boolean*/ mutable;
4820 XtCallbackProc callback;
4824 Widget shell, layout, form, edit;
4826 Dimension bw_width, pw_height, ew_height, w, h;
4832 XtSetArg(args[j], XtNresizable, True); j++;
4835 XtCreatePopupShell(name, topLevelShellWidgetClass,
4836 shellWidget, args, j);
4839 XtCreatePopupShell(name, transientShellWidgetClass,
4840 shellWidget, args, j);
4843 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4844 layoutArgs, XtNumber(layoutArgs));
4846 XtCreateManagedWidget("form", formWidgetClass, layout,
4847 formArgs, XtNumber(formArgs));
4851 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4852 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4854 XtSetArg(args[j], XtNstring, text); j++;
4855 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4856 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4857 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4858 XtSetArg(args[j], XtNright, XtChainRight); j++;
4859 XtSetArg(args[j], XtNresizable, True); j++;
4860 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4861 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4862 XtSetArg(args[j], XtNautoFill, True); j++;
4863 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4865 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4867 XtRealizeWidget(shell);
4870 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4871 XtGetValues(boardWidget, args, j);
4874 XtSetArg(args[j], XtNheight, &ew_height); j++;
4875 XtGetValues(edit, args, j);
4878 XtSetArg(args[j], XtNheight, &pw_height); j++;
4879 XtGetValues(shell, args, j);
4880 h = pw_height + (lines - 1) * ew_height;
4883 XSync(xDisplay, False);
4885 /* This code seems to tickle an X bug if it is executed too soon
4886 after xboard starts up. The coordinates get transformed as if
4887 the main window was positioned at (0, 0).
4889 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4891 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4892 RootWindowOfScreen(XtScreen(shellWidget)),
4893 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4897 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4900 XtSetArg(args[j], XtNheight, h); j++;
4901 XtSetArg(args[j], XtNwidth, w); j++;
4902 XtSetArg(args[j], XtNx, x); j++;
4903 XtSetArg(args[j], XtNy, y); j++;
4904 XtSetValues(shell, args, j);
4910 static int savedIndex; /* gross that this is global */
4912 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4915 XawTextPosition index, dummy;
4918 XawTextGetSelectionPos(w, &index, &dummy);
4919 XtSetArg(arg, XtNstring, &val);
4920 XtGetValues(w, &arg, 1);
4921 ReplaceComment(savedIndex, val);
4922 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4923 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4926 void EditCommentPopUp(index, title, text)
4935 if (text == NULL) text = "";
4937 if (editShell == NULL) {
4939 CommentCreate(title, text, True, EditCommentCallback, 4);
4940 XtRealizeWidget(editShell);
4941 CatchDeleteWindow(editShell, "EditCommentPopDown");
4943 edit = XtNameToWidget(editShell, "*form.text");
4945 XtSetArg(args[j], XtNstring, text); j++;
4946 XtSetValues(edit, args, j);
4948 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4949 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4950 XtSetValues(editShell, args, j);
4953 XtPopup(editShell, XtGrabNone);
4957 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4958 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4962 void EditCommentCallback(w, client_data, call_data)
4964 XtPointer client_data, call_data;
4972 XtSetArg(args[j], XtNlabel, &name); j++;
4973 XtGetValues(w, args, j);
4975 if (strcmp(name, _("ok")) == 0) {
4976 edit = XtNameToWidget(editShell, "*form.text");
4978 XtSetArg(args[j], XtNstring, &val); j++;
4979 XtGetValues(edit, args, j);
4980 ReplaceComment(savedIndex, val);
4981 EditCommentPopDown();
4982 } else if (strcmp(name, _("cancel")) == 0) {
4983 EditCommentPopDown();
4984 } else if (strcmp(name, _("clear")) == 0) {
4985 edit = XtNameToWidget(editShell, "*form.text");
4986 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4987 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4991 void EditCommentPopDown()
4996 if (!editUp) return;
4998 XtSetArg(args[j], XtNx, &commentX); j++;
4999 XtSetArg(args[j], XtNy, &commentY); j++;
5000 XtSetArg(args[j], XtNheight, &commentH); j++;
5001 XtSetArg(args[j], XtNwidth, &commentW); j++;
5002 XtGetValues(editShell, args, j);
5003 XtPopdown(editShell);
5006 XtSetArg(args[j], XtNleftBitmap, None); j++;
5007 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5011 void ICSInputBoxPopUp()
5016 char *title = _("ICS Input");
5019 if (ICSInputShell == NULL) {
5020 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5021 tr = XtParseTranslationTable(ICSInputTranslations);
5022 edit = XtNameToWidget(ICSInputShell, "*form.text");
5023 XtOverrideTranslations(edit, tr);
5024 XtRealizeWidget(ICSInputShell);
5025 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5028 edit = XtNameToWidget(ICSInputShell, "*form.text");
5030 XtSetArg(args[j], XtNstring, ""); j++;
5031 XtSetValues(edit, args, j);
5033 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5034 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5035 XtSetValues(ICSInputShell, args, j);
5038 XtPopup(ICSInputShell, XtGrabNone);
5039 XtSetKeyboardFocus(ICSInputShell, edit);
5041 ICSInputBoxUp = True;
5043 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5044 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5048 void ICSInputSendText()
5055 edit = XtNameToWidget(ICSInputShell, "*form.text");
5057 XtSetArg(args[j], XtNstring, &val); j++;
5058 XtGetValues(edit, args, j);
5060 SendMultiLineToICS(val);
5061 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5062 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5065 void ICSInputBoxPopDown()
5070 if (!ICSInputBoxUp) return;
5072 XtPopdown(ICSInputShell);
5073 ICSInputBoxUp = False;
5075 XtSetArg(args[j], XtNleftBitmap, None); j++;
5076 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5080 void CommentPopUp(title, text)
5087 savedIndex = currentMove; // [HGM] vari
5088 if (commentShell == NULL) {
5090 CommentCreate(title, text, False, CommentCallback, 4);
5091 XtRealizeWidget(commentShell);
5092 CatchDeleteWindow(commentShell, "CommentPopDown");
5094 edit = XtNameToWidget(commentShell, "*form.text");
5096 XtSetArg(args[j], XtNstring, text); j++;
5097 XtSetValues(edit, args, j);
5099 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5100 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5101 XtSetValues(commentShell, args, j);
5104 XtPopup(commentShell, XtGrabNone);
5105 XSync(xDisplay, False);
5110 void CommentCallback(w, client_data, call_data)
5112 XtPointer client_data, call_data;
5119 XtSetArg(args[j], XtNlabel, &name); j++;
5120 XtGetValues(w, args, j);
5122 if (strcmp(name, _("close")) == 0) {
5124 } else if (strcmp(name, _("edit")) == 0) {
5131 void CommentPopDown()
5136 if (!commentUp) return;
5138 XtSetArg(args[j], XtNx, &commentX); j++;
5139 XtSetArg(args[j], XtNy, &commentY); j++;
5140 XtSetArg(args[j], XtNwidth, &commentW); j++;
5141 XtSetArg(args[j], XtNheight, &commentH); j++;
5142 XtGetValues(commentShell, args, j);
5143 XtPopdown(commentShell);
5144 XSync(xDisplay, False);
5148 void FileNamePopUp(label, def, proc, openMode)
5154 fileProc = proc; /* I can't see a way not */
5155 fileOpenMode = openMode; /* to use globals here */
5156 { // [HGM] use file-selector dialog stolen from Ghostview
5158 int index; // this is not supported yet
5160 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5161 def, openMode, NULL, &name))
5162 (void) (*fileProc)(f, index=0, name);
5166 void FileNamePopDown()
5168 if (!filenameUp) return;
5169 XtPopdown(fileNameShell);
5170 XtDestroyWidget(fileNameShell);
5175 void FileNameCallback(w, client_data, call_data)
5177 XtPointer client_data, call_data;
5182 XtSetArg(args[0], XtNlabel, &name);
5183 XtGetValues(w, args, 1);
5185 if (strcmp(name, _("cancel")) == 0) {
5190 FileNameAction(w, NULL, NULL, NULL);
5193 void FileNameAction(w, event, prms, nprms)
5205 name = XawDialogGetValueString(w = XtParent(w));
5207 if ((name != NULL) && (*name != NULLCHAR)) {
5208 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5209 XtPopdown(w = XtParent(XtParent(w)));
5213 p = strrchr(buf, ' ');
5220 fullname = ExpandPathName(buf);
5222 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5225 f = fopen(fullname, fileOpenMode);
5227 DisplayError(_("Failed to open file"), errno);
5229 (void) (*fileProc)(f, index, buf);
5236 XtPopdown(w = XtParent(XtParent(w)));
5242 void PromotionPopUp()
5245 Widget dialog, layout;
5247 Dimension bw_width, pw_width;
5251 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5252 XtGetValues(boardWidget, args, j);
5255 XtSetArg(args[j], XtNresizable, True); j++;
5256 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5258 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5259 shellWidget, args, j);
5261 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5262 layoutArgs, XtNumber(layoutArgs));
5265 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5266 XtSetArg(args[j], XtNborderWidth, 0); j++;
5267 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5270 if(gameInfo.variant != VariantShogi) {
5271 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5272 (XtPointer) dialog);
5273 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5274 (XtPointer) dialog);
5275 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5276 (XtPointer) dialog);
5277 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5278 (XtPointer) dialog);
5279 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5280 gameInfo.variant == VariantGiveaway) {
5281 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5282 (XtPointer) dialog);
5284 if(gameInfo.variant == VariantCapablanca ||
5285 gameInfo.variant == VariantGothic ||
5286 gameInfo.variant == VariantCapaRandom) {
5287 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5288 (XtPointer) dialog);
5289 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5290 (XtPointer) dialog);
5292 } else // [HGM] shogi
5294 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5295 (XtPointer) dialog);
5296 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5297 (XtPointer) dialog);
5299 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5300 (XtPointer) dialog);
5302 XtRealizeWidget(promotionShell);
5303 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5306 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5307 XtGetValues(promotionShell, args, j);
5309 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5310 lineGap + squareSize/3 +
5311 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5312 0 : 6*(squareSize + lineGap)), &x, &y);
5315 XtSetArg(args[j], XtNx, x); j++;
5316 XtSetArg(args[j], XtNy, y); j++;
5317 XtSetValues(promotionShell, args, j);
5319 XtPopup(promotionShell, XtGrabNone);
5324 void PromotionPopDown()
5326 if (!promotionUp) return;
5327 XtPopdown(promotionShell);
5328 XtDestroyWidget(promotionShell);
5329 promotionUp = False;
5332 void PromotionCallback(w, client_data, call_data)
5334 XtPointer client_data, call_data;
5340 XtSetArg(args[0], XtNlabel, &name);
5341 XtGetValues(w, args, 1);
5345 if (fromX == -1) return;
5347 if (strcmp(name, _("cancel")) == 0) {
5351 } else if (strcmp(name, _("Knight")) == 0) {
5353 } else if (strcmp(name, _("Promote")) == 0) {
5355 } else if (strcmp(name, _("Defer")) == 0) {
5358 promoChar = ToLower(name[0]);
5361 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5363 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5364 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5369 void ErrorCallback(w, client_data, call_data)
5371 XtPointer client_data, call_data;
5374 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5376 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5382 if (!errorUp) return;
5384 XtPopdown(errorShell);
5385 XtDestroyWidget(errorShell);
5386 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5389 void ErrorPopUp(title, label, modal)
5390 char *title, *label;
5394 Widget dialog, layout;
5398 Dimension bw_width, pw_width;
5399 Dimension pw_height;
5403 XtSetArg(args[i], XtNresizable, True); i++;
5404 XtSetArg(args[i], XtNtitle, title); i++;
5406 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5407 shellWidget, args, i);
5409 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5410 layoutArgs, XtNumber(layoutArgs));
5413 XtSetArg(args[i], XtNlabel, label); i++;
5414 XtSetArg(args[i], XtNborderWidth, 0); i++;
5415 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5418 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5420 XtRealizeWidget(errorShell);
5421 CatchDeleteWindow(errorShell, "ErrorPopDown");
5424 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5425 XtGetValues(boardWidget, args, i);
5427 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5428 XtSetArg(args[i], XtNheight, &pw_height); i++;
5429 XtGetValues(errorShell, args, i);
5432 /* This code seems to tickle an X bug if it is executed too soon
5433 after xboard starts up. The coordinates get transformed as if
5434 the main window was positioned at (0, 0).
5436 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5437 0 - pw_height + squareSize / 3, &x, &y);
5439 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5440 RootWindowOfScreen(XtScreen(boardWidget)),
5441 (bw_width - pw_width) / 2,
5442 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5446 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5449 XtSetArg(args[i], XtNx, x); i++;
5450 XtSetArg(args[i], XtNy, y); i++;
5451 XtSetValues(errorShell, args, i);
5454 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5457 /* Disable all user input other than deleting the window */
5458 static int frozen = 0;
5462 /* Grab by a widget that doesn't accept input */
5463 XtAddGrab(messageWidget, TRUE, FALSE);
5467 /* Undo a FreezeUI */
5470 if (!frozen) return;
5471 XtRemoveGrab(messageWidget);
5475 char *ModeToWidgetName(mode)
5479 case BeginningOfGame:
5480 if (appData.icsActive)
5481 return "menuMode.ICS Client";
5482 else if (appData.noChessProgram ||
5483 *appData.cmailGameName != NULLCHAR)
5484 return "menuMode.Edit Game";
5486 return "menuMode.Machine Black";
5487 case MachinePlaysBlack:
5488 return "menuMode.Machine Black";
5489 case MachinePlaysWhite:
5490 return "menuMode.Machine White";
5492 return "menuMode.Analysis Mode";
5494 return "menuMode.Analyze File";
5495 case TwoMachinesPlay:
5496 return "menuMode.Two Machines";
5498 return "menuMode.Edit Game";
5499 case PlayFromGameFile:
5500 return "menuFile.Load Game";
5502 return "menuMode.Edit Position";
5504 return "menuMode.Training";
5505 case IcsPlayingWhite:
5506 case IcsPlayingBlack:
5510 return "menuMode.ICS Client";
5517 void ModeHighlight()
5520 static int oldPausing = FALSE;
5521 static GameMode oldmode = (GameMode) -1;
5524 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5526 if (pausing != oldPausing) {
5527 oldPausing = pausing;
5529 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5531 XtSetArg(args[0], XtNleftBitmap, None);
5533 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5536 if (appData.showButtonBar) {
5537 /* Always toggle, don't set. Previous code messes up when
5538 invoked while the button is pressed, as releasing it
5539 toggles the state again. */
5542 XtSetArg(args[0], XtNbackground, &oldbg);
5543 XtSetArg(args[1], XtNforeground, &oldfg);
5544 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5546 XtSetArg(args[0], XtNbackground, oldfg);
5547 XtSetArg(args[1], XtNforeground, oldbg);
5549 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5553 wname = ModeToWidgetName(oldmode);
5554 if (wname != NULL) {
5555 XtSetArg(args[0], XtNleftBitmap, None);
5556 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5558 wname = ModeToWidgetName(gameMode);
5559 if (wname != NULL) {
5560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5561 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5565 /* Maybe all the enables should be handled here, not just this one */
5566 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5567 gameMode == Training || gameMode == PlayFromGameFile);
5572 * Button/menu procedures
5574 void ResetProc(w, event, prms, nprms)
5583 int LoadGamePopUp(f, gameNumber, title)
5588 cmailMsgLoaded = FALSE;
5589 if (gameNumber == 0) {
5590 int error = GameListBuild(f);
5592 DisplayError(_("Cannot build game list"), error);
5593 } else if (!ListEmpty(&gameList) &&
5594 ((ListGame *) gameList.tailPred)->number > 1) {
5595 GameListPopUp(f, title);
5601 return LoadGame(f, gameNumber, title, FALSE);
5604 void LoadGameProc(w, event, prms, nprms)
5610 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5613 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5616 void LoadNextGameProc(w, event, prms, nprms)
5625 void LoadPrevGameProc(w, event, prms, nprms)
5634 void ReloadGameProc(w, event, prms, nprms)
5643 void LoadNextPositionProc(w, event, prms, nprms)
5652 void LoadPrevPositionProc(w, event, prms, nprms)
5661 void ReloadPositionProc(w, event, prms, nprms)
5670 void LoadPositionProc(w, event, prms, nprms)
5676 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5679 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5682 void SaveGameProc(w, event, prms, nprms)
5688 FileNamePopUp(_("Save game file name?"),
5689 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5693 void SavePositionProc(w, event, prms, nprms)
5699 FileNamePopUp(_("Save position file name?"),
5700 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5704 void ReloadCmailMsgProc(w, event, prms, nprms)
5710 ReloadCmailMsgEvent(FALSE);
5713 void MailMoveProc(w, event, prms, nprms)
5722 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5723 char *selected_fen_position=NULL;
5726 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5727 Atom *type_return, XtPointer *value_return,
5728 unsigned long *length_return, int *format_return)
5730 char *selection_tmp;
5732 if (!selected_fen_position) return False; /* should never happen */
5733 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5734 /* note: since no XtSelectionDoneProc was registered, Xt will
5735 * automatically call XtFree on the value returned. So have to
5736 * make a copy of it allocated with XtMalloc */
5737 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5738 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5740 *value_return=selection_tmp;
5741 *length_return=strlen(selection_tmp);
5742 *type_return=*target;
5743 *format_return = 8; /* bits per byte */
5745 } else if (*target == XA_TARGETS(xDisplay)) {
5746 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5747 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5748 targets_tmp[1] = XA_STRING;
5749 *value_return = targets_tmp;
5750 *type_return = XA_ATOM;
5752 *format_return = 8 * sizeof(Atom);
5753 if (*format_return > 32) {
5754 *length_return *= *format_return / 32;
5755 *format_return = 32;
5763 /* note: when called from menu all parameters are NULL, so no clue what the
5764 * Widget which was clicked on was, or what the click event was
5766 void CopyPositionProc(w, event, prms, nprms)
5773 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5774 * have a notion of a position that is selected but not copied.
5775 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5777 if(gameMode == EditPosition) EditPositionDone(TRUE);
5778 if (selected_fen_position) free(selected_fen_position);
5779 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5780 if (!selected_fen_position) return;
5781 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5783 SendPositionSelection,
5784 NULL/* lose_ownership_proc */ ,
5785 NULL/* transfer_done_proc */);
5786 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5788 SendPositionSelection,
5789 NULL/* lose_ownership_proc */ ,
5790 NULL/* transfer_done_proc */);
5793 /* function called when the data to Paste is ready */
5795 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5796 Atom *type, XtPointer value, unsigned long *len, int *format)
5799 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5800 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5801 EditPositionPasteFEN(fenstr);
5805 /* called when Paste Position button is pressed,
5806 * all parameters will be NULL */
5807 void PastePositionProc(w, event, prms, nprms)
5813 XtGetSelectionValue(menuBarWidget,
5814 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5815 /* (XtSelectionCallbackProc) */ PastePositionCB,
5816 NULL, /* client_data passed to PastePositionCB */
5818 /* better to use the time field from the event that triggered the
5819 * call to this function, but that isn't trivial to get
5827 SendGameSelection(Widget w, Atom *selection, Atom *target,
5828 Atom *type_return, XtPointer *value_return,
5829 unsigned long *length_return, int *format_return)
5831 char *selection_tmp;
5833 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5834 FILE* f = fopen(gameCopyFilename, "r");
5837 if (f == NULL) return False;
5841 selection_tmp = XtMalloc(len + 1);
5842 count = fread(selection_tmp, 1, len, f);
5844 XtFree(selection_tmp);
5847 selection_tmp[len] = NULLCHAR;
5848 *value_return = selection_tmp;
5849 *length_return = len;
5850 *type_return = *target;
5851 *format_return = 8; /* bits per byte */
5853 } else if (*target == XA_TARGETS(xDisplay)) {
5854 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5855 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5856 targets_tmp[1] = XA_STRING;
5857 *value_return = targets_tmp;
5858 *type_return = XA_ATOM;
5860 *format_return = 8 * sizeof(Atom);
5861 if (*format_return > 32) {
5862 *length_return *= *format_return / 32;
5863 *format_return = 32;
5871 /* note: when called from menu all parameters are NULL, so no clue what the
5872 * Widget which was clicked on was, or what the click event was
5874 void CopyGameProc(w, event, prms, nprms)
5882 ret = SaveGameToFile(gameCopyFilename, FALSE);
5886 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5887 * have a notion of a game that is selected but not copied.
5888 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5890 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5893 NULL/* lose_ownership_proc */ ,
5894 NULL/* transfer_done_proc */);
5895 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5898 NULL/* lose_ownership_proc */ ,
5899 NULL/* transfer_done_proc */);
5902 /* function called when the data to Paste is ready */
5904 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5905 Atom *type, XtPointer value, unsigned long *len, int *format)
5908 if (value == NULL || *len == 0) {
5909 return; /* nothing had been selected to copy */
5911 f = fopen(gamePasteFilename, "w");
5913 DisplayError(_("Can't open temp file"), errno);
5916 fwrite(value, 1, *len, f);
5919 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5922 /* called when Paste Game button is pressed,
5923 * all parameters will be NULL */
5924 void PasteGameProc(w, event, prms, nprms)
5930 XtGetSelectionValue(menuBarWidget,
5931 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5932 /* (XtSelectionCallbackProc) */ PasteGameCB,
5933 NULL, /* client_data passed to PasteGameCB */
5935 /* better to use the time field from the event that triggered the
5936 * call to this function, but that isn't trivial to get
5946 SaveGameProc(NULL, NULL, NULL, NULL);
5950 void QuitProc(w, event, prms, nprms)
5959 void PauseProc(w, event, prms, nprms)
5969 void MachineBlackProc(w, event, prms, nprms)
5975 MachineBlackEvent();
5978 void MachineWhiteProc(w, event, prms, nprms)
5984 MachineWhiteEvent();
5987 void AnalyzeModeProc(w, event, prms, nprms)
5995 if (!first.analysisSupport) {
5996 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5997 DisplayError(buf, 0);
6000 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6001 if (appData.icsActive) {
6002 if (gameMode != IcsObserving) {
6003 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6004 DisplayError(buf, 0);
6006 if (appData.icsEngineAnalyze) {
6007 if (appData.debugMode)
6008 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6014 /* if enable, use want disable icsEngineAnalyze */
6015 if (appData.icsEngineAnalyze) {
6020 appData.icsEngineAnalyze = TRUE;
6021 if (appData.debugMode)
6022 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6024 if (!appData.showThinking)
6025 ShowThinkingProc(w,event,prms,nprms);
6030 void AnalyzeFileProc(w, event, prms, nprms)
6036 if (!first.analysisSupport) {
6038 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6039 DisplayError(buf, 0);
6044 if (!appData.showThinking)
6045 ShowThinkingProc(w,event,prms,nprms);
6048 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6049 AnalysisPeriodicEvent(1);
6052 void TwoMachinesProc(w, event, prms, nprms)
6061 void IcsClientProc(w, event, prms, nprms)
6070 void EditGameProc(w, event, prms, nprms)
6079 void EditPositionProc(w, event, prms, nprms)
6085 EditPositionEvent();
6088 void TrainingProc(w, event, prms, nprms)
6097 void EditCommentProc(w, event, prms, nprms)
6104 EditCommentPopDown();
6110 void IcsInputBoxProc(w, event, prms, nprms)
6116 if (ICSInputBoxUp) {
6117 ICSInputBoxPopDown();
6123 void AcceptProc(w, event, prms, nprms)
6132 void DeclineProc(w, event, prms, nprms)
6141 void RematchProc(w, event, prms, nprms)
6150 void CallFlagProc(w, event, prms, nprms)
6159 void DrawProc(w, event, prms, nprms)
6168 void AbortProc(w, event, prms, nprms)
6177 void AdjournProc(w, event, prms, nprms)
6186 void ResignProc(w, event, prms, nprms)
6195 void AdjuWhiteProc(w, event, prms, nprms)
6201 UserAdjudicationEvent(+1);
6204 void AdjuBlackProc(w, event, prms, nprms)
6210 UserAdjudicationEvent(-1);
6213 void AdjuDrawProc(w, event, prms, nprms)
6219 UserAdjudicationEvent(0);
6222 void EnterKeyProc(w, event, prms, nprms)
6228 if (ICSInputBoxUp == True)
6232 void UpKeyProc(w, event, prms, nprms)
6237 { // [HGM] input: let up-arrow recall previous line from history
6244 if (!ICSInputBoxUp) return;
6245 edit = XtNameToWidget(ICSInputShell, "*form.text");
6247 XtSetArg(args[j], XtNstring, &val); j++;
6248 XtGetValues(edit, args, j);
6249 val = PrevInHistory(val);
6250 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6251 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6253 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6254 XawTextReplace(edit, 0, 0, &t);
6255 XawTextSetInsertionPoint(edit, 9999);
6259 void DownKeyProc(w, event, prms, nprms)
6264 { // [HGM] input: let down-arrow recall next line from history
6269 if (!ICSInputBoxUp) return;
6270 edit = XtNameToWidget(ICSInputShell, "*form.text");
6271 val = NextInHistory();
6272 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6273 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6275 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6276 XawTextReplace(edit, 0, 0, &t);
6277 XawTextSetInsertionPoint(edit, 9999);
6281 void StopObservingProc(w, event, prms, nprms)
6287 StopObservingEvent();
6290 void StopExaminingProc(w, event, prms, nprms)
6296 StopExaminingEvent();
6299 void UploadProc(w, event, prms, nprms)
6309 void ForwardProc(w, event, prms, nprms)
6319 void BackwardProc(w, event, prms, nprms)
6328 void ToStartProc(w, event, prms, nprms)
6337 void ToEndProc(w, event, prms, nprms)
6346 void RevertProc(w, event, prms, nprms)
6355 void AnnotateProc(w, event, prms, nprms)
6364 void TruncateGameProc(w, event, prms, nprms)
6370 TruncateGameEvent();
6372 void RetractMoveProc(w, event, prms, nprms)
6381 void MoveNowProc(w, event, prms, nprms)
6391 void AlwaysQueenProc(w, event, prms, nprms)
6399 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6401 if (appData.alwaysPromoteToQueen) {
6402 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6404 XtSetArg(args[0], XtNleftBitmap, None);
6406 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6410 void AnimateDraggingProc(w, event, prms, nprms)
6418 appData.animateDragging = !appData.animateDragging;
6420 if (appData.animateDragging) {
6421 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6424 XtSetArg(args[0], XtNleftBitmap, None);
6426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6430 void AnimateMovingProc(w, event, prms, nprms)
6438 appData.animate = !appData.animate;
6440 if (appData.animate) {
6441 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6444 XtSetArg(args[0], XtNleftBitmap, None);
6446 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6450 void AutocommProc(w, event, prms, nprms)
6458 appData.autoComment = !appData.autoComment;
6460 if (appData.autoComment) {
6461 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6463 XtSetArg(args[0], XtNleftBitmap, None);
6465 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6470 void AutoflagProc(w, event, prms, nprms)
6478 appData.autoCallFlag = !appData.autoCallFlag;
6480 if (appData.autoCallFlag) {
6481 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6483 XtSetArg(args[0], XtNleftBitmap, None);
6485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6489 void AutoflipProc(w, event, prms, nprms)
6497 appData.autoFlipView = !appData.autoFlipView;
6499 if (appData.autoFlipView) {
6500 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6502 XtSetArg(args[0], XtNleftBitmap, None);
6504 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6508 void AutobsProc(w, event, prms, nprms)
6516 appData.autoObserve = !appData.autoObserve;
6518 if (appData.autoObserve) {
6519 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6521 XtSetArg(args[0], XtNleftBitmap, None);
6523 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6527 void AutoraiseProc(w, event, prms, nprms)
6535 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6537 if (appData.autoRaiseBoard) {
6538 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6540 XtSetArg(args[0], XtNleftBitmap, None);
6542 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6546 void AutosaveProc(w, event, prms, nprms)
6554 appData.autoSaveGames = !appData.autoSaveGames;
6556 if (appData.autoSaveGames) {
6557 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6559 XtSetArg(args[0], XtNleftBitmap, None);
6561 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6565 void BlindfoldProc(w, event, prms, nprms)
6573 appData.blindfold = !appData.blindfold;
6575 if (appData.blindfold) {
6576 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6578 XtSetArg(args[0], XtNleftBitmap, None);
6580 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6583 DrawPosition(True, NULL);
6586 void TestLegalityProc(w, event, prms, nprms)
6594 appData.testLegality = !appData.testLegality;
6596 if (appData.testLegality) {
6597 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6599 XtSetArg(args[0], XtNleftBitmap, None);
6601 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6606 void FlashMovesProc(w, event, prms, nprms)
6614 if (appData.flashCount == 0) {
6615 appData.flashCount = 3;
6617 appData.flashCount = -appData.flashCount;
6620 if (appData.flashCount > 0) {
6621 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6623 XtSetArg(args[0], XtNleftBitmap, None);
6625 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6629 void FlipViewProc(w, event, prms, nprms)
6635 flipView = !flipView;
6636 DrawPosition(True, NULL);
6639 void GetMoveListProc(w, event, prms, nprms)
6647 appData.getMoveList = !appData.getMoveList;
6649 if (appData.getMoveList) {
6650 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6653 XtSetArg(args[0], XtNleftBitmap, None);
6655 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6660 void HighlightDraggingProc(w, event, prms, nprms)
6668 appData.highlightDragging = !appData.highlightDragging;
6670 if (appData.highlightDragging) {
6671 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6673 XtSetArg(args[0], XtNleftBitmap, None);
6675 XtSetValues(XtNameToWidget(menuBarWidget,
6676 "menuOptions.Highlight Dragging"), args, 1);
6680 void HighlightLastMoveProc(w, event, prms, nprms)
6688 appData.highlightLastMove = !appData.highlightLastMove;
6690 if (appData.highlightLastMove) {
6691 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6693 XtSetArg(args[0], XtNleftBitmap, None);
6695 XtSetValues(XtNameToWidget(menuBarWidget,
6696 "menuOptions.Highlight Last Move"), args, 1);
6699 void IcsAlarmProc(w, event, prms, nprms)
6707 appData.icsAlarm = !appData.icsAlarm;
6709 if (appData.icsAlarm) {
6710 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6712 XtSetArg(args[0], XtNleftBitmap, None);
6714 XtSetValues(XtNameToWidget(menuBarWidget,
6715 "menuOptions.ICS Alarm"), args, 1);
6718 void MoveSoundProc(w, event, prms, nprms)
6726 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6728 if (appData.ringBellAfterMoves) {
6729 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6731 XtSetArg(args[0], XtNleftBitmap, None);
6733 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6738 void OldSaveStyleProc(w, event, prms, nprms)
6746 appData.oldSaveStyle = !appData.oldSaveStyle;
6748 if (appData.oldSaveStyle) {
6749 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6751 XtSetArg(args[0], XtNleftBitmap, None);
6753 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6757 void PeriodicUpdatesProc(w, event, prms, nprms)
6765 PeriodicUpdatesEvent(!appData.periodicUpdates);
6767 if (appData.periodicUpdates) {
6768 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6770 XtSetArg(args[0], XtNleftBitmap, None);
6772 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6776 void PonderNextMoveProc(w, event, prms, nprms)
6784 PonderNextMoveEvent(!appData.ponderNextMove);
6786 if (appData.ponderNextMove) {
6787 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6789 XtSetArg(args[0], XtNleftBitmap, None);
6791 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6795 void PopupExitMessageProc(w, event, prms, nprms)
6803 appData.popupExitMessage = !appData.popupExitMessage;
6805 if (appData.popupExitMessage) {
6806 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6808 XtSetArg(args[0], XtNleftBitmap, None);
6810 XtSetValues(XtNameToWidget(menuBarWidget,
6811 "menuOptions.Popup Exit Message"), args, 1);
6814 void PopupMoveErrorsProc(w, event, prms, nprms)
6822 appData.popupMoveErrors = !appData.popupMoveErrors;
6824 if (appData.popupMoveErrors) {
6825 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6827 XtSetArg(args[0], XtNleftBitmap, None);
6829 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6833 void PremoveProc(w, event, prms, nprms)
6841 appData.premove = !appData.premove;
6843 if (appData.premove) {
6844 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6846 XtSetArg(args[0], XtNleftBitmap, None);
6848 XtSetValues(XtNameToWidget(menuBarWidget,
6849 "menuOptions.Premove"), args, 1);
6852 void QuietPlayProc(w, event, prms, nprms)
6860 appData.quietPlay = !appData.quietPlay;
6862 if (appData.quietPlay) {
6863 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6865 XtSetArg(args[0], XtNleftBitmap, None);
6867 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6871 void ShowCoordsProc(w, event, prms, nprms)
6879 appData.showCoords = !appData.showCoords;
6881 if (appData.showCoords) {
6882 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6884 XtSetArg(args[0], XtNleftBitmap, None);
6886 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6889 DrawPosition(True, NULL);
6892 void ShowThinkingProc(w, event, prms, nprms)
6898 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6899 ShowThinkingEvent();
6902 void HideThinkingProc(w, event, prms, nprms)
6910 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6911 ShowThinkingEvent();
6913 if (appData.hideThinkingFromHuman) {
6914 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6916 XtSetArg(args[0], XtNleftBitmap, None);
6918 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6922 void SaveOnExitProc(w, event, prms, nprms)
6930 saveSettingsOnExit = !saveSettingsOnExit;
6932 if (saveSettingsOnExit) {
6933 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6935 XtSetArg(args[0], XtNleftBitmap, None);
6937 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6941 void SaveSettingsProc(w, event, prms, nprms)
6947 SaveSettings(settingsFileName);
6950 void InfoProc(w, event, prms, nprms)
6957 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6962 void ManProc(w, event, prms, nprms)
6970 if (nprms && *nprms > 0)
6974 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6978 void HintProc(w, event, prms, nprms)
6987 void BookProc(w, event, prms, nprms)
6996 void AboutProc(w, event, prms, nprms)
7004 char *zippy = " (with Zippy code)";
7008 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7009 programVersion, zippy,
7010 "Copyright 1991 Digital Equipment Corporation",
7011 "Enhancements Copyright 1992-2009 Free Software Foundation",
7012 "Enhancements Copyright 2005 Alessandro Scotti",
7013 PACKAGE, " is free software and carries NO WARRANTY;",
7014 "see the file COPYING for more information.");
7015 ErrorPopUp(_("About XBoard"), buf, FALSE);
7018 void DebugProc(w, event, prms, nprms)
7024 appData.debugMode = !appData.debugMode;
7027 void AboutGameProc(w, event, prms, nprms)
7036 void NothingProc(w, event, prms, nprms)
7045 void Iconify(w, event, prms, nprms)
7054 XtSetArg(args[0], XtNiconic, True);
7055 XtSetValues(shellWidget, args, 1);
7058 void DisplayMessage(message, extMessage)
7059 char *message, *extMessage;
7061 /* display a message in the message widget */
7070 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7075 message = extMessage;
7079 /* need to test if messageWidget already exists, since this function
7080 can also be called during the startup, if for example a Xresource
7081 is not set up correctly */
7084 XtSetArg(arg, XtNlabel, message);
7085 XtSetValues(messageWidget, &arg, 1);
7091 void DisplayTitle(text)
7096 char title[MSG_SIZ];
7099 if (text == NULL) text = "";
7101 if (appData.titleInWindow) {
7103 XtSetArg(args[i], XtNlabel, text); i++;
7104 XtSetValues(titleWidget, args, i);
7107 if (*text != NULLCHAR) {
7108 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7109 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7110 } else if (appData.icsActive) {
7111 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7112 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7113 } else if (appData.cmailGameName[0] != NULLCHAR) {
7114 snprintf(icon, sizeof(icon), "%s", "CMail");
7115 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7117 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7118 } else if (gameInfo.variant == VariantGothic) {
7119 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7120 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7123 } else if (gameInfo.variant == VariantFalcon) {
7124 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7125 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7127 } else if (appData.noChessProgram) {
7128 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7129 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7131 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7132 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7135 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7136 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7137 XtSetValues(shellWidget, args, i);
7142 DisplayError(message, error)
7149 if (appData.debugMode || appData.matchMode) {
7150 fprintf(stderr, "%s: %s\n", programName, message);
7153 if (appData.debugMode || appData.matchMode) {
7154 fprintf(stderr, "%s: %s: %s\n",
7155 programName, message, strerror(error));
7157 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7160 ErrorPopUp(_("Error"), message, FALSE);
7164 void DisplayMoveError(message)
7169 DrawPosition(FALSE, NULL);
7170 if (appData.debugMode || appData.matchMode) {
7171 fprintf(stderr, "%s: %s\n", programName, message);
7173 if (appData.popupMoveErrors) {
7174 ErrorPopUp(_("Error"), message, FALSE);
7176 DisplayMessage(message, "");
7181 void DisplayFatalError(message, error, status)
7187 errorExitStatus = status;
7189 fprintf(stderr, "%s: %s\n", programName, message);
7191 fprintf(stderr, "%s: %s: %s\n",
7192 programName, message, strerror(error));
7193 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7196 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7197 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7203 void DisplayInformation(message)
7207 ErrorPopUp(_("Information"), message, TRUE);
7210 void DisplayNote(message)
7214 ErrorPopUp(_("Note"), message, FALSE);
7218 NullXErrorCheck(dpy, error_event)
7220 XErrorEvent *error_event;
7225 void DisplayIcsInteractionTitle(message)
7228 if (oldICSInteractionTitle == NULL) {
7229 /* Magic to find the old window title, adapted from vim */
7230 char *wina = getenv("WINDOWID");
7232 Window win = (Window) atoi(wina);
7233 Window root, parent, *children;
7234 unsigned int nchildren;
7235 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7237 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7238 if (!XQueryTree(xDisplay, win, &root, &parent,
7239 &children, &nchildren)) break;
7240 if (children) XFree((void *)children);
7241 if (parent == root || parent == 0) break;
7244 XSetErrorHandler(oldHandler);
7246 if (oldICSInteractionTitle == NULL) {
7247 oldICSInteractionTitle = "xterm";
7250 printf("\033]0;%s\007", message);
7254 char pendingReplyPrefix[MSG_SIZ];
7255 ProcRef pendingReplyPR;
7257 void AskQuestionProc(w, event, prms, nprms)
7264 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7268 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7271 void AskQuestionPopDown()
7273 if (!askQuestionUp) return;
7274 XtPopdown(askQuestionShell);
7275 XtDestroyWidget(askQuestionShell);
7276 askQuestionUp = False;
7279 void AskQuestionReplyAction(w, event, prms, nprms)
7289 reply = XawDialogGetValueString(w = XtParent(w));
7290 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7291 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7292 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7293 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7294 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7295 AskQuestionPopDown();
7297 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7300 void AskQuestionCallback(w, client_data, call_data)
7302 XtPointer client_data, call_data;
7307 XtSetArg(args[0], XtNlabel, &name);
7308 XtGetValues(w, args, 1);
7310 if (strcmp(name, _("cancel")) == 0) {
7311 AskQuestionPopDown();
7313 AskQuestionReplyAction(w, NULL, NULL, NULL);
7317 void AskQuestion(title, question, replyPrefix, pr)
7318 char *title, *question, *replyPrefix;
7322 Widget popup, layout, dialog, edit;
7328 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7329 pendingReplyPR = pr;
7332 XtSetArg(args[i], XtNresizable, True); i++;
7333 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7334 askQuestionShell = popup =
7335 XtCreatePopupShell(title, transientShellWidgetClass,
7336 shellWidget, args, i);
7339 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7340 layoutArgs, XtNumber(layoutArgs));
7343 XtSetArg(args[i], XtNlabel, question); i++;
7344 XtSetArg(args[i], XtNvalue, ""); i++;
7345 XtSetArg(args[i], XtNborderWidth, 0); i++;
7346 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7349 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7350 (XtPointer) dialog);
7351 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7352 (XtPointer) dialog);
7354 XtRealizeWidget(popup);
7355 CatchDeleteWindow(popup, "AskQuestionPopDown");
7357 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7358 &x, &y, &win_x, &win_y, &mask);
7360 XtSetArg(args[0], XtNx, x - 10);
7361 XtSetArg(args[1], XtNy, y - 30);
7362 XtSetValues(popup, args, 2);
7364 XtPopup(popup, XtGrabExclusive);
7365 askQuestionUp = True;
7367 edit = XtNameToWidget(dialog, "*value");
7368 XtSetKeyboardFocus(popup, edit);
7376 if (*name == NULLCHAR) {
7378 } else if (strcmp(name, "$") == 0) {
7379 putc(BELLCHAR, stderr);
7382 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7390 PlaySound(appData.soundMove);
7396 PlaySound(appData.soundIcsWin);
7402 PlaySound(appData.soundIcsLoss);
7408 PlaySound(appData.soundIcsDraw);
7412 PlayIcsUnfinishedSound()
7414 PlaySound(appData.soundIcsUnfinished);
7420 PlaySound(appData.soundIcsAlarm);
7426 system("stty echo");
7432 system("stty -echo");
7436 Colorize(cc, continuation)
7441 int count, outCount, error;
7443 if (textColors[(int)cc].bg > 0) {
7444 if (textColors[(int)cc].fg > 0) {
7445 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7446 textColors[(int)cc].fg, textColors[(int)cc].bg);
7448 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7449 textColors[(int)cc].bg);
7452 if (textColors[(int)cc].fg > 0) {
7453 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7454 textColors[(int)cc].fg);
7456 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7459 count = strlen(buf);
7460 outCount = OutputToProcess(NoProc, buf, count, &error);
7461 if (outCount < count) {
7462 DisplayFatalError(_("Error writing to display"), error, 1);
7465 if (continuation) return;
7468 PlaySound(appData.soundShout);
7471 PlaySound(appData.soundSShout);
7474 PlaySound(appData.soundChannel1);
7477 PlaySound(appData.soundChannel);
7480 PlaySound(appData.soundKibitz);
7483 PlaySound(appData.soundTell);
7485 case ColorChallenge:
7486 PlaySound(appData.soundChallenge);
7489 PlaySound(appData.soundRequest);
7492 PlaySound(appData.soundSeek);
7503 return getpwuid(getuid())->pw_name;
7507 ExpandPathName(path)
7510 static char static_buf[4*MSG_SIZ];
7511 char *d, *s, buf[4*MSG_SIZ];
7517 while (*s && isspace(*s))
7526 if (*(s+1) == '/') {
7527 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7531 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7532 *strchr(buf, '/') = 0;
7533 pwd = getpwnam(buf);
7536 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7540 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7541 strcat(d, strchr(s+1, '/'));
7545 safeStrCpy(d, s, 4*MSG_SIZ );
7552 static char host_name[MSG_SIZ];
7554 #if HAVE_GETHOSTNAME
7555 gethostname(host_name, MSG_SIZ);
7557 #else /* not HAVE_GETHOSTNAME */
7558 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7559 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7561 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7563 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7564 #endif /* not HAVE_GETHOSTNAME */
7567 XtIntervalId delayedEventTimerXID = 0;
7568 DelayedEventCallback delayedEventCallback = 0;
7573 delayedEventTimerXID = 0;
7574 delayedEventCallback();
7578 ScheduleDelayedEvent(cb, millisec)
7579 DelayedEventCallback cb; long millisec;
7581 if(delayedEventTimerXID && delayedEventCallback == cb)
7582 // [HGM] alive: replace, rather than add or flush identical event
7583 XtRemoveTimeOut(delayedEventTimerXID);
7584 delayedEventCallback = cb;
7585 delayedEventTimerXID =
7586 XtAppAddTimeOut(appContext, millisec,
7587 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7590 DelayedEventCallback
7593 if (delayedEventTimerXID) {
7594 return delayedEventCallback;
7601 CancelDelayedEvent()
7603 if (delayedEventTimerXID) {
7604 XtRemoveTimeOut(delayedEventTimerXID);
7605 delayedEventTimerXID = 0;
7609 XtIntervalId loadGameTimerXID = 0;
7611 int LoadGameTimerRunning()
7613 return loadGameTimerXID != 0;
7616 int StopLoadGameTimer()
7618 if (loadGameTimerXID != 0) {
7619 XtRemoveTimeOut(loadGameTimerXID);
7620 loadGameTimerXID = 0;
7628 LoadGameTimerCallback(arg, id)
7632 loadGameTimerXID = 0;
7637 StartLoadGameTimer(millisec)
7641 XtAppAddTimeOut(appContext, millisec,
7642 (XtTimerCallbackProc) LoadGameTimerCallback,
7646 XtIntervalId analysisClockXID = 0;
7649 AnalysisClockCallback(arg, id)
7653 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7654 || appData.icsEngineAnalyze) { // [DM]
7655 AnalysisPeriodicEvent(0);
7656 StartAnalysisClock();
7661 StartAnalysisClock()
7664 XtAppAddTimeOut(appContext, 2000,
7665 (XtTimerCallbackProc) AnalysisClockCallback,
7669 XtIntervalId clockTimerXID = 0;
7671 int ClockTimerRunning()
7673 return clockTimerXID != 0;
7676 int StopClockTimer()
7678 if (clockTimerXID != 0) {
7679 XtRemoveTimeOut(clockTimerXID);
7688 ClockTimerCallback(arg, id)
7697 StartClockTimer(millisec)
7701 XtAppAddTimeOut(appContext, millisec,
7702 (XtTimerCallbackProc) ClockTimerCallback,
7707 DisplayTimerLabel(w, color, timer, highlight)
7716 /* check for low time warning */
7717 Pixel foregroundOrWarningColor = timerForegroundPixel;
7720 appData.lowTimeWarning &&
7721 (timer / 1000) < appData.icsAlarmTime)
7722 foregroundOrWarningColor = lowTimeWarningColor;
7724 if (appData.clockMode) {
7725 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7726 XtSetArg(args[0], XtNlabel, buf);
7728 snprintf(buf, MSG_SIZ, "%s ", color);
7729 XtSetArg(args[0], XtNlabel, buf);
7734 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7735 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7737 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7738 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7741 XtSetValues(w, args, 3);
7745 DisplayWhiteClock(timeRemaining, highlight)
7751 if(appData.noGUI) return;
7752 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7753 if (highlight && iconPixmap == bIconPixmap) {
7754 iconPixmap = wIconPixmap;
7755 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7756 XtSetValues(shellWidget, args, 1);
7761 DisplayBlackClock(timeRemaining, highlight)
7767 if(appData.noGUI) return;
7768 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7769 if (highlight && iconPixmap == wIconPixmap) {
7770 iconPixmap = bIconPixmap;
7771 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7772 XtSetValues(shellWidget, args, 1);
7790 int StartChildProcess(cmdLine, dir, pr)
7797 int to_prog[2], from_prog[2];
7801 if (appData.debugMode) {
7802 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7805 /* We do NOT feed the cmdLine to the shell; we just
7806 parse it into blank-separated arguments in the
7807 most simple-minded way possible.
7810 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7813 while(*p == ' ') p++;
7815 if(*p == '"' || *p == '\'')
7816 p = strchr(++argv[i-1], *p);
7817 else p = strchr(p, ' ');
7818 if (p == NULL) break;
7823 SetUpChildIO(to_prog, from_prog);
7825 if ((pid = fork()) == 0) {
7827 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7828 close(to_prog[1]); // first close the unused pipe ends
7829 close(from_prog[0]);
7830 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7831 dup2(from_prog[1], 1);
7832 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7833 close(from_prog[1]); // and closing again loses one of the pipes!
7834 if(fileno(stderr) >= 2) // better safe than sorry...
7835 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7837 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7842 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7844 execvp(argv[0], argv);
7846 /* If we get here, exec failed */
7851 /* Parent process */
7853 close(from_prog[1]);
7855 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7858 cp->fdFrom = from_prog[0];
7859 cp->fdTo = to_prog[1];
7864 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7865 static RETSIGTYPE AlarmCallBack(int n)
7871 DestroyChildProcess(pr, signalType)
7875 ChildProc *cp = (ChildProc *) pr;
7877 if (cp->kind != CPReal) return;
7879 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7880 signal(SIGALRM, AlarmCallBack);
7882 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7883 kill(cp->pid, SIGKILL); // kill it forcefully
7884 wait((int *) 0); // and wait again
7888 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7890 /* Process is exiting either because of the kill or because of
7891 a quit command sent by the backend; either way, wait for it to die.
7900 InterruptChildProcess(pr)
7903 ChildProc *cp = (ChildProc *) pr;
7905 if (cp->kind != CPReal) return;
7906 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7909 int OpenTelnet(host, port, pr)
7914 char cmdLine[MSG_SIZ];
7916 if (port[0] == NULLCHAR) {
7917 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7919 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7921 return StartChildProcess(cmdLine, "", pr);
7924 int OpenTCP(host, port, pr)
7930 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7931 #else /* !OMIT_SOCKETS */
7933 struct sockaddr_in sa;
7935 unsigned short uport;
7938 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7942 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7943 sa.sin_family = AF_INET;
7944 sa.sin_addr.s_addr = INADDR_ANY;
7945 uport = (unsigned short) 0;
7946 sa.sin_port = htons(uport);
7947 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7951 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7952 if (!(hp = gethostbyname(host))) {
7954 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7955 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7956 hp->h_addrtype = AF_INET;
7958 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7959 hp->h_addr_list[0] = (char *) malloc(4);
7960 hp->h_addr_list[0][0] = b0;
7961 hp->h_addr_list[0][1] = b1;
7962 hp->h_addr_list[0][2] = b2;
7963 hp->h_addr_list[0][3] = b3;
7968 sa.sin_family = hp->h_addrtype;
7969 uport = (unsigned short) atoi(port);
7970 sa.sin_port = htons(uport);
7971 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7973 if (connect(s, (struct sockaddr *) &sa,
7974 sizeof(struct sockaddr_in)) < 0) {
7978 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7985 #endif /* !OMIT_SOCKETS */
7990 int OpenCommPort(name, pr)
7997 fd = open(name, 2, 0);
7998 if (fd < 0) return errno;
8000 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8010 int OpenLoopback(pr)
8016 SetUpChildIO(to, from);
8018 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8021 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8028 int OpenRcmd(host, user, cmd, pr)
8029 char *host, *user, *cmd;
8032 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8036 #define INPUT_SOURCE_BUF_SIZE 8192
8045 char buf[INPUT_SOURCE_BUF_SIZE];
8050 DoInputCallback(closure, source, xid)
8055 InputSource *is = (InputSource *) closure;
8060 if (is->lineByLine) {
8061 count = read(is->fd, is->unused,
8062 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8064 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8067 is->unused += count;
8069 while (p < is->unused) {
8070 q = memchr(p, '\n', is->unused - p);
8071 if (q == NULL) break;
8073 (is->func)(is, is->closure, p, q - p, 0);
8077 while (p < is->unused) {
8082 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8087 (is->func)(is, is->closure, is->buf, count, error);
8091 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8098 ChildProc *cp = (ChildProc *) pr;
8100 is = (InputSource *) calloc(1, sizeof(InputSource));
8101 is->lineByLine = lineByLine;
8105 is->fd = fileno(stdin);
8107 is->kind = cp->kind;
8108 is->fd = cp->fdFrom;
8111 is->unused = is->buf;
8114 is->xid = XtAppAddInput(appContext, is->fd,
8115 (XtPointer) (XtInputReadMask),
8116 (XtInputCallbackProc) DoInputCallback,
8118 is->closure = closure;
8119 return (InputSourceRef) is;
8123 RemoveInputSource(isr)
8126 InputSource *is = (InputSource *) isr;
8128 if (is->xid == 0) return;
8129 XtRemoveInput(is->xid);
8133 int OutputToProcess(pr, message, count, outError)
8139 static int line = 0;
8140 ChildProc *cp = (ChildProc *) pr;
8145 if (appData.noJoin || !appData.useInternalWrap)
8146 outCount = fwrite(message, 1, count, stdout);
8149 int width = get_term_width();
8150 int len = wrap(NULL, message, count, width, &line);
8151 char *msg = malloc(len);
8155 outCount = fwrite(message, 1, count, stdout);
8158 dbgchk = wrap(msg, message, count, width, &line);
8159 if (dbgchk != len && appData.debugMode)
8160 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8161 outCount = fwrite(msg, 1, dbgchk, stdout);
8167 outCount = write(cp->fdTo, message, count);
8177 /* Output message to process, with "ms" milliseconds of delay
8178 between each character. This is needed when sending the logon
8179 script to ICC, which for some reason doesn't like the
8180 instantaneous send. */
8181 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8188 ChildProc *cp = (ChildProc *) pr;
8193 r = write(cp->fdTo, message++, 1);
8206 /**** Animation code by Hugh Fisher, DCS, ANU.
8208 Known problem: if a window overlapping the board is
8209 moved away while a piece is being animated underneath,
8210 the newly exposed area won't be updated properly.
8211 I can live with this.
8213 Known problem: if you look carefully at the animation
8214 of pieces in mono mode, they are being drawn as solid
8215 shapes without interior detail while moving. Fixing
8216 this would be a major complication for minimal return.
8219 /* Masks for XPM pieces. Black and white pieces can have
8220 different shapes, but in the interest of retaining my
8221 sanity pieces must have the same outline on both light
8222 and dark squares, and all pieces must use the same
8223 background square colors/images. */
8225 static int xpmDone = 0;
8228 CreateAnimMasks (pieceDepth)
8235 unsigned long plane;
8238 /* Need a bitmap just to get a GC with right depth */
8239 buf = XCreatePixmap(xDisplay, xBoardWindow,
8241 values.foreground = 1;
8242 values.background = 0;
8243 /* Don't use XtGetGC, not read only */
8244 maskGC = XCreateGC(xDisplay, buf,
8245 GCForeground | GCBackground, &values);
8246 XFreePixmap(xDisplay, buf);
8248 buf = XCreatePixmap(xDisplay, xBoardWindow,
8249 squareSize, squareSize, pieceDepth);
8250 values.foreground = XBlackPixel(xDisplay, xScreen);
8251 values.background = XWhitePixel(xDisplay, xScreen);
8252 bufGC = XCreateGC(xDisplay, buf,
8253 GCForeground | GCBackground, &values);
8255 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8256 /* Begin with empty mask */
8257 if(!xpmDone) // [HGM] pieces: keep using existing
8258 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8259 squareSize, squareSize, 1);
8260 XSetFunction(xDisplay, maskGC, GXclear);
8261 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8262 0, 0, squareSize, squareSize);
8264 /* Take a copy of the piece */
8269 XSetFunction(xDisplay, bufGC, GXcopy);
8270 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8272 0, 0, squareSize, squareSize, 0, 0);
8274 /* XOR the background (light) over the piece */
8275 XSetFunction(xDisplay, bufGC, GXxor);
8277 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8278 0, 0, squareSize, squareSize, 0, 0);
8280 XSetForeground(xDisplay, bufGC, lightSquareColor);
8281 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8284 /* We now have an inverted piece image with the background
8285 erased. Construct mask by just selecting all the non-zero
8286 pixels - no need to reconstruct the original image. */
8287 XSetFunction(xDisplay, maskGC, GXor);
8289 /* Might be quicker to download an XImage and create bitmap
8290 data from it rather than this N copies per piece, but it
8291 only takes a fraction of a second and there is a much
8292 longer delay for loading the pieces. */
8293 for (n = 0; n < pieceDepth; n ++) {
8294 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8295 0, 0, squareSize, squareSize,
8301 XFreePixmap(xDisplay, buf);
8302 XFreeGC(xDisplay, bufGC);
8303 XFreeGC(xDisplay, maskGC);
8307 InitAnimState (anim, info)
8309 XWindowAttributes * info;
8314 /* Each buffer is square size, same depth as window */
8315 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8316 squareSize, squareSize, info->depth);
8317 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8318 squareSize, squareSize, info->depth);
8320 /* Create a plain GC for blitting */
8321 mask = GCForeground | GCBackground | GCFunction |
8322 GCPlaneMask | GCGraphicsExposures;
8323 values.foreground = XBlackPixel(xDisplay, xScreen);
8324 values.background = XWhitePixel(xDisplay, xScreen);
8325 values.function = GXcopy;
8326 values.plane_mask = AllPlanes;
8327 values.graphics_exposures = False;
8328 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8330 /* Piece will be copied from an existing context at
8331 the start of each new animation/drag. */
8332 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8334 /* Outline will be a read-only copy of an existing */
8335 anim->outlineGC = None;
8341 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8342 XWindowAttributes info;
8344 if (xpmDone && gameInfo.variant == old) return;
8345 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8346 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8348 InitAnimState(&game, &info);
8349 InitAnimState(&player, &info);
8351 /* For XPM pieces, we need bitmaps to use as masks. */
8353 CreateAnimMasks(info.depth);
8359 static Boolean frameWaiting;
8361 static RETSIGTYPE FrameAlarm (sig)
8364 frameWaiting = False;
8365 /* In case System-V style signals. Needed?? */
8366 signal(SIGALRM, FrameAlarm);
8373 struct itimerval delay;
8375 XSync(xDisplay, False);
8378 frameWaiting = True;
8379 signal(SIGALRM, FrameAlarm);
8380 delay.it_interval.tv_sec =
8381 delay.it_value.tv_sec = time / 1000;
8382 delay.it_interval.tv_usec =
8383 delay.it_value.tv_usec = (time % 1000) * 1000;
8384 setitimer(ITIMER_REAL, &delay, NULL);
8385 while (frameWaiting) pause();
8386 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8387 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8388 setitimer(ITIMER_REAL, &delay, NULL);
8398 XSync(xDisplay, False);
8400 usleep(time * 1000);
8405 /* Convert board position to corner of screen rect and color */
8408 ScreenSquare(column, row, pt, color)
8409 int column; int row; XPoint * pt; int * color;
8412 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8413 pt->y = lineGap + row * (squareSize + lineGap);
8415 pt->x = lineGap + column * (squareSize + lineGap);
8416 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8418 *color = SquareColor(row, column);
8421 /* Convert window coords to square */
8424 BoardSquare(x, y, column, row)
8425 int x; int y; int * column; int * row;
8427 *column = EventToSquare(x, BOARD_WIDTH);
8428 if (flipView && *column >= 0)
8429 *column = BOARD_WIDTH - 1 - *column;
8430 *row = EventToSquare(y, BOARD_HEIGHT);
8431 if (!flipView && *row >= 0)
8432 *row = BOARD_HEIGHT - 1 - *row;
8437 #undef Max /* just in case */
8439 #define Max(a, b) ((a) > (b) ? (a) : (b))
8440 #define Min(a, b) ((a) < (b) ? (a) : (b))
8443 SetRect(rect, x, y, width, height)
8444 XRectangle * rect; int x; int y; int width; int height;
8448 rect->width = width;
8449 rect->height = height;
8452 /* Test if two frames overlap. If they do, return
8453 intersection rect within old and location of
8454 that rect within new. */
8457 Intersect(old, new, size, area, pt)
8458 XPoint * old; XPoint * new;
8459 int size; XRectangle * area; XPoint * pt;
8461 if (old->x > new->x + size || new->x > old->x + size ||
8462 old->y > new->y + size || new->y > old->y + size) {
8465 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8466 size - abs(old->x - new->x), size - abs(old->y - new->y));
8467 pt->x = Max(old->x - new->x, 0);
8468 pt->y = Max(old->y - new->y, 0);
8473 /* For two overlapping frames, return the rect(s)
8474 in the old that do not intersect with the new. */
8477 CalcUpdateRects(old, new, size, update, nUpdates)
8478 XPoint * old; XPoint * new; int size;
8479 XRectangle update[]; int * nUpdates;
8483 /* If old = new (shouldn't happen) then nothing to draw */
8484 if (old->x == new->x && old->y == new->y) {
8488 /* Work out what bits overlap. Since we know the rects
8489 are the same size we don't need a full intersect calc. */
8491 /* Top or bottom edge? */
8492 if (new->y > old->y) {
8493 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8495 } else if (old->y > new->y) {
8496 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8497 size, old->y - new->y);
8500 /* Left or right edge - don't overlap any update calculated above. */
8501 if (new->x > old->x) {
8502 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8503 new->x - old->x, size - abs(new->y - old->y));
8505 } else if (old->x > new->x) {
8506 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8507 old->x - new->x, size - abs(new->y - old->y));
8514 /* Generate a series of frame coords from start->mid->finish.
8515 The movement rate doubles until the half way point is
8516 reached, then halves back down to the final destination,
8517 which gives a nice slow in/out effect. The algorithmn
8518 may seem to generate too many intermediates for short
8519 moves, but remember that the purpose is to attract the
8520 viewers attention to the piece about to be moved and
8521 then to where it ends up. Too few frames would be less
8525 Tween(start, mid, finish, factor, frames, nFrames)
8526 XPoint * start; XPoint * mid;
8527 XPoint * finish; int factor;
8528 XPoint frames[]; int * nFrames;
8530 int fraction, n, count;
8534 /* Slow in, stepping 1/16th, then 1/8th, ... */
8536 for (n = 0; n < factor; n++)
8538 for (n = 0; n < factor; n++) {
8539 frames[count].x = start->x + (mid->x - start->x) / fraction;
8540 frames[count].y = start->y + (mid->y - start->y) / fraction;
8542 fraction = fraction / 2;
8546 frames[count] = *mid;
8549 /* Slow out, stepping 1/2, then 1/4, ... */
8551 for (n = 0; n < factor; n++) {
8552 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8553 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8555 fraction = fraction * 2;
8560 /* Draw a piece on the screen without disturbing what's there */
8563 SelectGCMask(piece, clip, outline, mask)
8564 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8568 /* Bitmap for piece being moved. */
8569 if (appData.monoMode) {
8570 *mask = *pieceToSolid(piece);
8571 } else if (useImages) {
8573 *mask = xpmMask[piece];
8575 *mask = ximMaskPm[piece];
8578 *mask = *pieceToSolid(piece);
8581 /* GC for piece being moved. Square color doesn't matter, but
8582 since it gets modified we make a copy of the original. */
8584 if (appData.monoMode)
8589 if (appData.monoMode)
8594 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8596 /* Outline only used in mono mode and is not modified */
8598 *outline = bwPieceGC;
8600 *outline = wbPieceGC;
8604 OverlayPiece(piece, clip, outline, dest)
8605 ChessSquare piece; GC clip; GC outline; Drawable dest;
8610 /* Draw solid rectangle which will be clipped to shape of piece */
8611 XFillRectangle(xDisplay, dest, clip,
8612 0, 0, squareSize, squareSize);
8613 if (appData.monoMode)
8614 /* Also draw outline in contrasting color for black
8615 on black / white on white cases */
8616 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8617 0, 0, squareSize, squareSize, 0, 0, 1);
8619 /* Copy the piece */
8624 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8626 0, 0, squareSize, squareSize,
8631 /* Animate the movement of a single piece */
8634 BeginAnimation(anim, piece, startColor, start)
8642 /* The old buffer is initialised with the start square (empty) */
8643 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8644 anim->prevFrame = *start;
8646 /* The piece will be drawn using its own bitmap as a matte */
8647 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8648 XSetClipMask(xDisplay, anim->pieceGC, mask);
8652 AnimationFrame(anim, frame, piece)
8657 XRectangle updates[4];
8662 /* Save what we are about to draw into the new buffer */
8663 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8664 frame->x, frame->y, squareSize, squareSize,
8667 /* Erase bits of the previous frame */
8668 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8669 /* Where the new frame overlapped the previous,
8670 the contents in newBuf are wrong. */
8671 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8672 overlap.x, overlap.y,
8673 overlap.width, overlap.height,
8675 /* Repaint the areas in the old that don't overlap new */
8676 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8677 for (i = 0; i < count; i++)
8678 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8679 updates[i].x - anim->prevFrame.x,
8680 updates[i].y - anim->prevFrame.y,
8681 updates[i].width, updates[i].height,
8682 updates[i].x, updates[i].y);
8684 /* Easy when no overlap */
8685 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8686 0, 0, squareSize, squareSize,
8687 anim->prevFrame.x, anim->prevFrame.y);
8690 /* Save this frame for next time round */
8691 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8692 0, 0, squareSize, squareSize,
8694 anim->prevFrame = *frame;
8696 /* Draw piece over original screen contents, not current,
8697 and copy entire rect. Wipes out overlapping piece images. */
8698 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8699 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8700 0, 0, squareSize, squareSize,
8701 frame->x, frame->y);
8705 EndAnimation (anim, finish)
8709 XRectangle updates[4];
8714 /* The main code will redraw the final square, so we
8715 only need to erase the bits that don't overlap. */
8716 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8717 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8718 for (i = 0; i < count; i++)
8719 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8720 updates[i].x - anim->prevFrame.x,
8721 updates[i].y - anim->prevFrame.y,
8722 updates[i].width, updates[i].height,
8723 updates[i].x, updates[i].y);
8725 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8726 0, 0, squareSize, squareSize,
8727 anim->prevFrame.x, anim->prevFrame.y);
8732 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8734 ChessSquare piece; int startColor;
8735 XPoint * start; XPoint * finish;
8736 XPoint frames[]; int nFrames;
8740 BeginAnimation(anim, piece, startColor, start);
8741 for (n = 0; n < nFrames; n++) {
8742 AnimationFrame(anim, &(frames[n]), piece);
8743 FrameDelay(appData.animSpeed);
8745 EndAnimation(anim, finish);
8748 /* Main control logic for deciding what to animate and how */
8751 AnimateMove(board, fromX, fromY, toX, toY)
8760 XPoint start, finish, mid;
8761 XPoint frames[kFactor * 2 + 1];
8762 int nFrames, startColor, endColor;
8764 /* Are we animating? */
8765 if (!appData.animate || appData.blindfold)
8768 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8769 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8770 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8772 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8773 piece = board[fromY][fromX];
8774 if (piece >= EmptySquare) return;
8779 hop = (piece == WhiteKnight || piece == BlackKnight);
8782 if (appData.debugMode) {
8783 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8784 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8785 piece, fromX, fromY, toX, toY); }
8787 ScreenSquare(fromX, fromY, &start, &startColor);
8788 ScreenSquare(toX, toY, &finish, &endColor);
8791 /* Knight: make diagonal movement then straight */
8792 if (abs(toY - fromY) < abs(toX - fromX)) {
8793 mid.x = start.x + (finish.x - start.x) / 2;
8797 mid.y = start.y + (finish.y - start.y) / 2;
8800 mid.x = start.x + (finish.x - start.x) / 2;
8801 mid.y = start.y + (finish.y - start.y) / 2;
8804 /* Don't use as many frames for very short moves */
8805 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8806 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8808 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8809 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8811 /* Be sure end square is redrawn */
8812 damage[0][toY][toX] = True;
8816 DragPieceBegin(x, y)
8819 int boardX, boardY, color;
8822 /* Are we animating? */
8823 if (!appData.animateDragging || appData.blindfold)
8826 /* Figure out which square we start in and the
8827 mouse position relative to top left corner. */
8828 BoardSquare(x, y, &boardX, &boardY);
8829 player.startBoardX = boardX;
8830 player.startBoardY = boardY;
8831 ScreenSquare(boardX, boardY, &corner, &color);
8832 player.startSquare = corner;
8833 player.startColor = color;
8834 /* As soon as we start dragging, the piece will jump slightly to
8835 be centered over the mouse pointer. */
8836 player.mouseDelta.x = squareSize/2;
8837 player.mouseDelta.y = squareSize/2;
8838 /* Initialise animation */
8839 player.dragPiece = PieceForSquare(boardX, boardY);
8841 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8842 player.dragActive = True;
8843 BeginAnimation(&player, player.dragPiece, color, &corner);
8844 /* Mark this square as needing to be redrawn. Note that
8845 we don't remove the piece though, since logically (ie
8846 as seen by opponent) the move hasn't been made yet. */
8847 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8848 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8849 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8850 corner.x, corner.y, squareSize, squareSize,
8851 0, 0); // [HGM] zh: unstack in stead of grab
8852 damage[0][boardY][boardX] = True;
8854 player.dragActive = False;
8864 /* Are we animating? */
8865 if (!appData.animateDragging || appData.blindfold)
8869 if (! player.dragActive)
8871 /* Move piece, maintaining same relative position
8872 of mouse within square */
8873 corner.x = x - player.mouseDelta.x;
8874 corner.y = y - player.mouseDelta.y;
8875 AnimationFrame(&player, &corner, player.dragPiece);
8877 if (appData.highlightDragging) {
8879 BoardSquare(x, y, &boardX, &boardY);
8880 SetHighlights(fromX, fromY, boardX, boardY);
8889 int boardX, boardY, color;
8892 /* Are we animating? */
8893 if (!appData.animateDragging || appData.blindfold)
8897 if (! player.dragActive)
8899 /* Last frame in sequence is square piece is
8900 placed on, which may not match mouse exactly. */
8901 BoardSquare(x, y, &boardX, &boardY);
8902 ScreenSquare(boardX, boardY, &corner, &color);
8903 EndAnimation(&player, &corner);
8905 /* Be sure end square is redrawn */
8906 damage[0][boardY][boardX] = True;
8908 /* This prevents weird things happening with fast successive
8909 clicks which on my Sun at least can cause motion events
8910 without corresponding press/release. */
8911 player.dragActive = False;
8914 /* Handle expose event while piece being dragged */
8919 if (!player.dragActive || appData.blindfold)
8922 /* What we're doing: logically, the move hasn't been made yet,
8923 so the piece is still in it's original square. But visually
8924 it's being dragged around the board. So we erase the square
8925 that the piece is on and draw it at the last known drag point. */
8926 BlankSquare(player.startSquare.x, player.startSquare.y,
8927 player.startColor, EmptySquare, xBoardWindow);
8928 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8929 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8932 #include <sys/ioctl.h>
8933 int get_term_width()
8935 int fd, default_width;
8938 default_width = 79; // this is FICS default anyway...
8940 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8942 if (!ioctl(fd, TIOCGSIZE, &win))
8943 default_width = win.ts_cols;
8944 #elif defined(TIOCGWINSZ)
8946 if (!ioctl(fd, TIOCGWINSZ, &win))
8947 default_width = win.ws_col;
8949 return default_width;
8955 static int old_width = 0;
8956 int new_width = get_term_width();
8958 if (old_width != new_width)
8959 ics_printf("set width %d\n", new_width);
8960 old_width = new_width;
8963 void NotifyFrontendLogin()