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 ****/
2649 f = fopen(appData.icsLogon, "r");
2653 safeStrCpy(buf, p, sizeof(buf)/sizeof(buf[0]) );
2654 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2655 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2656 f = fopen(buf, "r");
2661 ProcessICSInitScript(f);
2668 EditCommentPopDown();
2683 if (!menuBarWidget) return;
2684 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2686 DisplayError("menuStep.Revert", 0);
2688 XtSetSensitive(w, !grey);
2690 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2692 DisplayError("menuStep.Annotate", 0);
2694 XtSetSensitive(w, !grey);
2699 SetMenuEnables(enab)
2703 if (!menuBarWidget) return;
2704 while (enab->name != NULL) {
2705 w = XtNameToWidget(menuBarWidget, enab->name);
2707 DisplayError(enab->name, 0);
2709 XtSetSensitive(w, enab->value);
2715 Enables icsEnables[] = {
2716 { "menuFile.Mail Move", False },
2717 { "menuFile.Reload CMail Message", False },
2718 { "menuMode.Machine Black", False },
2719 { "menuMode.Machine White", False },
2720 { "menuMode.Analysis Mode", False },
2721 { "menuMode.Analyze File", False },
2722 { "menuMode.Two Machines", False },
2724 { "menuHelp.Hint", False },
2725 { "menuHelp.Book", False },
2726 { "menuStep.Move Now", False },
2727 { "menuOptions.Periodic Updates", False },
2728 { "menuOptions.Hide Thinking", False },
2729 { "menuOptions.Ponder Next Move", False },
2731 { "menuStep.Annotate", False },
2735 Enables ncpEnables[] = {
2736 { "menuFile.Mail Move", False },
2737 { "menuFile.Reload CMail Message", False },
2738 { "menuMode.Machine White", False },
2739 { "menuMode.Machine Black", False },
2740 { "menuMode.Analysis Mode", False },
2741 { "menuMode.Analyze File", False },
2742 { "menuMode.Two Machines", False },
2743 { "menuMode.ICS Client", False },
2744 { "menuMode.ICS Input Box", False },
2745 { "Action", False },
2746 { "menuStep.Revert", False },
2747 { "menuStep.Annotate", False },
2748 { "menuStep.Move Now", False },
2749 { "menuStep.Retract Move", False },
2750 { "menuOptions.Auto Comment", False },
2751 { "menuOptions.Auto Flag", False },
2752 { "menuOptions.Auto Flip View", False },
2753 { "menuOptions.Auto Observe", False },
2754 { "menuOptions.Auto Raise Board", False },
2755 { "menuOptions.Get Move List", False },
2756 { "menuOptions.ICS Alarm", False },
2757 { "menuOptions.Move Sound", False },
2758 { "menuOptions.Quiet Play", False },
2759 { "menuOptions.Hide Thinking", False },
2760 { "menuOptions.Periodic Updates", False },
2761 { "menuOptions.Ponder Next Move", False },
2762 { "menuHelp.Hint", False },
2763 { "menuHelp.Book", False },
2767 Enables gnuEnables[] = {
2768 { "menuMode.ICS Client", False },
2769 { "menuMode.ICS Input Box", False },
2770 { "menuAction.Accept", False },
2771 { "menuAction.Decline", False },
2772 { "menuAction.Rematch", False },
2773 { "menuAction.Adjourn", False },
2774 { "menuAction.Stop Examining", False },
2775 { "menuAction.Stop Observing", False },
2776 { "menuAction.Upload to Examine", False },
2777 { "menuStep.Revert", False },
2778 { "menuStep.Annotate", False },
2779 { "menuOptions.Auto Comment", False },
2780 { "menuOptions.Auto Observe", False },
2781 { "menuOptions.Auto Raise Board", False },
2782 { "menuOptions.Get Move List", False },
2783 { "menuOptions.Premove", False },
2784 { "menuOptions.Quiet Play", False },
2786 /* The next two options rely on SetCmailMode being called *after* */
2787 /* SetGNUMode so that when GNU is being used to give hints these */
2788 /* menu options are still available */
2790 { "menuFile.Mail Move", False },
2791 { "menuFile.Reload CMail Message", False },
2795 Enables cmailEnables[] = {
2797 { "menuAction.Call Flag", False },
2798 { "menuAction.Draw", True },
2799 { "menuAction.Adjourn", False },
2800 { "menuAction.Abort", False },
2801 { "menuAction.Stop Observing", False },
2802 { "menuAction.Stop Examining", False },
2803 { "menuFile.Mail Move", True },
2804 { "menuFile.Reload CMail Message", True },
2808 Enables trainingOnEnables[] = {
2809 { "menuMode.Edit Comment", False },
2810 { "menuMode.Pause", False },
2811 { "menuStep.Forward", False },
2812 { "menuStep.Backward", False },
2813 { "menuStep.Forward to End", False },
2814 { "menuStep.Back to Start", False },
2815 { "menuStep.Move Now", False },
2816 { "menuStep.Truncate Game", False },
2820 Enables trainingOffEnables[] = {
2821 { "menuMode.Edit Comment", True },
2822 { "menuMode.Pause", True },
2823 { "menuStep.Forward", True },
2824 { "menuStep.Backward", True },
2825 { "menuStep.Forward to End", True },
2826 { "menuStep.Back to Start", True },
2827 { "menuStep.Move Now", True },
2828 { "menuStep.Truncate Game", True },
2832 Enables machineThinkingEnables[] = {
2833 { "menuFile.Load Game", False },
2834 { "menuFile.Load Next Game", False },
2835 { "menuFile.Load Previous Game", False },
2836 { "menuFile.Reload Same Game", False },
2837 { "menuFile.Paste Game", False },
2838 { "menuFile.Load Position", False },
2839 { "menuFile.Load Next Position", False },
2840 { "menuFile.Load Previous Position", False },
2841 { "menuFile.Reload Same Position", False },
2842 { "menuFile.Paste Position", False },
2843 { "menuMode.Machine White", False },
2844 { "menuMode.Machine Black", False },
2845 { "menuMode.Two Machines", False },
2846 { "menuStep.Retract Move", False },
2850 Enables userThinkingEnables[] = {
2851 { "menuFile.Load Game", True },
2852 { "menuFile.Load Next Game", True },
2853 { "menuFile.Load Previous Game", True },
2854 { "menuFile.Reload Same Game", True },
2855 { "menuFile.Paste Game", True },
2856 { "menuFile.Load Position", True },
2857 { "menuFile.Load Next Position", True },
2858 { "menuFile.Load Previous Position", True },
2859 { "menuFile.Reload Same Position", True },
2860 { "menuFile.Paste Position", True },
2861 { "menuMode.Machine White", True },
2862 { "menuMode.Machine Black", True },
2863 { "menuMode.Two Machines", True },
2864 { "menuStep.Retract Move", True },
2870 SetMenuEnables(icsEnables);
2873 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2874 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2881 SetMenuEnables(ncpEnables);
2887 SetMenuEnables(gnuEnables);
2893 SetMenuEnables(cmailEnables);
2899 SetMenuEnables(trainingOnEnables);
2900 if (appData.showButtonBar) {
2901 XtSetSensitive(buttonBarWidget, False);
2907 SetTrainingModeOff()
2909 SetMenuEnables(trainingOffEnables);
2910 if (appData.showButtonBar) {
2911 XtSetSensitive(buttonBarWidget, True);
2916 SetUserThinkingEnables()
2918 if (appData.noChessProgram) return;
2919 SetMenuEnables(userThinkingEnables);
2923 SetMachineThinkingEnables()
2925 if (appData.noChessProgram) return;
2926 SetMenuEnables(machineThinkingEnables);
2928 case MachinePlaysBlack:
2929 case MachinePlaysWhite:
2930 case TwoMachinesPlay:
2931 XtSetSensitive(XtNameToWidget(menuBarWidget,
2932 ModeToWidgetName(gameMode)), True);
2939 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2940 #define HISTORY_SIZE 64
\r
2941 static char *history[HISTORY_SIZE];
\r
2942 int histIn = 0, histP = 0;
\r
2945 SaveInHistory(char *cmd)
\r
2947 if (history[histIn] != NULL) {
\r
2948 free(history[histIn]);
\r
2949 history[histIn] = NULL;
\r
2951 if (*cmd == NULLCHAR) return;
\r
2952 history[histIn] = StrSave(cmd);
\r
2953 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2954 if (history[histIn] != NULL) {
\r
2955 free(history[histIn]);
\r
2956 history[histIn] = NULL;
\r
2962 PrevInHistory(char *cmd)
\r
2965 if (histP == histIn) {
\r
2966 if (history[histIn] != NULL) free(history[histIn]);
\r
2967 history[histIn] = StrSave(cmd);
\r
2969 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2970 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2972 return history[histP];
\r
2978 if (histP == histIn) return NULL;
\r
2979 histP = (histP + 1) % HISTORY_SIZE;
\r
2980 return history[histP];
\r
2982 // end of borrowed code
\r
2984 #define Abs(n) ((n)<0 ? -(n) : (n))
2987 * Find a font that matches "pattern" that is as close as
2988 * possible to the targetPxlSize. Prefer fonts that are k
2989 * pixels smaller to fonts that are k pixels larger. The
2990 * pattern must be in the X Consortium standard format,
2991 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2992 * The return value should be freed with XtFree when no
2996 FindFont(pattern, targetPxlSize)
3000 char **fonts, *p, *best, *scalable, *scalableTail;
3001 int i, j, nfonts, minerr, err, pxlSize;
3004 char **missing_list;
3006 char *def_string, *base_fnt_lst, strInt[3];
3008 XFontStruct **fnt_list;
3010 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3011 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3012 p = strstr(pattern, "--");
3013 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3014 strcat(base_fnt_lst, strInt);
3015 strcat(base_fnt_lst, strchr(p + 2, '-'));
3017 if ((fntSet = XCreateFontSet(xDisplay,
3021 &def_string)) == NULL) {
3023 fprintf(stderr, _("Unable to create font set.\n"));
3027 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3029 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3031 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3032 programName, pattern);
3040 for (i=0; i<nfonts; i++) {
3043 if (*p != '-') continue;
3045 if (*p == NULLCHAR) break;
3046 if (*p++ == '-') j++;
3048 if (j < 7) continue;
3051 scalable = fonts[i];
3054 err = pxlSize - targetPxlSize;
3055 if (Abs(err) < Abs(minerr) ||
3056 (minerr > 0 && err < 0 && -err == minerr)) {
3062 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3063 /* If the error is too big and there is a scalable font,
3064 use the scalable font. */
3065 int headlen = scalableTail - scalable;
3066 p = (char *) XtMalloc(strlen(scalable) + 10);
3067 while (isdigit(*scalableTail)) scalableTail++;
3068 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3070 p = (char *) XtMalloc(strlen(best) + 2);
3071 safeStrCpy(p, best, strlen(best)+1 );
3073 if (appData.debugMode) {
3074 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3075 pattern, targetPxlSize, p);
3078 if (missing_count > 0)
3079 XFreeStringList(missing_list);
3080 XFreeFontSet(xDisplay, fntSet);
3082 XFreeFontNames(fonts);
3089 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3090 | GCBackground | GCFunction | GCPlaneMask;
3091 XGCValues gc_values;
3094 gc_values.plane_mask = AllPlanes;
3095 gc_values.line_width = lineGap;
3096 gc_values.line_style = LineSolid;
3097 gc_values.function = GXcopy;
3099 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3100 gc_values.background = XBlackPixel(xDisplay, xScreen);
3101 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3103 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3104 gc_values.background = XWhitePixel(xDisplay, xScreen);
3105 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 XSetFont(xDisplay, coordGC, coordFontID);
3108 // [HGM] make font for holdings counts (white on black0
3109 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3110 gc_values.background = XBlackPixel(xDisplay, xScreen);
3111 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3112 XSetFont(xDisplay, countGC, countFontID);
3114 if (appData.monoMode) {
3115 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3116 gc_values.background = XWhitePixel(xDisplay, xScreen);
3117 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3119 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3120 gc_values.background = XBlackPixel(xDisplay, xScreen);
3121 lightSquareGC = wbPieceGC
3122 = XtGetGC(shellWidget, value_mask, &gc_values);
3124 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3125 gc_values.background = XWhitePixel(xDisplay, xScreen);
3126 darkSquareGC = bwPieceGC
3127 = XtGetGC(shellWidget, value_mask, &gc_values);
3129 if (DefaultDepth(xDisplay, xScreen) == 1) {
3130 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3131 gc_values.function = GXcopyInverted;
3132 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3133 gc_values.function = GXcopy;
3134 if (XBlackPixel(xDisplay, xScreen) == 1) {
3135 bwPieceGC = darkSquareGC;
3136 wbPieceGC = copyInvertedGC;
3138 bwPieceGC = copyInvertedGC;
3139 wbPieceGC = lightSquareGC;
3143 gc_values.foreground = highlightSquareColor;
3144 gc_values.background = highlightSquareColor;
3145 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3147 gc_values.foreground = premoveHighlightColor;
3148 gc_values.background = premoveHighlightColor;
3149 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3151 gc_values.foreground = lightSquareColor;
3152 gc_values.background = darkSquareColor;
3153 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3155 gc_values.foreground = darkSquareColor;
3156 gc_values.background = lightSquareColor;
3157 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3159 gc_values.foreground = jailSquareColor;
3160 gc_values.background = jailSquareColor;
3161 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3163 gc_values.foreground = whitePieceColor;
3164 gc_values.background = darkSquareColor;
3165 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3167 gc_values.foreground = whitePieceColor;
3168 gc_values.background = lightSquareColor;
3169 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3171 gc_values.foreground = whitePieceColor;
3172 gc_values.background = jailSquareColor;
3173 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3175 gc_values.foreground = blackPieceColor;
3176 gc_values.background = darkSquareColor;
3177 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3179 gc_values.foreground = blackPieceColor;
3180 gc_values.background = lightSquareColor;
3181 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3183 gc_values.foreground = blackPieceColor;
3184 gc_values.background = jailSquareColor;
3185 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3189 void loadXIM(xim, xmask, filename, dest, mask)
3202 fp = fopen(filename, "rb");
3204 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3211 for (y=0; y<h; ++y) {
3212 for (x=0; x<h; ++x) {
3217 XPutPixel(xim, x, y, blackPieceColor);
3219 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3222 XPutPixel(xim, x, y, darkSquareColor);
3224 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3227 XPutPixel(xim, x, y, whitePieceColor);
3229 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3232 XPutPixel(xim, x, y, lightSquareColor);
3234 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3240 /* create Pixmap of piece */
3241 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3243 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3246 /* create Pixmap of clipmask
3247 Note: We assume the white/black pieces have the same
3248 outline, so we make only 6 masks. This is okay
3249 since the XPM clipmask routines do the same. */
3251 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3253 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3256 /* now create the 1-bit version */
3257 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3260 values.foreground = 1;
3261 values.background = 0;
3263 /* Don't use XtGetGC, not read only */
3264 maskGC = XCreateGC(xDisplay, *mask,
3265 GCForeground | GCBackground, &values);
3266 XCopyPlane(xDisplay, temp, *mask, maskGC,
3267 0, 0, squareSize, squareSize, 0, 0, 1);
3268 XFreePixmap(xDisplay, temp);
3273 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3275 void CreateXIMPieces()
3280 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3285 /* The XSynchronize calls were copied from CreatePieces.
3286 Not sure if needed, but can't hurt */
3287 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3290 /* temp needed by loadXIM() */
3291 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3292 0, 0, ss, ss, AllPlanes, XYPixmap);
3294 if (strlen(appData.pixmapDirectory) == 0) {
3298 if (appData.monoMode) {
3299 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3303 fprintf(stderr, _("\nLoading XIMs...\n"));
3305 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3306 fprintf(stderr, "%d", piece+1);
3307 for (kind=0; kind<4; kind++) {
3308 fprintf(stderr, ".");
3309 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3310 ExpandPathName(appData.pixmapDirectory),
3311 piece <= (int) WhiteKing ? "" : "w",
3312 pieceBitmapNames[piece],
3314 ximPieceBitmap[kind][piece] =
3315 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3316 0, 0, ss, ss, AllPlanes, XYPixmap);
3317 if (appData.debugMode)
3318 fprintf(stderr, _("(File:%s:) "), buf);
3319 loadXIM(ximPieceBitmap[kind][piece],
3321 &(xpmPieceBitmap2[kind][piece]),
3322 &(ximMaskPm2[piece]));
3323 if(piece <= (int)WhiteKing)
3324 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3326 fprintf(stderr," ");
3328 /* Load light and dark squares */
3329 /* If the LSQ and DSQ pieces don't exist, we will
3330 draw them with solid squares. */
3331 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3332 if (access(buf, 0) != 0) {
3336 fprintf(stderr, _("light square "));
3338 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3339 0, 0, ss, ss, AllPlanes, XYPixmap);
3340 if (appData.debugMode)
3341 fprintf(stderr, _("(File:%s:) "), buf);
3343 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3344 fprintf(stderr, _("dark square "));
3345 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3346 ExpandPathName(appData.pixmapDirectory), ss);
3347 if (appData.debugMode)
3348 fprintf(stderr, _("(File:%s:) "), buf);
3350 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3351 0, 0, ss, ss, AllPlanes, XYPixmap);
3352 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3353 xpmJailSquare = xpmLightSquare;
3355 fprintf(stderr, _("Done.\n"));
3357 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3361 void CreateXPMPieces()
3365 u_int ss = squareSize;
3367 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3368 XpmColorSymbol symbols[4];
3370 /* The XSynchronize calls were copied from CreatePieces.
3371 Not sure if needed, but can't hurt */
3372 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3374 /* Setup translations so piece colors match square colors */
3375 symbols[0].name = "light_piece";
3376 symbols[0].value = appData.whitePieceColor;
3377 symbols[1].name = "dark_piece";
3378 symbols[1].value = appData.blackPieceColor;
3379 symbols[2].name = "light_square";
3380 symbols[2].value = appData.lightSquareColor;
3381 symbols[3].name = "dark_square";
3382 symbols[3].value = appData.darkSquareColor;
3384 attr.valuemask = XpmColorSymbols;
3385 attr.colorsymbols = symbols;
3386 attr.numsymbols = 4;
3388 if (appData.monoMode) {
3389 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3393 if (strlen(appData.pixmapDirectory) == 0) {
3394 XpmPieces* pieces = builtInXpms;
3397 while (pieces->size != squareSize && pieces->size) pieces++;
3398 if (!pieces->size) {
3399 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3402 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3403 for (kind=0; kind<4; kind++) {
3405 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3406 pieces->xpm[piece][kind],
3407 &(xpmPieceBitmap2[kind][piece]),
3408 NULL, &attr)) != 0) {
3409 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3413 if(piece <= (int) WhiteKing)
3414 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3418 xpmJailSquare = xpmLightSquare;
3422 fprintf(stderr, _("\nLoading XPMs...\n"));
3425 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3426 fprintf(stderr, "%d ", piece+1);
3427 for (kind=0; kind<4; kind++) {
3428 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3429 ExpandPathName(appData.pixmapDirectory),
3430 piece > (int) WhiteKing ? "w" : "",
3431 pieceBitmapNames[piece],
3433 if (appData.debugMode) {
3434 fprintf(stderr, _("(File:%s:) "), buf);
3436 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3437 &(xpmPieceBitmap2[kind][piece]),
3438 NULL, &attr)) != 0) {
3439 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3440 // [HGM] missing: read of unorthodox piece failed; substitute King.
3441 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3442 ExpandPathName(appData.pixmapDirectory),
3444 if (appData.debugMode) {
3445 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3447 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3448 &(xpmPieceBitmap2[kind][piece]),
3452 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3457 if(piece <= (int) WhiteKing)
3458 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3461 /* Load light and dark squares */
3462 /* If the LSQ and DSQ pieces don't exist, we will
3463 draw them with solid squares. */
3464 fprintf(stderr, _("light square "));
3465 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3466 if (access(buf, 0) != 0) {
3470 if (appData.debugMode)
3471 fprintf(stderr, _("(File:%s:) "), buf);
3473 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3474 &xpmLightSquare, NULL, &attr)) != 0) {
3475 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3478 fprintf(stderr, _("dark square "));
3479 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3480 ExpandPathName(appData.pixmapDirectory), ss);
3481 if (appData.debugMode) {
3482 fprintf(stderr, _("(File:%s:) "), buf);
3484 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3485 &xpmDarkSquare, NULL, &attr)) != 0) {
3486 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3490 xpmJailSquare = xpmLightSquare;
3491 fprintf(stderr, _("Done.\n"));
3493 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3496 #endif /* HAVE_LIBXPM */
3499 /* No built-in bitmaps */
3504 u_int ss = squareSize;
3506 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3509 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3510 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3511 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3512 pieceBitmapNames[piece],
3513 ss, kind == SOLID ? 's' : 'o');
3514 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3515 if(piece <= (int)WhiteKing)
3516 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3520 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3524 /* With built-in bitmaps */
3527 BuiltInBits* bib = builtInBits;
3530 u_int ss = squareSize;
3532 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3535 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3537 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3538 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3539 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3540 pieceBitmapNames[piece],
3541 ss, kind == SOLID ? 's' : 'o');
3542 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3543 bib->bits[kind][piece], ss, ss);
3544 if(piece <= (int)WhiteKing)
3545 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3549 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3554 void ReadBitmap(pm, name, bits, wreq, hreq)
3557 unsigned char bits[];
3563 char msg[MSG_SIZ], fullname[MSG_SIZ];
3565 if (*appData.bitmapDirectory != NULLCHAR) {
3566 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3567 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3568 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3569 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3570 &w, &h, pm, &x_hot, &y_hot);
3571 fprintf(stderr, "load %s\n", name);
3572 if (errcode != BitmapSuccess) {
3574 case BitmapOpenFailed:
3575 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3577 case BitmapFileInvalid:
3578 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3580 case BitmapNoMemory:
3581 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3585 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3589 fprintf(stderr, _("%s: %s...using built-in\n"),
3591 } else if (w != wreq || h != hreq) {
3593 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3594 programName, fullname, w, h, wreq, hreq);
3600 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3609 if (lineGap == 0) return;
3611 /* [HR] Split this into 2 loops for non-square boards. */
3613 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3614 gridSegments[i].x1 = 0;
3615 gridSegments[i].x2 =
3616 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3617 gridSegments[i].y1 = gridSegments[i].y2
3618 = lineGap / 2 + (i * (squareSize + lineGap));
3621 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3622 gridSegments[j + i].y1 = 0;
3623 gridSegments[j + i].y2 =
3624 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3625 gridSegments[j + i].x1 = gridSegments[j + i].x2
3626 = lineGap / 2 + (j * (squareSize + lineGap));
3630 static void MenuBarSelect(w, addr, index)
3635 XtActionProc proc = (XtActionProc) addr;
3637 (proc)(NULL, NULL, NULL, NULL);
3640 void CreateMenuBarPopup(parent, name, mb)
3650 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3653 XtSetArg(args[j], XtNleftMargin, 20); j++;
3654 XtSetArg(args[j], XtNrightMargin, 20); j++;
3656 while (mi->string != NULL) {
3657 if (strcmp(mi->string, "----") == 0) {
3658 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3661 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3662 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3664 XtAddCallback(entry, XtNcallback,
3665 (XtCallbackProc) MenuBarSelect,
3666 (caddr_t) mi->proc);
3672 Widget CreateMenuBar(mb)
3676 Widget anchor, menuBar;
3678 char menuName[MSG_SIZ];
3681 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3682 XtSetArg(args[j], XtNvSpace, 0); j++;
3683 XtSetArg(args[j], XtNborderWidth, 0); j++;
3684 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3685 formWidget, args, j);
3687 while (mb->name != NULL) {
3688 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3689 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3691 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3694 shortName[0] = _(mb->name)[0];
3695 shortName[1] = NULLCHAR;
3696 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3699 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3702 XtSetArg(args[j], XtNborderWidth, 0); j++;
3703 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3705 CreateMenuBarPopup(menuBar, menuName, mb);
3711 Widget CreateButtonBar(mi)
3715 Widget button, buttonBar;
3719 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3721 XtSetArg(args[j], XtNhSpace, 0); j++;
3723 XtSetArg(args[j], XtNborderWidth, 0); j++;
3724 XtSetArg(args[j], XtNvSpace, 0); j++;
3725 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3726 formWidget, args, j);
3728 while (mi->string != NULL) {
3731 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3732 XtSetArg(args[j], XtNborderWidth, 0); j++;
3734 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3735 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3736 buttonBar, args, j);
3737 XtAddCallback(button, XtNcallback,
3738 (XtCallbackProc) MenuBarSelect,
3739 (caddr_t) mi->proc);
3746 CreatePieceMenu(name, color)
3753 ChessSquare selection;
3755 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3756 boardWidget, args, 0);
3758 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3759 String item = pieceMenuStrings[color][i];
3761 if (strcmp(item, "----") == 0) {
3762 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3765 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3766 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3768 selection = pieceMenuTranslation[color][i];
3769 XtAddCallback(entry, XtNcallback,
3770 (XtCallbackProc) PieceMenuSelect,
3771 (caddr_t) selection);
3772 if (selection == WhitePawn || selection == BlackPawn) {
3773 XtSetArg(args[0], XtNpopupOnEntry, entry);
3774 XtSetValues(menu, args, 1);
3787 ChessSquare selection;
3789 whitePieceMenu = CreatePieceMenu("menuW", 0);
3790 blackPieceMenu = CreatePieceMenu("menuB", 1);
3792 XtRegisterGrabAction(PieceMenuPopup, True,
3793 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3794 GrabModeAsync, GrabModeAsync);
3796 XtSetArg(args[0], XtNlabel, _("Drop"));
3797 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3798 boardWidget, args, 1);
3799 for (i = 0; i < DROP_MENU_SIZE; i++) {
3800 String item = dropMenuStrings[i];
3802 if (strcmp(item, "----") == 0) {
3803 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3806 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3807 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3809 selection = dropMenuTranslation[i];
3810 XtAddCallback(entry, XtNcallback,
3811 (XtCallbackProc) DropMenuSelect,
3812 (caddr_t) selection);
3817 void SetupDropMenu()
3825 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3826 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3827 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3828 dmEnables[i].piece);
3829 XtSetSensitive(entry, p != NULL || !appData.testLegality
3830 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3831 && !appData.icsActive));
3833 while (p && *p++ == dmEnables[i].piece) count++;
3834 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3836 XtSetArg(args[j], XtNlabel, label); j++;
3837 XtSetValues(entry, args, j);
3841 void PieceMenuPopup(w, event, params, num_params)
3845 Cardinal *num_params;
3847 String whichMenu; int menuNr;
3848 if (event->type == ButtonRelease)
3849 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3850 else if (event->type == ButtonPress)
3851 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3853 case 0: whichMenu = params[0]; break;
3854 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3856 case -1: if (errorUp) ErrorPopDown();
3859 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3862 static void PieceMenuSelect(w, piece, junk)
3867 if (pmFromX < 0 || pmFromY < 0) return;
3868 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3871 static void DropMenuSelect(w, piece, junk)
3876 if (pmFromX < 0 || pmFromY < 0) return;
3877 DropMenuEvent(piece, pmFromX, pmFromY);
3880 void WhiteClock(w, event, prms, nprms)
3886 if (gameMode == EditPosition || gameMode == IcsExamining) {
3887 SetWhiteToPlayEvent();
3888 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3893 void BlackClock(w, event, prms, nprms)
3899 if (gameMode == EditPosition || gameMode == IcsExamining) {
3900 SetBlackToPlayEvent();
3901 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3908 * If the user selects on a border boundary, return -1; if off the board,
3909 * return -2. Otherwise map the event coordinate to the square.
3911 int EventToSquare(x, limit)
3919 if ((x % (squareSize + lineGap)) >= squareSize)
3921 x /= (squareSize + lineGap);
3927 static void do_flash_delay(msec)
3933 static void drawHighlight(file, rank, gc)
3939 if (lineGap == 0 || appData.blindfold) return;
3942 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3943 (squareSize + lineGap);
3944 y = lineGap/2 + rank * (squareSize + lineGap);
3946 x = lineGap/2 + file * (squareSize + lineGap);
3947 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3948 (squareSize + lineGap);
3951 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3952 squareSize+lineGap, squareSize+lineGap);
3955 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3956 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3959 SetHighlights(fromX, fromY, toX, toY)
3960 int fromX, fromY, toX, toY;
3962 if (hi1X != fromX || hi1Y != fromY) {
3963 if (hi1X >= 0 && hi1Y >= 0) {
3964 drawHighlight(hi1X, hi1Y, lineGC);
3966 } // [HGM] first erase both, then draw new!
3967 if (hi2X != toX || hi2Y != toY) {
3968 if (hi2X >= 0 && hi2Y >= 0) {
3969 drawHighlight(hi2X, hi2Y, lineGC);
3972 if (hi1X != fromX || hi1Y != fromY) {
3973 if (fromX >= 0 && fromY >= 0) {
3974 drawHighlight(fromX, fromY, highlineGC);
3977 if (hi2X != toX || hi2Y != toY) {
3978 if (toX >= 0 && toY >= 0) {
3979 drawHighlight(toX, toY, highlineGC);
3991 SetHighlights(-1, -1, -1, -1);
3996 SetPremoveHighlights(fromX, fromY, toX, toY)
3997 int fromX, fromY, toX, toY;
3999 if (pm1X != fromX || pm1Y != fromY) {
4000 if (pm1X >= 0 && pm1Y >= 0) {
4001 drawHighlight(pm1X, pm1Y, lineGC);
4003 if (fromX >= 0 && fromY >= 0) {
4004 drawHighlight(fromX, fromY, prelineGC);
4007 if (pm2X != toX || pm2Y != toY) {
4008 if (pm2X >= 0 && pm2Y >= 0) {
4009 drawHighlight(pm2X, pm2Y, lineGC);
4011 if (toX >= 0 && toY >= 0) {
4012 drawHighlight(toX, toY, prelineGC);
4022 ClearPremoveHighlights()
4024 SetPremoveHighlights(-1, -1, -1, -1);
4027 static void BlankSquare(x, y, color, piece, dest)
4032 if (useImages && useImageSqs) {
4036 pm = xpmLightSquare;
4041 case 2: /* neutral */
4046 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4047 squareSize, squareSize, x, y);
4057 case 2: /* neutral */
4062 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4067 I split out the routines to draw a piece so that I could
4068 make a generic flash routine.
4070 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4072 int square_color, x, y;
4075 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4076 switch (square_color) {
4078 case 2: /* neutral */
4080 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4081 ? *pieceToOutline(piece)
4082 : *pieceToSolid(piece),
4083 dest, bwPieceGC, 0, 0,
4084 squareSize, squareSize, x, y);
4087 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4088 ? *pieceToSolid(piece)
4089 : *pieceToOutline(piece),
4090 dest, wbPieceGC, 0, 0,
4091 squareSize, squareSize, x, y);
4096 static void monoDrawPiece(piece, square_color, x, y, dest)
4098 int square_color, x, y;
4101 switch (square_color) {
4103 case 2: /* neutral */
4105 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4106 ? *pieceToOutline(piece)
4107 : *pieceToSolid(piece),
4108 dest, bwPieceGC, 0, 0,
4109 squareSize, squareSize, x, y, 1);
4112 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4113 ? *pieceToSolid(piece)
4114 : *pieceToOutline(piece),
4115 dest, wbPieceGC, 0, 0,
4116 squareSize, squareSize, x, y, 1);
4121 static void colorDrawPiece(piece, square_color, x, y, dest)
4123 int square_color, x, y;
4126 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4127 switch (square_color) {
4129 XCopyPlane(xDisplay, *pieceToSolid(piece),
4130 dest, (int) piece < (int) BlackPawn
4131 ? wlPieceGC : blPieceGC, 0, 0,
4132 squareSize, squareSize, x, y, 1);
4135 XCopyPlane(xDisplay, *pieceToSolid(piece),
4136 dest, (int) piece < (int) BlackPawn
4137 ? wdPieceGC : bdPieceGC, 0, 0,
4138 squareSize, squareSize, x, y, 1);
4140 case 2: /* neutral */
4142 XCopyPlane(xDisplay, *pieceToSolid(piece),
4143 dest, (int) piece < (int) BlackPawn
4144 ? wjPieceGC : bjPieceGC, 0, 0,
4145 squareSize, squareSize, x, y, 1);
4150 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4152 int square_color, x, y;
4157 switch (square_color) {
4159 case 2: /* neutral */
4161 if ((int)piece < (int) BlackPawn) {
4169 if ((int)piece < (int) BlackPawn) {
4177 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4178 dest, wlPieceGC, 0, 0,
4179 squareSize, squareSize, x, y);
4182 typedef void (*DrawFunc)();
4184 DrawFunc ChooseDrawFunc()
4186 if (appData.monoMode) {
4187 if (DefaultDepth(xDisplay, xScreen) == 1) {
4188 return monoDrawPiece_1bit;
4190 return monoDrawPiece;
4194 return colorDrawPieceImage;
4196 return colorDrawPiece;
4200 /* [HR] determine square color depending on chess variant. */
4201 static int SquareColor(row, column)
4206 if (gameInfo.variant == VariantXiangqi) {
4207 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4209 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4211 } else if (row <= 4) {
4217 square_color = ((column + row) % 2) == 1;
4220 /* [hgm] holdings: next line makes all holdings squares light */
4221 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4223 return square_color;
4226 void DrawSquare(row, column, piece, do_flash)
4227 int row, column, do_flash;
4230 int square_color, x, y, direction, font_ascent, font_descent;
4233 XCharStruct overall;
4237 /* Calculate delay in milliseconds (2-delays per complete flash) */
4238 flash_delay = 500 / appData.flashRate;
4241 x = lineGap + ((BOARD_WIDTH-1)-column) *
4242 (squareSize + lineGap);
4243 y = lineGap + row * (squareSize + lineGap);
4245 x = lineGap + column * (squareSize + lineGap);
4246 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4247 (squareSize + lineGap);
4250 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4252 square_color = SquareColor(row, column);
4254 if ( // [HGM] holdings: blank out area between board and holdings
4255 column == BOARD_LEFT-1 || column == BOARD_RGHT
4256 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4257 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4258 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4260 // [HGM] print piece counts next to holdings
4261 string[1] = NULLCHAR;
4262 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4263 string[0] = '0' + piece;
4264 XTextExtents(countFontStruct, string, 1, &direction,
4265 &font_ascent, &font_descent, &overall);
4266 if (appData.monoMode) {
4267 XDrawImageString(xDisplay, xBoardWindow, countGC,
4268 x + squareSize - overall.width - 2,
4269 y + font_ascent + 1, string, 1);
4271 XDrawString(xDisplay, xBoardWindow, countGC,
4272 x + squareSize - overall.width - 2,
4273 y + font_ascent + 1, string, 1);
4276 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4277 string[0] = '0' + piece;
4278 XTextExtents(countFontStruct, string, 1, &direction,
4279 &font_ascent, &font_descent, &overall);
4280 if (appData.monoMode) {
4281 XDrawImageString(xDisplay, xBoardWindow, countGC,
4282 x + 2, y + font_ascent + 1, string, 1);
4284 XDrawString(xDisplay, xBoardWindow, countGC,
4285 x + 2, y + font_ascent + 1, string, 1);
4289 if (piece == EmptySquare || appData.blindfold) {
4290 BlankSquare(x, y, square_color, piece, xBoardWindow);
4292 drawfunc = ChooseDrawFunc();
4293 if (do_flash && appData.flashCount > 0) {
4294 for (i=0; i<appData.flashCount; ++i) {
4296 drawfunc(piece, square_color, x, y, xBoardWindow);
4297 XSync(xDisplay, False);
4298 do_flash_delay(flash_delay);
4300 BlankSquare(x, y, square_color, piece, xBoardWindow);
4301 XSync(xDisplay, False);
4302 do_flash_delay(flash_delay);
4305 drawfunc(piece, square_color, x, y, xBoardWindow);
4309 string[1] = NULLCHAR;
4310 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4311 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4312 string[0] = 'a' + column - BOARD_LEFT;
4313 XTextExtents(coordFontStruct, string, 1, &direction,
4314 &font_ascent, &font_descent, &overall);
4315 if (appData.monoMode) {
4316 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4317 x + squareSize - overall.width - 2,
4318 y + squareSize - font_descent - 1, string, 1);
4320 XDrawString(xDisplay, xBoardWindow, coordGC,
4321 x + squareSize - overall.width - 2,
4322 y + squareSize - font_descent - 1, string, 1);
4325 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4326 string[0] = ONE + row;
4327 XTextExtents(coordFontStruct, string, 1, &direction,
4328 &font_ascent, &font_descent, &overall);
4329 if (appData.monoMode) {
4330 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4331 x + 2, y + font_ascent + 1, string, 1);
4333 XDrawString(xDisplay, xBoardWindow, coordGC,
4334 x + 2, y + font_ascent + 1, string, 1);
4337 if(!partnerUp && marker[row][column]) {
4338 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4339 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4344 /* Why is this needed on some versions of X? */
4345 void EventProc(widget, unused, event)
4350 if (!XtIsRealized(widget))
4353 switch (event->type) {
4355 if (event->xexpose.count > 0) return; /* no clipping is done */
4356 XDrawPosition(widget, True, NULL);
4357 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4358 flipView = !flipView; partnerUp = !partnerUp;
4359 XDrawPosition(widget, True, NULL);
4360 flipView = !flipView; partnerUp = !partnerUp;
4364 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4371 void DrawPosition(fullRedraw, board)
4372 /*Boolean*/int fullRedraw;
4375 XDrawPosition(boardWidget, fullRedraw, board);
4378 /* Returns 1 if there are "too many" differences between b1 and b2
4379 (i.e. more than 1 move was made) */
4380 static int too_many_diffs(b1, b2)
4386 for (i=0; i<BOARD_HEIGHT; ++i) {
4387 for (j=0; j<BOARD_WIDTH; ++j) {
4388 if (b1[i][j] != b2[i][j]) {
4389 if (++c > 4) /* Castling causes 4 diffs */
4398 /* Matrix describing castling maneuvers */
4399 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4400 static int castling_matrix[4][5] = {
4401 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4402 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4403 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4404 { 7, 7, 4, 5, 6 } /* 0-0, black */
4407 /* Checks whether castling occurred. If it did, *rrow and *rcol
4408 are set to the destination (row,col) of the rook that moved.
4410 Returns 1 if castling occurred, 0 if not.
4412 Note: Only handles a max of 1 castling move, so be sure
4413 to call too_many_diffs() first.
4415 static int check_castle_draw(newb, oldb, rrow, rcol)
4422 /* For each type of castling... */
4423 for (i=0; i<4; ++i) {
4424 r = castling_matrix[i];
4426 /* Check the 4 squares involved in the castling move */
4428 for (j=1; j<=4; ++j) {
4429 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4436 /* All 4 changed, so it must be a castling move */
4445 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4446 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4448 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4451 void DrawSeekBackground( int left, int top, int right, int bottom )
4453 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4456 void DrawSeekText(char *buf, int x, int y)
4458 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4461 void DrawSeekDot(int x, int y, int colorNr)
4463 int square = colorNr & 0x80;
4466 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4468 XFillRectangle(xDisplay, xBoardWindow, color,
4469 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4471 XFillArc(xDisplay, xBoardWindow, color,
4472 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4475 static int damage[2][BOARD_RANKS][BOARD_FILES];
4478 * event handler for redrawing the board
4480 void XDrawPosition(w, repaint, board)
4482 /*Boolean*/int repaint;
4486 static int lastFlipView = 0;
4487 static int lastBoardValid[2] = {0, 0};
4488 static Board lastBoard[2];
4491 int nr = twoBoards*partnerUp;
4493 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4495 if (board == NULL) {
4496 if (!lastBoardValid[nr]) return;
4497 board = lastBoard[nr];
4499 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4500 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4506 * It would be simpler to clear the window with XClearWindow()
4507 * but this causes a very distracting flicker.
4510 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4512 /* If too much changes (begin observing new game, etc.), don't
4514 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4516 /* Special check for castling so we don't flash both the king
4517 and the rook (just flash the king). */
4519 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4520 /* Draw rook with NO flashing. King will be drawn flashing later */
4521 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4522 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4526 /* First pass -- Draw (newly) empty squares and repair damage.
4527 This prevents you from having a piece show up twice while it
4528 is flashing on its new square */
4529 for (i = 0; i < BOARD_HEIGHT; i++)
4530 for (j = 0; j < BOARD_WIDTH; j++)
4531 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4532 || damage[nr][i][j]) {
4533 DrawSquare(i, j, board[i][j], 0);
4534 damage[nr][i][j] = False;
4537 /* Second pass -- Draw piece(s) in new position and flash them */
4538 for (i = 0; i < BOARD_HEIGHT; i++)
4539 for (j = 0; j < BOARD_WIDTH; j++)
4540 if (board[i][j] != lastBoard[nr][i][j]) {
4541 DrawSquare(i, j, board[i][j], do_flash);
4545 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4546 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4547 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4549 for (i = 0; i < BOARD_HEIGHT; i++)
4550 for (j = 0; j < BOARD_WIDTH; j++) {
4551 DrawSquare(i, j, board[i][j], 0);
4552 damage[nr][i][j] = False;
4556 CopyBoard(lastBoard[nr], board);
4557 lastBoardValid[nr] = 1;
4558 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4559 lastFlipView = flipView;
4561 /* Draw highlights */
4562 if (pm1X >= 0 && pm1Y >= 0) {
4563 drawHighlight(pm1X, pm1Y, prelineGC);
4565 if (pm2X >= 0 && pm2Y >= 0) {
4566 drawHighlight(pm2X, pm2Y, prelineGC);
4568 if (hi1X >= 0 && hi1Y >= 0) {
4569 drawHighlight(hi1X, hi1Y, highlineGC);
4571 if (hi2X >= 0 && hi2Y >= 0) {
4572 drawHighlight(hi2X, hi2Y, highlineGC);
4575 /* If piece being dragged around board, must redraw that too */
4578 XSync(xDisplay, False);
4583 * event handler for redrawing the board
4585 void DrawPositionProc(w, event, prms, nprms)
4591 XDrawPosition(w, True, NULL);
4596 * event handler for parsing user moves
4598 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4599 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4600 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4601 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4602 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4603 // and at the end FinishMove() to perform the move after optional promotion popups.
4604 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4605 void HandleUserMove(w, event, prms, nprms)
4611 if (w != boardWidget || errorExitStatus != -1) return;
4614 if (event->type == ButtonPress) {
4615 XtPopdown(promotionShell);
4616 XtDestroyWidget(promotionShell);
4617 promotionUp = False;
4625 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4626 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4627 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4630 void AnimateUserMove (Widget w, XEvent * event,
4631 String * params, Cardinal * nParams)
4633 DragPieceMove(event->xmotion.x, event->xmotion.y);
4636 void HandlePV (Widget w, XEvent * event,
4637 String * params, Cardinal * nParams)
4638 { // [HGM] pv: walk PV
4639 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4642 Widget CommentCreate(name, text, mutable, callback, lines)
4644 int /*Boolean*/ mutable;
4645 XtCallbackProc callback;
4649 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4654 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4655 XtGetValues(boardWidget, args, j);
4658 XtSetArg(args[j], XtNresizable, True); j++;
4661 XtCreatePopupShell(name, topLevelShellWidgetClass,
4662 shellWidget, args, j);
4665 XtCreatePopupShell(name, transientShellWidgetClass,
4666 shellWidget, args, j);
4669 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4670 layoutArgs, XtNumber(layoutArgs));
4672 XtCreateManagedWidget("form", formWidgetClass, layout,
4673 formArgs, XtNumber(formArgs));
4677 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4678 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4680 XtSetArg(args[j], XtNstring, text); j++;
4681 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4682 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4683 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4684 XtSetArg(args[j], XtNright, XtChainRight); j++;
4685 XtSetArg(args[j], XtNresizable, True); j++;
4686 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4687 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4688 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4689 XtSetArg(args[j], XtNautoFill, True); j++;
4690 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4692 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4693 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4697 XtSetArg(args[j], XtNfromVert, edit); j++;
4698 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4699 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4700 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4701 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4703 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4704 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4707 XtSetArg(args[j], XtNfromVert, edit); j++;
4708 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4709 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4710 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4711 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4712 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4714 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4715 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4718 XtSetArg(args[j], XtNfromVert, edit); j++;
4719 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4720 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4721 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4722 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4723 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4725 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4726 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4729 XtSetArg(args[j], XtNfromVert, edit); 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(_("close"), commandWidgetClass, form, args, j);
4736 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4739 XtSetArg(args[j], XtNfromVert, edit); j++;
4740 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4741 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4742 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4743 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4744 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4746 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4747 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4750 XtRealizeWidget(shell);
4752 if (commentX == -1) {
4755 Dimension pw_height;
4756 Dimension ew_height;
4759 XtSetArg(args[j], XtNheight, &ew_height); j++;
4760 XtGetValues(edit, args, j);
4763 XtSetArg(args[j], XtNheight, &pw_height); j++;
4764 XtGetValues(shell, args, j);
4765 commentH = pw_height + (lines - 1) * ew_height;
4766 commentW = bw_width - 16;
4768 XSync(xDisplay, False);
4770 /* This code seems to tickle an X bug if it is executed too soon
4771 after xboard starts up. The coordinates get transformed as if
4772 the main window was positioned at (0, 0).
4774 XtTranslateCoords(shellWidget,
4775 (bw_width - commentW) / 2, 0 - commentH / 2,
4776 &commentX, &commentY);
4778 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4779 RootWindowOfScreen(XtScreen(shellWidget)),
4780 (bw_width - commentW) / 2, 0 - commentH / 2,
4785 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4788 if(wpComment.width > 0) {
4789 commentX = wpComment.x;
4790 commentY = wpComment.y;
4791 commentW = wpComment.width;
4792 commentH = wpComment.height;
4796 XtSetArg(args[j], XtNheight, commentH); j++;
4797 XtSetArg(args[j], XtNwidth, commentW); j++;
4798 XtSetArg(args[j], XtNx, commentX); j++;
4799 XtSetArg(args[j], XtNy, commentY); j++;
4800 XtSetValues(shell, args, j);
4801 XtSetKeyboardFocus(shell, edit);
4806 /* Used for analysis window and ICS input window */
4807 Widget MiscCreate(name, text, mutable, callback, lines)
4809 int /*Boolean*/ mutable;
4810 XtCallbackProc callback;
4814 Widget shell, layout, form, edit;
4816 Dimension bw_width, pw_height, ew_height, w, h;
4822 XtSetArg(args[j], XtNresizable, True); j++;
4825 XtCreatePopupShell(name, topLevelShellWidgetClass,
4826 shellWidget, args, j);
4829 XtCreatePopupShell(name, transientShellWidgetClass,
4830 shellWidget, args, j);
4833 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4834 layoutArgs, XtNumber(layoutArgs));
4836 XtCreateManagedWidget("form", formWidgetClass, layout,
4837 formArgs, XtNumber(formArgs));
4841 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4842 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4844 XtSetArg(args[j], XtNstring, text); j++;
4845 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4846 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4847 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4848 XtSetArg(args[j], XtNright, XtChainRight); j++;
4849 XtSetArg(args[j], XtNresizable, True); j++;
4850 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4851 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4852 XtSetArg(args[j], XtNautoFill, True); j++;
4853 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4855 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4857 XtRealizeWidget(shell);
4860 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4861 XtGetValues(boardWidget, args, j);
4864 XtSetArg(args[j], XtNheight, &ew_height); j++;
4865 XtGetValues(edit, args, j);
4868 XtSetArg(args[j], XtNheight, &pw_height); j++;
4869 XtGetValues(shell, args, j);
4870 h = pw_height + (lines - 1) * ew_height;
4873 XSync(xDisplay, False);
4875 /* This code seems to tickle an X bug if it is executed too soon
4876 after xboard starts up. The coordinates get transformed as if
4877 the main window was positioned at (0, 0).
4879 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4881 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4882 RootWindowOfScreen(XtScreen(shellWidget)),
4883 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4887 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4890 XtSetArg(args[j], XtNheight, h); j++;
4891 XtSetArg(args[j], XtNwidth, w); j++;
4892 XtSetArg(args[j], XtNx, x); j++;
4893 XtSetArg(args[j], XtNy, y); j++;
4894 XtSetValues(shell, args, j);
4900 static int savedIndex; /* gross that this is global */
4902 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4905 XawTextPosition index, dummy;
4908 XawTextGetSelectionPos(w, &index, &dummy);
4909 XtSetArg(arg, XtNstring, &val);
4910 XtGetValues(w, &arg, 1);
4911 ReplaceComment(savedIndex, val);
4912 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4913 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4916 void EditCommentPopUp(index, title, text)
4925 if (text == NULL) text = "";
4927 if (editShell == NULL) {
4929 CommentCreate(title, text, True, EditCommentCallback, 4);
4930 XtRealizeWidget(editShell);
4931 CatchDeleteWindow(editShell, "EditCommentPopDown");
4933 edit = XtNameToWidget(editShell, "*form.text");
4935 XtSetArg(args[j], XtNstring, text); j++;
4936 XtSetValues(edit, args, j);
4938 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4939 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4940 XtSetValues(editShell, args, j);
4943 XtPopup(editShell, XtGrabNone);
4947 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4948 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4952 void EditCommentCallback(w, client_data, call_data)
4954 XtPointer client_data, call_data;
4962 XtSetArg(args[j], XtNlabel, &name); j++;
4963 XtGetValues(w, args, j);
4965 if (strcmp(name, _("ok")) == 0) {
4966 edit = XtNameToWidget(editShell, "*form.text");
4968 XtSetArg(args[j], XtNstring, &val); j++;
4969 XtGetValues(edit, args, j);
4970 ReplaceComment(savedIndex, val);
4971 EditCommentPopDown();
4972 } else if (strcmp(name, _("cancel")) == 0) {
4973 EditCommentPopDown();
4974 } else if (strcmp(name, _("clear")) == 0) {
4975 edit = XtNameToWidget(editShell, "*form.text");
4976 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4977 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4981 void EditCommentPopDown()
4986 if (!editUp) return;
4988 XtSetArg(args[j], XtNx, &commentX); j++;
4989 XtSetArg(args[j], XtNy, &commentY); j++;
4990 XtSetArg(args[j], XtNheight, &commentH); j++;
4991 XtSetArg(args[j], XtNwidth, &commentW); j++;
4992 XtGetValues(editShell, args, j);
4993 XtPopdown(editShell);
4996 XtSetArg(args[j], XtNleftBitmap, None); j++;
4997 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5001 void ICSInputBoxPopUp()
5006 char *title = _("ICS Input");
5009 if (ICSInputShell == NULL) {
5010 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5011 tr = XtParseTranslationTable(ICSInputTranslations);
5012 edit = XtNameToWidget(ICSInputShell, "*form.text");
5013 XtOverrideTranslations(edit, tr);
5014 XtRealizeWidget(ICSInputShell);
5015 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5018 edit = XtNameToWidget(ICSInputShell, "*form.text");
5020 XtSetArg(args[j], XtNstring, ""); j++;
5021 XtSetValues(edit, args, j);
5023 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5024 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5025 XtSetValues(ICSInputShell, args, j);
5028 XtPopup(ICSInputShell, XtGrabNone);
5029 XtSetKeyboardFocus(ICSInputShell, edit);
5031 ICSInputBoxUp = True;
5033 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5034 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5038 void ICSInputSendText()
5045 edit = XtNameToWidget(ICSInputShell, "*form.text");
5047 XtSetArg(args[j], XtNstring, &val); j++;
5048 XtGetValues(edit, args, j);
5050 SendMultiLineToICS(val);
5051 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5052 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5055 void ICSInputBoxPopDown()
5060 if (!ICSInputBoxUp) return;
5062 XtPopdown(ICSInputShell);
5063 ICSInputBoxUp = False;
5065 XtSetArg(args[j], XtNleftBitmap, None); j++;
5066 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5070 void CommentPopUp(title, text)
5077 savedIndex = currentMove; // [HGM] vari
5078 if (commentShell == NULL) {
5080 CommentCreate(title, text, False, CommentCallback, 4);
5081 XtRealizeWidget(commentShell);
5082 CatchDeleteWindow(commentShell, "CommentPopDown");
5084 edit = XtNameToWidget(commentShell, "*form.text");
5086 XtSetArg(args[j], XtNstring, text); j++;
5087 XtSetValues(edit, args, j);
5089 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5090 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5091 XtSetValues(commentShell, args, j);
5094 XtPopup(commentShell, XtGrabNone);
5095 XSync(xDisplay, False);
5100 void CommentCallback(w, client_data, call_data)
5102 XtPointer client_data, call_data;
5109 XtSetArg(args[j], XtNlabel, &name); j++;
5110 XtGetValues(w, args, j);
5112 if (strcmp(name, _("close")) == 0) {
5114 } else if (strcmp(name, _("edit")) == 0) {
5121 void CommentPopDown()
5126 if (!commentUp) return;
5128 XtSetArg(args[j], XtNx, &commentX); j++;
5129 XtSetArg(args[j], XtNy, &commentY); j++;
5130 XtSetArg(args[j], XtNwidth, &commentW); j++;
5131 XtSetArg(args[j], XtNheight, &commentH); j++;
5132 XtGetValues(commentShell, args, j);
5133 XtPopdown(commentShell);
5134 XSync(xDisplay, False);
5138 void FileNamePopUp(label, def, proc, openMode)
5144 fileProc = proc; /* I can't see a way not */
5145 fileOpenMode = openMode; /* to use globals here */
5146 { // [HGM] use file-selector dialog stolen from Ghostview
5148 int index; // this is not supported yet
5150 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5151 def, openMode, NULL, &name))
5152 (void) (*fileProc)(f, index=0, name);
5156 void FileNamePopDown()
5158 if (!filenameUp) return;
5159 XtPopdown(fileNameShell);
5160 XtDestroyWidget(fileNameShell);
5165 void FileNameCallback(w, client_data, call_data)
5167 XtPointer client_data, call_data;
5172 XtSetArg(args[0], XtNlabel, &name);
5173 XtGetValues(w, args, 1);
5175 if (strcmp(name, _("cancel")) == 0) {
5180 FileNameAction(w, NULL, NULL, NULL);
5183 void FileNameAction(w, event, prms, nprms)
5195 name = XawDialogGetValueString(w = XtParent(w));
5197 if ((name != NULL) && (*name != NULLCHAR)) {
5198 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5199 XtPopdown(w = XtParent(XtParent(w)));
5203 p = strrchr(buf, ' ');
5210 fullname = ExpandPathName(buf);
5212 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5215 f = fopen(fullname, fileOpenMode);
5217 DisplayError(_("Failed to open file"), errno);
5219 (void) (*fileProc)(f, index, buf);
5226 XtPopdown(w = XtParent(XtParent(w)));
5232 void PromotionPopUp()
5235 Widget dialog, layout;
5237 Dimension bw_width, pw_width;
5241 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5242 XtGetValues(boardWidget, args, j);
5245 XtSetArg(args[j], XtNresizable, True); j++;
5246 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5248 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5249 shellWidget, args, j);
5251 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5252 layoutArgs, XtNumber(layoutArgs));
5255 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5256 XtSetArg(args[j], XtNborderWidth, 0); j++;
5257 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5260 if(gameInfo.variant != VariantShogi) {
5261 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5262 (XtPointer) dialog);
5263 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5264 (XtPointer) dialog);
5265 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5266 (XtPointer) dialog);
5267 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5268 (XtPointer) dialog);
5269 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5270 gameInfo.variant == VariantGiveaway) {
5271 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5272 (XtPointer) dialog);
5274 if(gameInfo.variant == VariantCapablanca ||
5275 gameInfo.variant == VariantGothic ||
5276 gameInfo.variant == VariantCapaRandom) {
5277 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5278 (XtPointer) dialog);
5279 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5280 (XtPointer) dialog);
5282 } else // [HGM] shogi
5284 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5285 (XtPointer) dialog);
5286 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5287 (XtPointer) dialog);
5289 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5290 (XtPointer) dialog);
5292 XtRealizeWidget(promotionShell);
5293 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5296 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5297 XtGetValues(promotionShell, args, j);
5299 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5300 lineGap + squareSize/3 +
5301 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5302 0 : 6*(squareSize + lineGap)), &x, &y);
5305 XtSetArg(args[j], XtNx, x); j++;
5306 XtSetArg(args[j], XtNy, y); j++;
5307 XtSetValues(promotionShell, args, j);
5309 XtPopup(promotionShell, XtGrabNone);
5314 void PromotionPopDown()
5316 if (!promotionUp) return;
5317 XtPopdown(promotionShell);
5318 XtDestroyWidget(promotionShell);
5319 promotionUp = False;
5322 void PromotionCallback(w, client_data, call_data)
5324 XtPointer client_data, call_data;
5330 XtSetArg(args[0], XtNlabel, &name);
5331 XtGetValues(w, args, 1);
5335 if (fromX == -1) return;
5337 if (strcmp(name, _("cancel")) == 0) {
5341 } else if (strcmp(name, _("Knight")) == 0) {
5343 } else if (strcmp(name, _("Promote")) == 0) {
5345 } else if (strcmp(name, _("Defer")) == 0) {
5348 promoChar = ToLower(name[0]);
5351 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5353 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5354 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5359 void ErrorCallback(w, client_data, call_data)
5361 XtPointer client_data, call_data;
5364 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5366 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5372 if (!errorUp) return;
5374 XtPopdown(errorShell);
5375 XtDestroyWidget(errorShell);
5376 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5379 void ErrorPopUp(title, label, modal)
5380 char *title, *label;
5384 Widget dialog, layout;
5388 Dimension bw_width, pw_width;
5389 Dimension pw_height;
5393 XtSetArg(args[i], XtNresizable, True); i++;
5394 XtSetArg(args[i], XtNtitle, title); i++;
5396 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5397 shellWidget, args, i);
5399 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5400 layoutArgs, XtNumber(layoutArgs));
5403 XtSetArg(args[i], XtNlabel, label); i++;
5404 XtSetArg(args[i], XtNborderWidth, 0); i++;
5405 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5408 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5410 XtRealizeWidget(errorShell);
5411 CatchDeleteWindow(errorShell, "ErrorPopDown");
5414 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5415 XtGetValues(boardWidget, args, i);
5417 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5418 XtSetArg(args[i], XtNheight, &pw_height); i++;
5419 XtGetValues(errorShell, args, i);
5422 /* This code seems to tickle an X bug if it is executed too soon
5423 after xboard starts up. The coordinates get transformed as if
5424 the main window was positioned at (0, 0).
5426 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5427 0 - pw_height + squareSize / 3, &x, &y);
5429 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5430 RootWindowOfScreen(XtScreen(boardWidget)),
5431 (bw_width - pw_width) / 2,
5432 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5436 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5439 XtSetArg(args[i], XtNx, x); i++;
5440 XtSetArg(args[i], XtNy, y); i++;
5441 XtSetValues(errorShell, args, i);
5444 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5447 /* Disable all user input other than deleting the window */
5448 static int frozen = 0;
5452 /* Grab by a widget that doesn't accept input */
5453 XtAddGrab(messageWidget, TRUE, FALSE);
5457 /* Undo a FreezeUI */
5460 if (!frozen) return;
5461 XtRemoveGrab(messageWidget);
5465 char *ModeToWidgetName(mode)
5469 case BeginningOfGame:
5470 if (appData.icsActive)
5471 return "menuMode.ICS Client";
5472 else if (appData.noChessProgram ||
5473 *appData.cmailGameName != NULLCHAR)
5474 return "menuMode.Edit Game";
5476 return "menuMode.Machine Black";
5477 case MachinePlaysBlack:
5478 return "menuMode.Machine Black";
5479 case MachinePlaysWhite:
5480 return "menuMode.Machine White";
5482 return "menuMode.Analysis Mode";
5484 return "menuMode.Analyze File";
5485 case TwoMachinesPlay:
5486 return "menuMode.Two Machines";
5488 return "menuMode.Edit Game";
5489 case PlayFromGameFile:
5490 return "menuFile.Load Game";
5492 return "menuMode.Edit Position";
5494 return "menuMode.Training";
5495 case IcsPlayingWhite:
5496 case IcsPlayingBlack:
5500 return "menuMode.ICS Client";
5507 void ModeHighlight()
5510 static int oldPausing = FALSE;
5511 static GameMode oldmode = (GameMode) -1;
5514 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5516 if (pausing != oldPausing) {
5517 oldPausing = pausing;
5519 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5521 XtSetArg(args[0], XtNleftBitmap, None);
5523 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5526 if (appData.showButtonBar) {
5527 /* Always toggle, don't set. Previous code messes up when
5528 invoked while the button is pressed, as releasing it
5529 toggles the state again. */
5532 XtSetArg(args[0], XtNbackground, &oldbg);
5533 XtSetArg(args[1], XtNforeground, &oldfg);
5534 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5536 XtSetArg(args[0], XtNbackground, oldfg);
5537 XtSetArg(args[1], XtNforeground, oldbg);
5539 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5543 wname = ModeToWidgetName(oldmode);
5544 if (wname != NULL) {
5545 XtSetArg(args[0], XtNleftBitmap, None);
5546 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5548 wname = ModeToWidgetName(gameMode);
5549 if (wname != NULL) {
5550 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5551 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5555 /* Maybe all the enables should be handled here, not just this one */
5556 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5557 gameMode == Training || gameMode == PlayFromGameFile);
5562 * Button/menu procedures
5564 void ResetProc(w, event, prms, nprms)
5573 int LoadGamePopUp(f, gameNumber, title)
5578 cmailMsgLoaded = FALSE;
5579 if (gameNumber == 0) {
5580 int error = GameListBuild(f);
5582 DisplayError(_("Cannot build game list"), error);
5583 } else if (!ListEmpty(&gameList) &&
5584 ((ListGame *) gameList.tailPred)->number > 1) {
5585 GameListPopUp(f, title);
5591 return LoadGame(f, gameNumber, title, FALSE);
5594 void LoadGameProc(w, event, prms, nprms)
5600 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5603 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5606 void LoadNextGameProc(w, event, prms, nprms)
5615 void LoadPrevGameProc(w, event, prms, nprms)
5624 void ReloadGameProc(w, event, prms, nprms)
5633 void LoadNextPositionProc(w, event, prms, nprms)
5642 void LoadPrevPositionProc(w, event, prms, nprms)
5651 void ReloadPositionProc(w, event, prms, nprms)
5660 void LoadPositionProc(w, event, prms, nprms)
5666 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5669 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5672 void SaveGameProc(w, event, prms, nprms)
5678 FileNamePopUp(_("Save game file name?"),
5679 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5683 void SavePositionProc(w, event, prms, nprms)
5689 FileNamePopUp(_("Save position file name?"),
5690 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5694 void ReloadCmailMsgProc(w, event, prms, nprms)
5700 ReloadCmailMsgEvent(FALSE);
5703 void MailMoveProc(w, event, prms, nprms)
5712 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5713 char *selected_fen_position=NULL;
5716 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5717 Atom *type_return, XtPointer *value_return,
5718 unsigned long *length_return, int *format_return)
5720 char *selection_tmp;
5722 if (!selected_fen_position) return False; /* should never happen */
5723 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5724 /* note: since no XtSelectionDoneProc was registered, Xt will
5725 * automatically call XtFree on the value returned. So have to
5726 * make a copy of it allocated with XtMalloc */
5727 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5728 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5730 *value_return=selection_tmp;
5731 *length_return=strlen(selection_tmp);
5732 *type_return=*target;
5733 *format_return = 8; /* bits per byte */
5735 } else if (*target == XA_TARGETS(xDisplay)) {
5736 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5737 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5738 targets_tmp[1] = XA_STRING;
5739 *value_return = targets_tmp;
5740 *type_return = XA_ATOM;
5742 *format_return = 8 * sizeof(Atom);
5743 if (*format_return > 32) {
5744 *length_return *= *format_return / 32;
5745 *format_return = 32;
5753 /* note: when called from menu all parameters are NULL, so no clue what the
5754 * Widget which was clicked on was, or what the click event was
5756 void CopyPositionProc(w, event, prms, nprms)
5763 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5764 * have a notion of a position that is selected but not copied.
5765 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5767 if(gameMode == EditPosition) EditPositionDone(TRUE);
5768 if (selected_fen_position) free(selected_fen_position);
5769 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5770 if (!selected_fen_position) return;
5771 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5773 SendPositionSelection,
5774 NULL/* lose_ownership_proc */ ,
5775 NULL/* transfer_done_proc */);
5776 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5778 SendPositionSelection,
5779 NULL/* lose_ownership_proc */ ,
5780 NULL/* transfer_done_proc */);
5783 /* function called when the data to Paste is ready */
5785 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5786 Atom *type, XtPointer value, unsigned long *len, int *format)
5789 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5790 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5791 EditPositionPasteFEN(fenstr);
5795 /* called when Paste Position button is pressed,
5796 * all parameters will be NULL */
5797 void PastePositionProc(w, event, prms, nprms)
5803 XtGetSelectionValue(menuBarWidget,
5804 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5805 /* (XtSelectionCallbackProc) */ PastePositionCB,
5806 NULL, /* client_data passed to PastePositionCB */
5808 /* better to use the time field from the event that triggered the
5809 * call to this function, but that isn't trivial to get
5817 SendGameSelection(Widget w, Atom *selection, Atom *target,
5818 Atom *type_return, XtPointer *value_return,
5819 unsigned long *length_return, int *format_return)
5821 char *selection_tmp;
5823 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5824 FILE* f = fopen(gameCopyFilename, "r");
5827 if (f == NULL) return False;
5831 selection_tmp = XtMalloc(len + 1);
5832 count = fread(selection_tmp, 1, len, f);
5834 XtFree(selection_tmp);
5837 selection_tmp[len] = NULLCHAR;
5838 *value_return = selection_tmp;
5839 *length_return = len;
5840 *type_return = *target;
5841 *format_return = 8; /* bits per byte */
5843 } else if (*target == XA_TARGETS(xDisplay)) {
5844 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5845 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5846 targets_tmp[1] = XA_STRING;
5847 *value_return = targets_tmp;
5848 *type_return = XA_ATOM;
5850 *format_return = 8 * sizeof(Atom);
5851 if (*format_return > 32) {
5852 *length_return *= *format_return / 32;
5853 *format_return = 32;
5861 /* note: when called from menu all parameters are NULL, so no clue what the
5862 * Widget which was clicked on was, or what the click event was
5864 void CopyGameProc(w, event, prms, nprms)
5872 ret = SaveGameToFile(gameCopyFilename, FALSE);
5876 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5877 * have a notion of a game that is selected but not copied.
5878 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5880 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5883 NULL/* lose_ownership_proc */ ,
5884 NULL/* transfer_done_proc */);
5885 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5888 NULL/* lose_ownership_proc */ ,
5889 NULL/* transfer_done_proc */);
5892 /* function called when the data to Paste is ready */
5894 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5895 Atom *type, XtPointer value, unsigned long *len, int *format)
5898 if (value == NULL || *len == 0) {
5899 return; /* nothing had been selected to copy */
5901 f = fopen(gamePasteFilename, "w");
5903 DisplayError(_("Can't open temp file"), errno);
5906 fwrite(value, 1, *len, f);
5909 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5912 /* called when Paste Game button is pressed,
5913 * all parameters will be NULL */
5914 void PasteGameProc(w, event, prms, nprms)
5920 XtGetSelectionValue(menuBarWidget,
5921 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5922 /* (XtSelectionCallbackProc) */ PasteGameCB,
5923 NULL, /* client_data passed to PasteGameCB */
5925 /* better to use the time field from the event that triggered the
5926 * call to this function, but that isn't trivial to get
5936 SaveGameProc(NULL, NULL, NULL, NULL);
5940 void QuitProc(w, event, prms, nprms)
5949 void PauseProc(w, event, prms, nprms)
5959 void MachineBlackProc(w, event, prms, nprms)
5965 MachineBlackEvent();
5968 void MachineWhiteProc(w, event, prms, nprms)
5974 MachineWhiteEvent();
5977 void AnalyzeModeProc(w, event, prms, nprms)
5985 if (!first.analysisSupport) {
5986 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5987 DisplayError(buf, 0);
5990 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5991 if (appData.icsActive) {
5992 if (gameMode != IcsObserving) {
5993 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5994 DisplayError(buf, 0);
5996 if (appData.icsEngineAnalyze) {
5997 if (appData.debugMode)
5998 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6004 /* if enable, use want disable icsEngineAnalyze */
6005 if (appData.icsEngineAnalyze) {
6010 appData.icsEngineAnalyze = TRUE;
6011 if (appData.debugMode)
6012 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6014 if (!appData.showThinking)
6015 ShowThinkingProc(w,event,prms,nprms);
6020 void AnalyzeFileProc(w, event, prms, nprms)
6026 if (!first.analysisSupport) {
6028 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6029 DisplayError(buf, 0);
6034 if (!appData.showThinking)
6035 ShowThinkingProc(w,event,prms,nprms);
6038 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6039 AnalysisPeriodicEvent(1);
6042 void TwoMachinesProc(w, event, prms, nprms)
6051 void IcsClientProc(w, event, prms, nprms)
6060 void EditGameProc(w, event, prms, nprms)
6069 void EditPositionProc(w, event, prms, nprms)
6075 EditPositionEvent();
6078 void TrainingProc(w, event, prms, nprms)
6087 void EditCommentProc(w, event, prms, nprms)
6094 EditCommentPopDown();
6100 void IcsInputBoxProc(w, event, prms, nprms)
6106 if (ICSInputBoxUp) {
6107 ICSInputBoxPopDown();
6113 void AcceptProc(w, event, prms, nprms)
6122 void DeclineProc(w, event, prms, nprms)
6131 void RematchProc(w, event, prms, nprms)
6140 void CallFlagProc(w, event, prms, nprms)
6149 void DrawProc(w, event, prms, nprms)
6158 void AbortProc(w, event, prms, nprms)
6167 void AdjournProc(w, event, prms, nprms)
6176 void ResignProc(w, event, prms, nprms)
6185 void AdjuWhiteProc(w, event, prms, nprms)
6191 UserAdjudicationEvent(+1);
6194 void AdjuBlackProc(w, event, prms, nprms)
6200 UserAdjudicationEvent(-1);
6203 void AdjuDrawProc(w, event, prms, nprms)
6209 UserAdjudicationEvent(0);
6212 void EnterKeyProc(w, event, prms, nprms)
6218 if (ICSInputBoxUp == True)
6222 void UpKeyProc(w, event, prms, nprms)
6227 { // [HGM] input: let up-arrow recall previous line from history
6234 if (!ICSInputBoxUp) return;
6235 edit = XtNameToWidget(ICSInputShell, "*form.text");
6237 XtSetArg(args[j], XtNstring, &val); j++;
6238 XtGetValues(edit, args, j);
6239 val = PrevInHistory(val);
6240 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6241 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6243 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6244 XawTextReplace(edit, 0, 0, &t);
6245 XawTextSetInsertionPoint(edit, 9999);
6249 void DownKeyProc(w, event, prms, nprms)
6254 { // [HGM] input: let down-arrow recall next line from history
6259 if (!ICSInputBoxUp) return;
6260 edit = XtNameToWidget(ICSInputShell, "*form.text");
6261 val = NextInHistory();
6262 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6263 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6265 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6266 XawTextReplace(edit, 0, 0, &t);
6267 XawTextSetInsertionPoint(edit, 9999);
6271 void StopObservingProc(w, event, prms, nprms)
6277 StopObservingEvent();
6280 void StopExaminingProc(w, event, prms, nprms)
6286 StopExaminingEvent();
6289 void UploadProc(w, event, prms, nprms)
6299 void ForwardProc(w, event, prms, nprms)
6309 void BackwardProc(w, event, prms, nprms)
6318 void ToStartProc(w, event, prms, nprms)
6327 void ToEndProc(w, event, prms, nprms)
6336 void RevertProc(w, event, prms, nprms)
6345 void AnnotateProc(w, event, prms, nprms)
6354 void TruncateGameProc(w, event, prms, nprms)
6360 TruncateGameEvent();
6362 void RetractMoveProc(w, event, prms, nprms)
6371 void MoveNowProc(w, event, prms, nprms)
6381 void AlwaysQueenProc(w, event, prms, nprms)
6389 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6391 if (appData.alwaysPromoteToQueen) {
6392 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6394 XtSetArg(args[0], XtNleftBitmap, None);
6396 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6400 void AnimateDraggingProc(w, event, prms, nprms)
6408 appData.animateDragging = !appData.animateDragging;
6410 if (appData.animateDragging) {
6411 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6414 XtSetArg(args[0], XtNleftBitmap, None);
6416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6420 void AnimateMovingProc(w, event, prms, nprms)
6428 appData.animate = !appData.animate;
6430 if (appData.animate) {
6431 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6434 XtSetArg(args[0], XtNleftBitmap, None);
6436 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6440 void AutocommProc(w, event, prms, nprms)
6448 appData.autoComment = !appData.autoComment;
6450 if (appData.autoComment) {
6451 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6453 XtSetArg(args[0], XtNleftBitmap, None);
6455 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6460 void AutoflagProc(w, event, prms, nprms)
6468 appData.autoCallFlag = !appData.autoCallFlag;
6470 if (appData.autoCallFlag) {
6471 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6473 XtSetArg(args[0], XtNleftBitmap, None);
6475 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6479 void AutoflipProc(w, event, prms, nprms)
6487 appData.autoFlipView = !appData.autoFlipView;
6489 if (appData.autoFlipView) {
6490 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6492 XtSetArg(args[0], XtNleftBitmap, None);
6494 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6498 void AutobsProc(w, event, prms, nprms)
6506 appData.autoObserve = !appData.autoObserve;
6508 if (appData.autoObserve) {
6509 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6511 XtSetArg(args[0], XtNleftBitmap, None);
6513 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6517 void AutoraiseProc(w, event, prms, nprms)
6525 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6527 if (appData.autoRaiseBoard) {
6528 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6530 XtSetArg(args[0], XtNleftBitmap, None);
6532 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6536 void AutosaveProc(w, event, prms, nprms)
6544 appData.autoSaveGames = !appData.autoSaveGames;
6546 if (appData.autoSaveGames) {
6547 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6549 XtSetArg(args[0], XtNleftBitmap, None);
6551 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6555 void BlindfoldProc(w, event, prms, nprms)
6563 appData.blindfold = !appData.blindfold;
6565 if (appData.blindfold) {
6566 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6568 XtSetArg(args[0], XtNleftBitmap, None);
6570 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6573 DrawPosition(True, NULL);
6576 void TestLegalityProc(w, event, prms, nprms)
6584 appData.testLegality = !appData.testLegality;
6586 if (appData.testLegality) {
6587 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6589 XtSetArg(args[0], XtNleftBitmap, None);
6591 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6596 void FlashMovesProc(w, event, prms, nprms)
6604 if (appData.flashCount == 0) {
6605 appData.flashCount = 3;
6607 appData.flashCount = -appData.flashCount;
6610 if (appData.flashCount > 0) {
6611 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6613 XtSetArg(args[0], XtNleftBitmap, None);
6615 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6619 void FlipViewProc(w, event, prms, nprms)
6625 flipView = !flipView;
6626 DrawPosition(True, NULL);
6629 void GetMoveListProc(w, event, prms, nprms)
6637 appData.getMoveList = !appData.getMoveList;
6639 if (appData.getMoveList) {
6640 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6643 XtSetArg(args[0], XtNleftBitmap, None);
6645 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6650 void HighlightDraggingProc(w, event, prms, nprms)
6658 appData.highlightDragging = !appData.highlightDragging;
6660 if (appData.highlightDragging) {
6661 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6663 XtSetArg(args[0], XtNleftBitmap, None);
6665 XtSetValues(XtNameToWidget(menuBarWidget,
6666 "menuOptions.Highlight Dragging"), args, 1);
6670 void HighlightLastMoveProc(w, event, prms, nprms)
6678 appData.highlightLastMove = !appData.highlightLastMove;
6680 if (appData.highlightLastMove) {
6681 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6683 XtSetArg(args[0], XtNleftBitmap, None);
6685 XtSetValues(XtNameToWidget(menuBarWidget,
6686 "menuOptions.Highlight Last Move"), args, 1);
6689 void IcsAlarmProc(w, event, prms, nprms)
6697 appData.icsAlarm = !appData.icsAlarm;
6699 if (appData.icsAlarm) {
6700 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6702 XtSetArg(args[0], XtNleftBitmap, None);
6704 XtSetValues(XtNameToWidget(menuBarWidget,
6705 "menuOptions.ICS Alarm"), args, 1);
6708 void MoveSoundProc(w, event, prms, nprms)
6716 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6718 if (appData.ringBellAfterMoves) {
6719 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6721 XtSetArg(args[0], XtNleftBitmap, None);
6723 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6728 void OldSaveStyleProc(w, event, prms, nprms)
6736 appData.oldSaveStyle = !appData.oldSaveStyle;
6738 if (appData.oldSaveStyle) {
6739 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6741 XtSetArg(args[0], XtNleftBitmap, None);
6743 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6747 void PeriodicUpdatesProc(w, event, prms, nprms)
6755 PeriodicUpdatesEvent(!appData.periodicUpdates);
6757 if (appData.periodicUpdates) {
6758 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6760 XtSetArg(args[0], XtNleftBitmap, None);
6762 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6766 void PonderNextMoveProc(w, event, prms, nprms)
6774 PonderNextMoveEvent(!appData.ponderNextMove);
6776 if (appData.ponderNextMove) {
6777 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6779 XtSetArg(args[0], XtNleftBitmap, None);
6781 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6785 void PopupExitMessageProc(w, event, prms, nprms)
6793 appData.popupExitMessage = !appData.popupExitMessage;
6795 if (appData.popupExitMessage) {
6796 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6798 XtSetArg(args[0], XtNleftBitmap, None);
6800 XtSetValues(XtNameToWidget(menuBarWidget,
6801 "menuOptions.Popup Exit Message"), args, 1);
6804 void PopupMoveErrorsProc(w, event, prms, nprms)
6812 appData.popupMoveErrors = !appData.popupMoveErrors;
6814 if (appData.popupMoveErrors) {
6815 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6817 XtSetArg(args[0], XtNleftBitmap, None);
6819 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6823 void PremoveProc(w, event, prms, nprms)
6831 appData.premove = !appData.premove;
6833 if (appData.premove) {
6834 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6836 XtSetArg(args[0], XtNleftBitmap, None);
6838 XtSetValues(XtNameToWidget(menuBarWidget,
6839 "menuOptions.Premove"), args, 1);
6842 void QuietPlayProc(w, event, prms, nprms)
6850 appData.quietPlay = !appData.quietPlay;
6852 if (appData.quietPlay) {
6853 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6855 XtSetArg(args[0], XtNleftBitmap, None);
6857 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6861 void ShowCoordsProc(w, event, prms, nprms)
6869 appData.showCoords = !appData.showCoords;
6871 if (appData.showCoords) {
6872 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6874 XtSetArg(args[0], XtNleftBitmap, None);
6876 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6879 DrawPosition(True, NULL);
6882 void ShowThinkingProc(w, event, prms, nprms)
6888 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6889 ShowThinkingEvent();
6892 void HideThinkingProc(w, event, prms, nprms)
6900 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6901 ShowThinkingEvent();
6903 if (appData.hideThinkingFromHuman) {
6904 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6906 XtSetArg(args[0], XtNleftBitmap, None);
6908 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6912 void SaveOnExitProc(w, event, prms, nprms)
6920 saveSettingsOnExit = !saveSettingsOnExit;
6922 if (saveSettingsOnExit) {
6923 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6925 XtSetArg(args[0], XtNleftBitmap, None);
6927 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6931 void SaveSettingsProc(w, event, prms, nprms)
6937 SaveSettings(settingsFileName);
6940 void InfoProc(w, event, prms, nprms)
6947 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6952 void ManProc(w, event, prms, nprms)
6960 if (nprms && *nprms > 0)
6964 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6968 void HintProc(w, event, prms, nprms)
6977 void BookProc(w, event, prms, nprms)
6986 void AboutProc(w, event, prms, nprms)
6994 char *zippy = " (with Zippy code)";
6998 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6999 programVersion, zippy,
7000 "Copyright 1991 Digital Equipment Corporation",
7001 "Enhancements Copyright 1992-2009 Free Software Foundation",
7002 "Enhancements Copyright 2005 Alessandro Scotti",
7003 PACKAGE, " is free software and carries NO WARRANTY;",
7004 "see the file COPYING for more information.");
7005 ErrorPopUp(_("About XBoard"), buf, FALSE);
7008 void DebugProc(w, event, prms, nprms)
7014 appData.debugMode = !appData.debugMode;
7017 void AboutGameProc(w, event, prms, nprms)
7026 void NothingProc(w, event, prms, nprms)
7035 void Iconify(w, event, prms, nprms)
7044 XtSetArg(args[0], XtNiconic, True);
7045 XtSetValues(shellWidget, args, 1);
7048 void DisplayMessage(message, extMessage)
7049 char *message, *extMessage;
7051 /* display a message in the message widget */
7060 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7065 message = extMessage;
7069 /* need to test if messageWidget already exists, since this function
7070 can also be called during the startup, if for example a Xresource
7071 is not set up correctly */
7074 XtSetArg(arg, XtNlabel, message);
7075 XtSetValues(messageWidget, &arg, 1);
7081 void DisplayTitle(text)
7086 char title[MSG_SIZ];
7089 if (text == NULL) text = "";
7091 if (appData.titleInWindow) {
7093 XtSetArg(args[i], XtNlabel, text); i++;
7094 XtSetValues(titleWidget, args, i);
7097 if (*text != NULLCHAR) {
7098 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7099 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7100 } else if (appData.icsActive) {
7101 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7102 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7103 } else if (appData.cmailGameName[0] != NULLCHAR) {
7104 snprintf(icon, sizeof(icon), "%s", "CMail");
7105 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7107 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7108 } else if (gameInfo.variant == VariantGothic) {
7109 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7110 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7113 } else if (gameInfo.variant == VariantFalcon) {
7114 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7115 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7117 } else if (appData.noChessProgram) {
7118 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7119 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7121 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7122 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7125 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7126 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7127 XtSetValues(shellWidget, args, i);
7132 DisplayError(message, error)
7139 if (appData.debugMode || appData.matchMode) {
7140 fprintf(stderr, "%s: %s\n", programName, message);
7143 if (appData.debugMode || appData.matchMode) {
7144 fprintf(stderr, "%s: %s: %s\n",
7145 programName, message, strerror(error));
7147 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7150 ErrorPopUp(_("Error"), message, FALSE);
7154 void DisplayMoveError(message)
7159 DrawPosition(FALSE, NULL);
7160 if (appData.debugMode || appData.matchMode) {
7161 fprintf(stderr, "%s: %s\n", programName, message);
7163 if (appData.popupMoveErrors) {
7164 ErrorPopUp(_("Error"), message, FALSE);
7166 DisplayMessage(message, "");
7171 void DisplayFatalError(message, error, status)
7177 errorExitStatus = status;
7179 fprintf(stderr, "%s: %s\n", programName, message);
7181 fprintf(stderr, "%s: %s: %s\n",
7182 programName, message, strerror(error));
7183 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7186 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7187 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7193 void DisplayInformation(message)
7197 ErrorPopUp(_("Information"), message, TRUE);
7200 void DisplayNote(message)
7204 ErrorPopUp(_("Note"), message, FALSE);
7208 NullXErrorCheck(dpy, error_event)
7210 XErrorEvent *error_event;
7215 void DisplayIcsInteractionTitle(message)
7218 if (oldICSInteractionTitle == NULL) {
7219 /* Magic to find the old window title, adapted from vim */
7220 char *wina = getenv("WINDOWID");
7222 Window win = (Window) atoi(wina);
7223 Window root, parent, *children;
7224 unsigned int nchildren;
7225 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7227 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7228 if (!XQueryTree(xDisplay, win, &root, &parent,
7229 &children, &nchildren)) break;
7230 if (children) XFree((void *)children);
7231 if (parent == root || parent == 0) break;
7234 XSetErrorHandler(oldHandler);
7236 if (oldICSInteractionTitle == NULL) {
7237 oldICSInteractionTitle = "xterm";
7240 printf("\033]0;%s\007", message);
7244 char pendingReplyPrefix[MSG_SIZ];
7245 ProcRef pendingReplyPR;
7247 void AskQuestionProc(w, event, prms, nprms)
7254 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7258 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7261 void AskQuestionPopDown()
7263 if (!askQuestionUp) return;
7264 XtPopdown(askQuestionShell);
7265 XtDestroyWidget(askQuestionShell);
7266 askQuestionUp = False;
7269 void AskQuestionReplyAction(w, event, prms, nprms)
7279 reply = XawDialogGetValueString(w = XtParent(w));
7280 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7281 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7282 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7283 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7284 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7285 AskQuestionPopDown();
7287 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7290 void AskQuestionCallback(w, client_data, call_data)
7292 XtPointer client_data, call_data;
7297 XtSetArg(args[0], XtNlabel, &name);
7298 XtGetValues(w, args, 1);
7300 if (strcmp(name, _("cancel")) == 0) {
7301 AskQuestionPopDown();
7303 AskQuestionReplyAction(w, NULL, NULL, NULL);
7307 void AskQuestion(title, question, replyPrefix, pr)
7308 char *title, *question, *replyPrefix;
7312 Widget popup, layout, dialog, edit;
7318 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7319 pendingReplyPR = pr;
7322 XtSetArg(args[i], XtNresizable, True); i++;
7323 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7324 askQuestionShell = popup =
7325 XtCreatePopupShell(title, transientShellWidgetClass,
7326 shellWidget, args, i);
7329 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7330 layoutArgs, XtNumber(layoutArgs));
7333 XtSetArg(args[i], XtNlabel, question); i++;
7334 XtSetArg(args[i], XtNvalue, ""); i++;
7335 XtSetArg(args[i], XtNborderWidth, 0); i++;
7336 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7339 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7340 (XtPointer) dialog);
7341 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7342 (XtPointer) dialog);
7344 XtRealizeWidget(popup);
7345 CatchDeleteWindow(popup, "AskQuestionPopDown");
7347 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7348 &x, &y, &win_x, &win_y, &mask);
7350 XtSetArg(args[0], XtNx, x - 10);
7351 XtSetArg(args[1], XtNy, y - 30);
7352 XtSetValues(popup, args, 2);
7354 XtPopup(popup, XtGrabExclusive);
7355 askQuestionUp = True;
7357 edit = XtNameToWidget(dialog, "*value");
7358 XtSetKeyboardFocus(popup, edit);
7366 if (*name == NULLCHAR) {
7368 } else if (strcmp(name, "$") == 0) {
7369 putc(BELLCHAR, stderr);
7372 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7380 PlaySound(appData.soundMove);
7386 PlaySound(appData.soundIcsWin);
7392 PlaySound(appData.soundIcsLoss);
7398 PlaySound(appData.soundIcsDraw);
7402 PlayIcsUnfinishedSound()
7404 PlaySound(appData.soundIcsUnfinished);
7410 PlaySound(appData.soundIcsAlarm);
7416 system("stty echo");
7422 system("stty -echo");
7426 Colorize(cc, continuation)
7431 int count, outCount, error;
7433 if (textColors[(int)cc].bg > 0) {
7434 if (textColors[(int)cc].fg > 0) {
7435 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7436 textColors[(int)cc].fg, textColors[(int)cc].bg);
7438 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7439 textColors[(int)cc].bg);
7442 if (textColors[(int)cc].fg > 0) {
7443 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7444 textColors[(int)cc].fg);
7446 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7449 count = strlen(buf);
7450 outCount = OutputToProcess(NoProc, buf, count, &error);
7451 if (outCount < count) {
7452 DisplayFatalError(_("Error writing to display"), error, 1);
7455 if (continuation) return;
7458 PlaySound(appData.soundShout);
7461 PlaySound(appData.soundSShout);
7464 PlaySound(appData.soundChannel1);
7467 PlaySound(appData.soundChannel);
7470 PlaySound(appData.soundKibitz);
7473 PlaySound(appData.soundTell);
7475 case ColorChallenge:
7476 PlaySound(appData.soundChallenge);
7479 PlaySound(appData.soundRequest);
7482 PlaySound(appData.soundSeek);
7493 return getpwuid(getuid())->pw_name;
7497 ExpandPathName(path)
7500 static char static_buf[4*MSG_SIZ];
7501 char *d, *s, buf[4*MSG_SIZ];
7507 while (*s && isspace(*s))
7516 if (*(s+1) == '/') {
7517 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7521 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7522 *strchr(buf, '/') = 0;
7523 pwd = getpwnam(buf);
7526 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7530 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7531 strcat(d, strchr(s+1, '/'));
7535 safeStrCpy(d, s, 4*MSG_SIZ );
7542 static char host_name[MSG_SIZ];
7544 #if HAVE_GETHOSTNAME
7545 gethostname(host_name, MSG_SIZ);
7547 #else /* not HAVE_GETHOSTNAME */
7548 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7549 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7551 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7553 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7554 #endif /* not HAVE_GETHOSTNAME */
7557 XtIntervalId delayedEventTimerXID = 0;
7558 DelayedEventCallback delayedEventCallback = 0;
7563 delayedEventTimerXID = 0;
7564 delayedEventCallback();
7568 ScheduleDelayedEvent(cb, millisec)
7569 DelayedEventCallback cb; long millisec;
7571 if(delayedEventTimerXID && delayedEventCallback == cb)
7572 // [HGM] alive: replace, rather than add or flush identical event
7573 XtRemoveTimeOut(delayedEventTimerXID);
7574 delayedEventCallback = cb;
7575 delayedEventTimerXID =
7576 XtAppAddTimeOut(appContext, millisec,
7577 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7580 DelayedEventCallback
7583 if (delayedEventTimerXID) {
7584 return delayedEventCallback;
7591 CancelDelayedEvent()
7593 if (delayedEventTimerXID) {
7594 XtRemoveTimeOut(delayedEventTimerXID);
7595 delayedEventTimerXID = 0;
7599 XtIntervalId loadGameTimerXID = 0;
7601 int LoadGameTimerRunning()
7603 return loadGameTimerXID != 0;
7606 int StopLoadGameTimer()
7608 if (loadGameTimerXID != 0) {
7609 XtRemoveTimeOut(loadGameTimerXID);
7610 loadGameTimerXID = 0;
7618 LoadGameTimerCallback(arg, id)
7622 loadGameTimerXID = 0;
7627 StartLoadGameTimer(millisec)
7631 XtAppAddTimeOut(appContext, millisec,
7632 (XtTimerCallbackProc) LoadGameTimerCallback,
7636 XtIntervalId analysisClockXID = 0;
7639 AnalysisClockCallback(arg, id)
7643 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7644 || appData.icsEngineAnalyze) { // [DM]
7645 AnalysisPeriodicEvent(0);
7646 StartAnalysisClock();
7651 StartAnalysisClock()
7654 XtAppAddTimeOut(appContext, 2000,
7655 (XtTimerCallbackProc) AnalysisClockCallback,
7659 XtIntervalId clockTimerXID = 0;
7661 int ClockTimerRunning()
7663 return clockTimerXID != 0;
7666 int StopClockTimer()
7668 if (clockTimerXID != 0) {
7669 XtRemoveTimeOut(clockTimerXID);
7678 ClockTimerCallback(arg, id)
7687 StartClockTimer(millisec)
7691 XtAppAddTimeOut(appContext, millisec,
7692 (XtTimerCallbackProc) ClockTimerCallback,
7697 DisplayTimerLabel(w, color, timer, highlight)
7706 /* check for low time warning */
7707 Pixel foregroundOrWarningColor = timerForegroundPixel;
7710 appData.lowTimeWarning &&
7711 (timer / 1000) < appData.icsAlarmTime)
7712 foregroundOrWarningColor = lowTimeWarningColor;
7714 if (appData.clockMode) {
7715 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7716 XtSetArg(args[0], XtNlabel, buf);
7718 snprintf(buf, MSG_SIZ, "%s ", color);
7719 XtSetArg(args[0], XtNlabel, buf);
7724 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7725 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7727 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7728 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7731 XtSetValues(w, args, 3);
7735 DisplayWhiteClock(timeRemaining, highlight)
7741 if(appData.noGUI) return;
7742 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7743 if (highlight && iconPixmap == bIconPixmap) {
7744 iconPixmap = wIconPixmap;
7745 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7746 XtSetValues(shellWidget, args, 1);
7751 DisplayBlackClock(timeRemaining, highlight)
7757 if(appData.noGUI) return;
7758 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7759 if (highlight && iconPixmap == wIconPixmap) {
7760 iconPixmap = bIconPixmap;
7761 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7762 XtSetValues(shellWidget, args, 1);
7780 int StartChildProcess(cmdLine, dir, pr)
7787 int to_prog[2], from_prog[2];
7791 if (appData.debugMode) {
7792 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7795 /* We do NOT feed the cmdLine to the shell; we just
7796 parse it into blank-separated arguments in the
7797 most simple-minded way possible.
7800 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7803 while(*p == ' ') p++;
7805 if(*p == '"' || *p == '\'')
7806 p = strchr(++argv[i-1], *p);
7807 else p = strchr(p, ' ');
7808 if (p == NULL) break;
7813 SetUpChildIO(to_prog, from_prog);
7815 if ((pid = fork()) == 0) {
7817 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7818 close(to_prog[1]); // first close the unused pipe ends
7819 close(from_prog[0]);
7820 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7821 dup2(from_prog[1], 1);
7822 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7823 close(from_prog[1]); // and closing again loses one of the pipes!
7824 if(fileno(stderr) >= 2) // better safe than sorry...
7825 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7827 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7832 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7834 execvp(argv[0], argv);
7836 /* If we get here, exec failed */
7841 /* Parent process */
7843 close(from_prog[1]);
7845 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7848 cp->fdFrom = from_prog[0];
7849 cp->fdTo = to_prog[1];
7854 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7855 static RETSIGTYPE AlarmCallBack(int n)
7861 DestroyChildProcess(pr, signalType)
7865 ChildProc *cp = (ChildProc *) pr;
7867 if (cp->kind != CPReal) return;
7869 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7870 signal(SIGALRM, AlarmCallBack);
7872 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7873 kill(cp->pid, SIGKILL); // kill it forcefully
7874 wait((int *) 0); // and wait again
7878 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7880 /* Process is exiting either because of the kill or because of
7881 a quit command sent by the backend; either way, wait for it to die.
7890 InterruptChildProcess(pr)
7893 ChildProc *cp = (ChildProc *) pr;
7895 if (cp->kind != CPReal) return;
7896 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7899 int OpenTelnet(host, port, pr)
7904 char cmdLine[MSG_SIZ];
7906 if (port[0] == NULLCHAR) {
7907 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7909 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7911 return StartChildProcess(cmdLine, "", pr);
7914 int OpenTCP(host, port, pr)
7920 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7921 #else /* !OMIT_SOCKETS */
7923 struct sockaddr_in sa;
7925 unsigned short uport;
7928 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7932 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7933 sa.sin_family = AF_INET;
7934 sa.sin_addr.s_addr = INADDR_ANY;
7935 uport = (unsigned short) 0;
7936 sa.sin_port = htons(uport);
7937 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7941 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7942 if (!(hp = gethostbyname(host))) {
7944 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7945 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7946 hp->h_addrtype = AF_INET;
7948 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7949 hp->h_addr_list[0] = (char *) malloc(4);
7950 hp->h_addr_list[0][0] = b0;
7951 hp->h_addr_list[0][1] = b1;
7952 hp->h_addr_list[0][2] = b2;
7953 hp->h_addr_list[0][3] = b3;
7958 sa.sin_family = hp->h_addrtype;
7959 uport = (unsigned short) atoi(port);
7960 sa.sin_port = htons(uport);
7961 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7963 if (connect(s, (struct sockaddr *) &sa,
7964 sizeof(struct sockaddr_in)) < 0) {
7968 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7975 #endif /* !OMIT_SOCKETS */
7980 int OpenCommPort(name, pr)
7987 fd = open(name, 2, 0);
7988 if (fd < 0) return errno;
7990 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8000 int OpenLoopback(pr)
8006 SetUpChildIO(to, from);
8008 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8011 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8018 int OpenRcmd(host, user, cmd, pr)
8019 char *host, *user, *cmd;
8022 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8026 #define INPUT_SOURCE_BUF_SIZE 8192
8035 char buf[INPUT_SOURCE_BUF_SIZE];
8040 DoInputCallback(closure, source, xid)
8045 InputSource *is = (InputSource *) closure;
8050 if (is->lineByLine) {
8051 count = read(is->fd, is->unused,
8052 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8054 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8057 is->unused += count;
8059 while (p < is->unused) {
8060 q = memchr(p, '\n', is->unused - p);
8061 if (q == NULL) break;
8063 (is->func)(is, is->closure, p, q - p, 0);
8067 while (p < is->unused) {
8072 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8077 (is->func)(is, is->closure, is->buf, count, error);
8081 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8088 ChildProc *cp = (ChildProc *) pr;
8090 is = (InputSource *) calloc(1, sizeof(InputSource));
8091 is->lineByLine = lineByLine;
8095 is->fd = fileno(stdin);
8097 is->kind = cp->kind;
8098 is->fd = cp->fdFrom;
8101 is->unused = is->buf;
8104 is->xid = XtAppAddInput(appContext, is->fd,
8105 (XtPointer) (XtInputReadMask),
8106 (XtInputCallbackProc) DoInputCallback,
8108 is->closure = closure;
8109 return (InputSourceRef) is;
8113 RemoveInputSource(isr)
8116 InputSource *is = (InputSource *) isr;
8118 if (is->xid == 0) return;
8119 XtRemoveInput(is->xid);
8123 int OutputToProcess(pr, message, count, outError)
8129 static int line = 0;
8130 ChildProc *cp = (ChildProc *) pr;
8135 if (appData.noJoin || !appData.useInternalWrap)
8136 outCount = fwrite(message, 1, count, stdout);
8139 int width = get_term_width();
8140 int len = wrap(NULL, message, count, width, &line);
8141 char *msg = malloc(len);
8145 outCount = fwrite(message, 1, count, stdout);
8148 dbgchk = wrap(msg, message, count, width, &line);
8149 if (dbgchk != len && appData.debugMode)
8150 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8151 outCount = fwrite(msg, 1, dbgchk, stdout);
8157 outCount = write(cp->fdTo, message, count);
8167 /* Output message to process, with "ms" milliseconds of delay
8168 between each character. This is needed when sending the logon
8169 script to ICC, which for some reason doesn't like the
8170 instantaneous send. */
8171 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8178 ChildProc *cp = (ChildProc *) pr;
8183 r = write(cp->fdTo, message++, 1);
8196 /**** Animation code by Hugh Fisher, DCS, ANU.
8198 Known problem: if a window overlapping the board is
8199 moved away while a piece is being animated underneath,
8200 the newly exposed area won't be updated properly.
8201 I can live with this.
8203 Known problem: if you look carefully at the animation
8204 of pieces in mono mode, they are being drawn as solid
8205 shapes without interior detail while moving. Fixing
8206 this would be a major complication for minimal return.
8209 /* Masks for XPM pieces. Black and white pieces can have
8210 different shapes, but in the interest of retaining my
8211 sanity pieces must have the same outline on both light
8212 and dark squares, and all pieces must use the same
8213 background square colors/images. */
8215 static int xpmDone = 0;
8218 CreateAnimMasks (pieceDepth)
8225 unsigned long plane;
8228 /* Need a bitmap just to get a GC with right depth */
8229 buf = XCreatePixmap(xDisplay, xBoardWindow,
8231 values.foreground = 1;
8232 values.background = 0;
8233 /* Don't use XtGetGC, not read only */
8234 maskGC = XCreateGC(xDisplay, buf,
8235 GCForeground | GCBackground, &values);
8236 XFreePixmap(xDisplay, buf);
8238 buf = XCreatePixmap(xDisplay, xBoardWindow,
8239 squareSize, squareSize, pieceDepth);
8240 values.foreground = XBlackPixel(xDisplay, xScreen);
8241 values.background = XWhitePixel(xDisplay, xScreen);
8242 bufGC = XCreateGC(xDisplay, buf,
8243 GCForeground | GCBackground, &values);
8245 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8246 /* Begin with empty mask */
8247 if(!xpmDone) // [HGM] pieces: keep using existing
8248 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8249 squareSize, squareSize, 1);
8250 XSetFunction(xDisplay, maskGC, GXclear);
8251 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8252 0, 0, squareSize, squareSize);
8254 /* Take a copy of the piece */
8259 XSetFunction(xDisplay, bufGC, GXcopy);
8260 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8262 0, 0, squareSize, squareSize, 0, 0);
8264 /* XOR the background (light) over the piece */
8265 XSetFunction(xDisplay, bufGC, GXxor);
8267 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8268 0, 0, squareSize, squareSize, 0, 0);
8270 XSetForeground(xDisplay, bufGC, lightSquareColor);
8271 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8274 /* We now have an inverted piece image with the background
8275 erased. Construct mask by just selecting all the non-zero
8276 pixels - no need to reconstruct the original image. */
8277 XSetFunction(xDisplay, maskGC, GXor);
8279 /* Might be quicker to download an XImage and create bitmap
8280 data from it rather than this N copies per piece, but it
8281 only takes a fraction of a second and there is a much
8282 longer delay for loading the pieces. */
8283 for (n = 0; n < pieceDepth; n ++) {
8284 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8285 0, 0, squareSize, squareSize,
8291 XFreePixmap(xDisplay, buf);
8292 XFreeGC(xDisplay, bufGC);
8293 XFreeGC(xDisplay, maskGC);
8297 InitAnimState (anim, info)
8299 XWindowAttributes * info;
8304 /* Each buffer is square size, same depth as window */
8305 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8306 squareSize, squareSize, info->depth);
8307 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8308 squareSize, squareSize, info->depth);
8310 /* Create a plain GC for blitting */
8311 mask = GCForeground | GCBackground | GCFunction |
8312 GCPlaneMask | GCGraphicsExposures;
8313 values.foreground = XBlackPixel(xDisplay, xScreen);
8314 values.background = XWhitePixel(xDisplay, xScreen);
8315 values.function = GXcopy;
8316 values.plane_mask = AllPlanes;
8317 values.graphics_exposures = False;
8318 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8320 /* Piece will be copied from an existing context at
8321 the start of each new animation/drag. */
8322 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8324 /* Outline will be a read-only copy of an existing */
8325 anim->outlineGC = None;
8331 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8332 XWindowAttributes info;
8334 if (xpmDone && gameInfo.variant == old) return;
8335 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8336 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8338 InitAnimState(&game, &info);
8339 InitAnimState(&player, &info);
8341 /* For XPM pieces, we need bitmaps to use as masks. */
8343 CreateAnimMasks(info.depth);
8349 static Boolean frameWaiting;
8351 static RETSIGTYPE FrameAlarm (sig)
8354 frameWaiting = False;
8355 /* In case System-V style signals. Needed?? */
8356 signal(SIGALRM, FrameAlarm);
8363 struct itimerval delay;
8365 XSync(xDisplay, False);
8368 frameWaiting = True;
8369 signal(SIGALRM, FrameAlarm);
8370 delay.it_interval.tv_sec =
8371 delay.it_value.tv_sec = time / 1000;
8372 delay.it_interval.tv_usec =
8373 delay.it_value.tv_usec = (time % 1000) * 1000;
8374 setitimer(ITIMER_REAL, &delay, NULL);
8375 while (frameWaiting) pause();
8376 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8377 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8378 setitimer(ITIMER_REAL, &delay, NULL);
8388 XSync(xDisplay, False);
8390 usleep(time * 1000);
8395 /* Convert board position to corner of screen rect and color */
8398 ScreenSquare(column, row, pt, color)
8399 int column; int row; XPoint * pt; int * color;
8402 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8403 pt->y = lineGap + row * (squareSize + lineGap);
8405 pt->x = lineGap + column * (squareSize + lineGap);
8406 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8408 *color = SquareColor(row, column);
8411 /* Convert window coords to square */
8414 BoardSquare(x, y, column, row)
8415 int x; int y; int * column; int * row;
8417 *column = EventToSquare(x, BOARD_WIDTH);
8418 if (flipView && *column >= 0)
8419 *column = BOARD_WIDTH - 1 - *column;
8420 *row = EventToSquare(y, BOARD_HEIGHT);
8421 if (!flipView && *row >= 0)
8422 *row = BOARD_HEIGHT - 1 - *row;
8427 #undef Max /* just in case */
8429 #define Max(a, b) ((a) > (b) ? (a) : (b))
8430 #define Min(a, b) ((a) < (b) ? (a) : (b))
8433 SetRect(rect, x, y, width, height)
8434 XRectangle * rect; int x; int y; int width; int height;
8438 rect->width = width;
8439 rect->height = height;
8442 /* Test if two frames overlap. If they do, return
8443 intersection rect within old and location of
8444 that rect within new. */
8447 Intersect(old, new, size, area, pt)
8448 XPoint * old; XPoint * new;
8449 int size; XRectangle * area; XPoint * pt;
8451 if (old->x > new->x + size || new->x > old->x + size ||
8452 old->y > new->y + size || new->y > old->y + size) {
8455 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8456 size - abs(old->x - new->x), size - abs(old->y - new->y));
8457 pt->x = Max(old->x - new->x, 0);
8458 pt->y = Max(old->y - new->y, 0);
8463 /* For two overlapping frames, return the rect(s)
8464 in the old that do not intersect with the new. */
8467 CalcUpdateRects(old, new, size, update, nUpdates)
8468 XPoint * old; XPoint * new; int size;
8469 XRectangle update[]; int * nUpdates;
8473 /* If old = new (shouldn't happen) then nothing to draw */
8474 if (old->x == new->x && old->y == new->y) {
8478 /* Work out what bits overlap. Since we know the rects
8479 are the same size we don't need a full intersect calc. */
8481 /* Top or bottom edge? */
8482 if (new->y > old->y) {
8483 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8485 } else if (old->y > new->y) {
8486 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8487 size, old->y - new->y);
8490 /* Left or right edge - don't overlap any update calculated above. */
8491 if (new->x > old->x) {
8492 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8493 new->x - old->x, size - abs(new->y - old->y));
8495 } else if (old->x > new->x) {
8496 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8497 old->x - new->x, size - abs(new->y - old->y));
8504 /* Generate a series of frame coords from start->mid->finish.
8505 The movement rate doubles until the half way point is
8506 reached, then halves back down to the final destination,
8507 which gives a nice slow in/out effect. The algorithmn
8508 may seem to generate too many intermediates for short
8509 moves, but remember that the purpose is to attract the
8510 viewers attention to the piece about to be moved and
8511 then to where it ends up. Too few frames would be less
8515 Tween(start, mid, finish, factor, frames, nFrames)
8516 XPoint * start; XPoint * mid;
8517 XPoint * finish; int factor;
8518 XPoint frames[]; int * nFrames;
8520 int fraction, n, count;
8524 /* Slow in, stepping 1/16th, then 1/8th, ... */
8526 for (n = 0; n < factor; n++)
8528 for (n = 0; n < factor; n++) {
8529 frames[count].x = start->x + (mid->x - start->x) / fraction;
8530 frames[count].y = start->y + (mid->y - start->y) / fraction;
8532 fraction = fraction / 2;
8536 frames[count] = *mid;
8539 /* Slow out, stepping 1/2, then 1/4, ... */
8541 for (n = 0; n < factor; n++) {
8542 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8543 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8545 fraction = fraction * 2;
8550 /* Draw a piece on the screen without disturbing what's there */
8553 SelectGCMask(piece, clip, outline, mask)
8554 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8558 /* Bitmap for piece being moved. */
8559 if (appData.monoMode) {
8560 *mask = *pieceToSolid(piece);
8561 } else if (useImages) {
8563 *mask = xpmMask[piece];
8565 *mask = ximMaskPm[piece];
8568 *mask = *pieceToSolid(piece);
8571 /* GC for piece being moved. Square color doesn't matter, but
8572 since it gets modified we make a copy of the original. */
8574 if (appData.monoMode)
8579 if (appData.monoMode)
8584 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8586 /* Outline only used in mono mode and is not modified */
8588 *outline = bwPieceGC;
8590 *outline = wbPieceGC;
8594 OverlayPiece(piece, clip, outline, dest)
8595 ChessSquare piece; GC clip; GC outline; Drawable dest;
8600 /* Draw solid rectangle which will be clipped to shape of piece */
8601 XFillRectangle(xDisplay, dest, clip,
8602 0, 0, squareSize, squareSize);
8603 if (appData.monoMode)
8604 /* Also draw outline in contrasting color for black
8605 on black / white on white cases */
8606 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8607 0, 0, squareSize, squareSize, 0, 0, 1);
8609 /* Copy the piece */
8614 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8616 0, 0, squareSize, squareSize,
8621 /* Animate the movement of a single piece */
8624 BeginAnimation(anim, piece, startColor, start)
8632 /* The old buffer is initialised with the start square (empty) */
8633 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8634 anim->prevFrame = *start;
8636 /* The piece will be drawn using its own bitmap as a matte */
8637 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8638 XSetClipMask(xDisplay, anim->pieceGC, mask);
8642 AnimationFrame(anim, frame, piece)
8647 XRectangle updates[4];
8652 /* Save what we are about to draw into the new buffer */
8653 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8654 frame->x, frame->y, squareSize, squareSize,
8657 /* Erase bits of the previous frame */
8658 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8659 /* Where the new frame overlapped the previous,
8660 the contents in newBuf are wrong. */
8661 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8662 overlap.x, overlap.y,
8663 overlap.width, overlap.height,
8665 /* Repaint the areas in the old that don't overlap new */
8666 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8667 for (i = 0; i < count; i++)
8668 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8669 updates[i].x - anim->prevFrame.x,
8670 updates[i].y - anim->prevFrame.y,
8671 updates[i].width, updates[i].height,
8672 updates[i].x, updates[i].y);
8674 /* Easy when no overlap */
8675 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8676 0, 0, squareSize, squareSize,
8677 anim->prevFrame.x, anim->prevFrame.y);
8680 /* Save this frame for next time round */
8681 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8682 0, 0, squareSize, squareSize,
8684 anim->prevFrame = *frame;
8686 /* Draw piece over original screen contents, not current,
8687 and copy entire rect. Wipes out overlapping piece images. */
8688 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8689 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8690 0, 0, squareSize, squareSize,
8691 frame->x, frame->y);
8695 EndAnimation (anim, finish)
8699 XRectangle updates[4];
8704 /* The main code will redraw the final square, so we
8705 only need to erase the bits that don't overlap. */
8706 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8707 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8708 for (i = 0; i < count; i++)
8709 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8710 updates[i].x - anim->prevFrame.x,
8711 updates[i].y - anim->prevFrame.y,
8712 updates[i].width, updates[i].height,
8713 updates[i].x, updates[i].y);
8715 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8716 0, 0, squareSize, squareSize,
8717 anim->prevFrame.x, anim->prevFrame.y);
8722 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8724 ChessSquare piece; int startColor;
8725 XPoint * start; XPoint * finish;
8726 XPoint frames[]; int nFrames;
8730 BeginAnimation(anim, piece, startColor, start);
8731 for (n = 0; n < nFrames; n++) {
8732 AnimationFrame(anim, &(frames[n]), piece);
8733 FrameDelay(appData.animSpeed);
8735 EndAnimation(anim, finish);
8738 /* Main control logic for deciding what to animate and how */
8741 AnimateMove(board, fromX, fromY, toX, toY)
8750 XPoint start, finish, mid;
8751 XPoint frames[kFactor * 2 + 1];
8752 int nFrames, startColor, endColor;
8754 /* Are we animating? */
8755 if (!appData.animate || appData.blindfold)
8758 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8759 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8760 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8762 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8763 piece = board[fromY][fromX];
8764 if (piece >= EmptySquare) return;
8769 hop = (piece == WhiteKnight || piece == BlackKnight);
8772 if (appData.debugMode) {
8773 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8774 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8775 piece, fromX, fromY, toX, toY); }
8777 ScreenSquare(fromX, fromY, &start, &startColor);
8778 ScreenSquare(toX, toY, &finish, &endColor);
8781 /* Knight: make diagonal movement then straight */
8782 if (abs(toY - fromY) < abs(toX - fromX)) {
8783 mid.x = start.x + (finish.x - start.x) / 2;
8787 mid.y = start.y + (finish.y - start.y) / 2;
8790 mid.x = start.x + (finish.x - start.x) / 2;
8791 mid.y = start.y + (finish.y - start.y) / 2;
8794 /* Don't use as many frames for very short moves */
8795 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8796 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8798 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8799 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8801 /* Be sure end square is redrawn */
8802 damage[0][toY][toX] = True;
8806 DragPieceBegin(x, y)
8809 int boardX, boardY, color;
8812 /* Are we animating? */
8813 if (!appData.animateDragging || appData.blindfold)
8816 /* Figure out which square we start in and the
8817 mouse position relative to top left corner. */
8818 BoardSquare(x, y, &boardX, &boardY);
8819 player.startBoardX = boardX;
8820 player.startBoardY = boardY;
8821 ScreenSquare(boardX, boardY, &corner, &color);
8822 player.startSquare = corner;
8823 player.startColor = color;
8824 /* As soon as we start dragging, the piece will jump slightly to
8825 be centered over the mouse pointer. */
8826 player.mouseDelta.x = squareSize/2;
8827 player.mouseDelta.y = squareSize/2;
8828 /* Initialise animation */
8829 player.dragPiece = PieceForSquare(boardX, boardY);
8831 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8832 player.dragActive = True;
8833 BeginAnimation(&player, player.dragPiece, color, &corner);
8834 /* Mark this square as needing to be redrawn. Note that
8835 we don't remove the piece though, since logically (ie
8836 as seen by opponent) the move hasn't been made yet. */
8837 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8838 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8839 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8840 corner.x, corner.y, squareSize, squareSize,
8841 0, 0); // [HGM] zh: unstack in stead of grab
8842 damage[0][boardY][boardX] = True;
8844 player.dragActive = False;
8854 /* Are we animating? */
8855 if (!appData.animateDragging || appData.blindfold)
8859 if (! player.dragActive)
8861 /* Move piece, maintaining same relative position
8862 of mouse within square */
8863 corner.x = x - player.mouseDelta.x;
8864 corner.y = y - player.mouseDelta.y;
8865 AnimationFrame(&player, &corner, player.dragPiece);
8867 if (appData.highlightDragging) {
8869 BoardSquare(x, y, &boardX, &boardY);
8870 SetHighlights(fromX, fromY, boardX, boardY);
8879 int boardX, boardY, color;
8882 /* Are we animating? */
8883 if (!appData.animateDragging || appData.blindfold)
8887 if (! player.dragActive)
8889 /* Last frame in sequence is square piece is
8890 placed on, which may not match mouse exactly. */
8891 BoardSquare(x, y, &boardX, &boardY);
8892 ScreenSquare(boardX, boardY, &corner, &color);
8893 EndAnimation(&player, &corner);
8895 /* Be sure end square is redrawn */
8896 damage[0][boardY][boardX] = True;
8898 /* This prevents weird things happening with fast successive
8899 clicks which on my Sun at least can cause motion events
8900 without corresponding press/release. */
8901 player.dragActive = False;
8904 /* Handle expose event while piece being dragged */
8909 if (!player.dragActive || appData.blindfold)
8912 /* What we're doing: logically, the move hasn't been made yet,
8913 so the piece is still in it's original square. But visually
8914 it's being dragged around the board. So we erase the square
8915 that the piece is on and draw it at the last known drag point. */
8916 BlankSquare(player.startSquare.x, player.startSquare.y,
8917 player.startColor, EmptySquare, xBoardWindow);
8918 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8919 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8922 #include <sys/ioctl.h>
8923 int get_term_width()
8925 int fd, default_width;
8928 default_width = 79; // this is FICS default anyway...
8930 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8932 if (!ioctl(fd, TIOCGSIZE, &win))
8933 default_width = win.ts_cols;
8934 #elif defined(TIOCGWINSZ)
8936 if (!ioctl(fd, TIOCGWINSZ, &win))
8937 default_width = win.ws_col;
8939 return default_width;
8945 static int old_width = 0;
8946 int new_width = get_term_width();
8948 if (old_width != new_width)
8949 ics_printf("set width %d\n", new_width);
8950 old_width = new_width;
8953 void NotifyFrontendLogin()